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="../../../../tests/interactive/test-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>
263 * <title>Explicit animations</title>
264 * <para>The explicit animation model supported by Clutter requires that
265 * you create a #ClutterTransition object, and set the initial and
266 * final values. The transition will not start unless you add it to the
267 * #ClutterActor.</para>
268 * <informalexample><programlisting>
269 * ClutterTransition *transition;
271 * transition = clutter_property_transition_new ("opacity");
272 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
273 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
274 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
275 * clutter_transition_set_interval (transition, clutter_interval_new (G_TYPE_UINT, 255, 0));
277 * clutter_actor_add_transition (actor, "animate-opacity", transition);
278 * </programlisting></informalexample>
279 * <para>The example above will animate the #ClutterActor:opacity property
280 * of an actor between fully opaque and fully transparent, and back, over
281 * a span of 3 seconds. The animation does not begin until it is added to
283 * <para>The explicit animation API should also be used when using custom
284 * animatable properties for #ClutterAction, #ClutterConstraint, and
285 * #ClutterEffect instances associated to an actor; see the section on
286 * <ulink linkend="ClutterActor-custom-animatable-properties">custom
287 * animatable properties below</ulink> for an example.</para>
288 * <para>Finally, explicit animations are useful for creating animations
289 * that run continuously, for instance:</para>
290 * <informalexample><programlisting>
291 * /* this animation will pulse the actor's opacity continuously */
292 * ClutterTransition *transition;
293 * ClutterInterval *interval;
295 * transition = clutter_property_transition_new ("opacity");
297 * /* we want to animate the opacity between 0 and 255 */
298 * internal = clutter_interval_new (G_TYPE_UINT, 0, 255);
299 * clutter_transition_set_interval (transition, interval);
301 * /* over a one second duration, running an infinite amount of times */
302 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
303 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
305 * /* we want to fade in and out, so we need to auto-reverse the transition */
306 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
308 * /* and we want to use an easing function that eases both in and out */
309 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
310 * CLUTTER_EASE_IN_OUT_CUBIC);
312 * /* add the transition to the desired actor; this will
313 * * start the animation.
315 * clutter_actor_add_transition (actor, "opacityAnimation", transition);
316 * </programlisting></informalexample>
320 * <refsect2 id="ClutterActor-subclassing">
321 * <title>Implementing an actor</title>
322 * <para>Careful consideration should be given when deciding to implement
323 * a #ClutterActor sub-class. It is generally recommended to implement a
324 * sub-class of #ClutterActor only for actors that should be used as leaf
325 * nodes of a scene graph.</para>
326 * <para>If your actor should be painted in a custom way, you should
327 * override the #ClutterActor::paint signal class handler. You can either
328 * opt to chain up to the parent class implementation or decide to fully
329 * override the default paint implementation; Clutter will set up the
330 * transformations and clip regions prior to emitting the #ClutterActor::paint
332 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
333 * #ClutterActorClass.get_preferred_height() virtual functions it is
334 * possible to change or provide the preferred size of an actor; similarly,
335 * by overriding the #ClutterActorClass.allocate() virtual function it is
336 * possible to control the layout of the children of an actor. Make sure to
337 * always chain up to the parent implementation of the
338 * #ClutterActorClass.allocate() virtual function.</para>
339 * <para>In general, it is strongly encouraged to use delegation and
340 * composition instead of direct subclassing.</para>
343 * <refsect2 id="ClutterActor-script">
344 * <title>ClutterActor custom properties for #ClutterScript</title>
345 * <para>#ClutterActor defines a custom "rotation" property which
346 * allows a short-hand description of the rotations to be applied
347 * to an actor.</para>
348 * <para>The syntax of the "rotation" property is the following:</para>
352 * { "<axis>" : [ <angle>, [ <center> ] ] }
356 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
357 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
358 * floating point value representing the rotation angle on the given axis,
360 * <para>The <emphasis>center</emphasis> array is optional, and if present
361 * it must contain the center of rotation as described by two coordinates:
362 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
364 * <para>#ClutterActor will also parse every positional and dimensional
365 * property defined as a string through clutter_units_from_string(); you
366 * should read the documentation for the #ClutterUnits parser format for
367 * the valid units and syntax.</para>
370 * <refsect2 id="ClutterActor-custom-animatable-properties">
371 * <title>Custom animatable properties</title>
372 * <para>#ClutterActor allows accessing properties of #ClutterAction,
373 * #ClutterEffect, and #ClutterConstraint instances associated to an actor
374 * instance for animation purposes.</para>
375 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
376 * property it is necessary to set the #ClutterActorMeta:name property on the
377 * given action or constraint.</para>
378 * <para>The property can be accessed using the following syntax:</para>
381 * @<section>.<meta-name>.<property-name>
384 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
385 * <para>The <emphasis>section</emphasis> fragment can be one between
386 * "actions", "constraints" and "effects".</para>
387 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
388 * action or constraint, as specified by the #ClutterActorMeta:name
390 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
391 * action or constraint property to be animated.</para>
392 * <para>The example below animates a #ClutterBindConstraint applied to an
393 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
394 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
395 * its initial state is overlapping the actor to which is bound to.</para>
396 * <informalexample><programlisting>
397 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
398 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
399 * clutter_actor_add_constraint (rect, constraint);
401 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
402 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
403 * clutter_actor_add_constraint (rect, constraint);
405 * clutter_actor_set_reactive (origin, TRUE);
407 * g_signal_connect (origin, "button-press-event",
408 * G_CALLBACK (on_button_press),
410 * </programlisting></informalexample>
411 * <para>On button press, the rectangle "slides" from behind the actor to
412 * which is bound to, using the #ClutterBindConstraint:offset property to
413 * achieve the effect:</para>
414 * <informalexample><programlisting>
416 * on_button_press (ClutterActor *origin,
417 * ClutterEvent *event,
418 * ClutterActor *rect)
420 * ClutterTransition *transition;
421 * ClutterInterval *interval;
423 * /* the offset that we want to apply; this will make the actor
424 * * slide in from behind the origin and rest at the right of
425 * * the origin, plus a padding value.
427 * float new_offset = clutter_actor_get_width (origin) + h_padding;
429 * /* the property we wish to animate; the "@constraints" section
430 * * tells Clutter to check inside the constraints associated
431 * * with the actor; the "bind-x" section is the name of the
432 * * constraint; and the "offset" is the name of the property
433 * * on the constraint.
435 * const char *prop = "@constraints.bind-x.offset";
437 * /* create a new transition for the given property */
438 * transition = clutter_property_transition_new (prop);
440 * /* set the easing mode and duration */
441 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
442 * CLUTTER_EASE_OUT_CUBIC);
443 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
445 * /* create the interval with the initial and final values */
446 * interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
447 * clutter_transition_set_interval (transition, interval);
449 * /* add the transition to the actor; this causes the animation
450 * * to start. the name "offsetAnimation" can be used to retrieve
451 * * the transition later.
453 * clutter_actor_add_transition (rect, "offsetAnimation", transition);
455 * /* we handled the event */
456 * return CLUTTER_EVENT_STOP;
458 * </programlisting></informalexample>
463 * CLUTTER_ACTOR_IS_MAPPED:
464 * @a: a #ClutterActor
466 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
468 * The mapped state is set when the actor is visible and all its parents up
469 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
471 * This check can be used to see if an actor is going to be painted, as only
472 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
474 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
475 * not be checked directly; instead, the recommended usage is to connect a
476 * handler on the #GObject::notify signal for the #ClutterActor:mapped
477 * property of #ClutterActor, and check the presence of
478 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
480 * It is also important to note that Clutter may delay the changes of
481 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
482 * limitations, or during the reparenting of an actor, to optimize
483 * unnecessary (and potentially expensive) state changes.
489 * CLUTTER_ACTOR_IS_REALIZED:
490 * @a: a #ClutterActor
492 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
494 * The realized state has an actor-dependant interpretation. If an
495 * actor wants to delay allocating resources until it is attached to a
496 * stage, it may use the realize state to do so. However it is
497 * perfectly acceptable for an actor to allocate Cogl resources before
498 * being realized because there is only one drawing context used by Clutter
499 * so any resources will work on any stage. If an actor is mapped it
500 * must also be realized, but an actor can be realized and unmapped
501 * (this is so hiding an actor temporarily doesn't do an expensive
502 * unrealize/realize).
504 * To be realized an actor must be inside a stage, and all its parents
511 * CLUTTER_ACTOR_IS_VISIBLE:
512 * @a: a #ClutterActor
514 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
515 * Equivalent to the ClutterActor::visible object property.
517 * Note that an actor is only painted onscreen if it's mapped, which
518 * means it's visible, and all its parents are visible, and one of the
519 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
525 * CLUTTER_ACTOR_IS_REACTIVE:
526 * @a: a #ClutterActor
528 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
530 * Only reactive actors will receive event-related signals.
541 #include <gobject/gvaluecollector.h>
543 #include <cogl/cogl.h>
545 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
546 #define CLUTTER_ENABLE_EXPERIMENTAL_API
548 #include "clutter-actor-private.h"
550 #include "clutter-action.h"
551 #include "clutter-actor-meta-private.h"
552 #include "clutter-animatable.h"
553 #include "clutter-color-static.h"
554 #include "clutter-color.h"
555 #include "clutter-constraint.h"
556 #include "clutter-container.h"
557 #include "clutter-content-private.h"
558 #include "clutter-debug.h"
559 #include "clutter-effect-private.h"
560 #include "clutter-enum-types.h"
561 #include "clutter-fixed-layout.h"
562 #include "clutter-flatten-effect.h"
563 #include "clutter-interval.h"
564 #include "clutter-main.h"
565 #include "clutter-marshal.h"
566 #include "clutter-paint-nodes.h"
567 #include "clutter-paint-node-private.h"
568 #include "clutter-paint-volume-private.h"
569 #include "clutter-private.h"
570 #include "clutter-profile.h"
571 #include "clutter-property-transition.h"
572 #include "clutter-scriptable.h"
573 #include "clutter-script-private.h"
574 #include "clutter-stage-private.h"
575 #include "clutter-timeline.h"
576 #include "clutter-transition.h"
577 #include "clutter-units.h"
579 #include "deprecated/clutter-actor.h"
580 #include "deprecated/clutter-behaviour.h"
581 #include "deprecated/clutter-container.h"
583 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
584 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
586 /* Internal enum used to control mapped state update. This is a hint
587 * which indicates when to do something other than just enforce
591 MAP_STATE_CHECK, /* just enforce invariants. */
592 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
593 * used when about to unparent.
595 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
596 * used to set mapped on toplevels.
598 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
599 * used just before unmapping parent.
603 /* 3 entries should be a good compromise, few layout managers
604 * will ask for 3 different preferred size in each allocation cycle */
605 #define N_CACHED_SIZE_REQUESTS 3
607 struct _ClutterActorPrivate
610 ClutterRequestMode request_mode;
612 /* our cached size requests for different width / height */
613 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
614 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
616 /* An age of 0 means the entry is not set */
617 guint cached_height_age;
618 guint cached_width_age;
620 /* the bounding box of the actor, relative to the parent's
623 ClutterActorBox allocation;
624 ClutterAllocationFlags allocation_flags;
626 /* clip, in actor coordinates */
627 cairo_rectangle_t clip;
629 /* the cached transformation matrix; see apply_transform() */
630 CoglMatrix transform;
633 gint opacity_override;
635 ClutterOffscreenRedirect offscreen_redirect;
637 /* This is an internal effect used to implement the
638 offscreen-redirect property */
639 ClutterEffect *flatten_effect;
642 ClutterActor *parent;
643 ClutterActor *prev_sibling;
644 ClutterActor *next_sibling;
645 ClutterActor *first_child;
646 ClutterActor *last_child;
650 /* tracks whenever the children of an actor are changed; the
651 * age is incremented by 1 whenever an actor is added or
652 * removed. the age is not incremented when the first or the
653 * last child pointers are changed, or when grandchildren of
654 * an actor are changed.
658 gchar *name; /* a non-unique name, used for debugging */
659 guint32 id; /* unique id, used for backward compatibility */
661 gint32 pick_id; /* per-stage unique id, used for picking */
663 /* a back-pointer to the Pango context that we can use
664 * to create pre-configured PangoLayout
666 PangoContext *pango_context;
668 /* the text direction configured for this child - either by
669 * application code, or by the actor's parent
671 ClutterTextDirection text_direction;
673 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
677 ClutterMetaGroup *actions;
678 ClutterMetaGroup *constraints;
679 ClutterMetaGroup *effects;
681 /* delegate object used to allocate the children of this actor */
682 ClutterLayoutManager *layout_manager;
684 /* delegate object used to paint the contents of this actor */
685 ClutterContent *content;
687 ClutterContentGravity content_gravity;
688 ClutterScalingFilter min_filter;
689 ClutterScalingFilter mag_filter;
691 /* used when painting, to update the paint volume */
692 ClutterEffect *current_effect;
694 /* This is used to store an effect which needs to be redrawn. A
695 redraw can be queued to start from a particular effect. This is
696 used by parametrised effects that can cache an image of the
697 actor. If a parameter of the effect changes then it only needs to
698 redraw the cached image, not the actual actor. The pointer is
699 only valid if is_dirty == TRUE. If the pointer is NULL then the
700 whole actor is dirty. */
701 ClutterEffect *effect_to_redraw;
703 /* This is used when painting effects to implement the
704 clutter_actor_continue_paint() function. It points to the node in
705 the list of effects that is next in the chain */
706 const GList *next_effect_to_paint;
708 ClutterPaintVolume paint_volume;
710 /* NB: This volume isn't relative to this actor, it is in eye
711 * coordinates so that it can remain valid after the actor changes.
713 ClutterPaintVolume last_paint_volume;
715 ClutterStageQueueRedrawEntry *queue_redraw_entry;
717 ClutterColor bg_color;
721 /* fixed position and sizes */
722 guint position_set : 1;
723 guint min_width_set : 1;
724 guint min_height_set : 1;
725 guint natural_width_set : 1;
726 guint natural_height_set : 1;
727 /* cached request is invalid (implies allocation is too) */
728 guint needs_width_request : 1;
729 /* cached request is invalid (implies allocation is too) */
730 guint needs_height_request : 1;
731 /* cached allocation is invalid (request has changed, probably) */
732 guint needs_allocation : 1;
733 guint show_on_set_parent : 1;
735 guint clip_to_allocation : 1;
736 guint enable_model_view_transform : 1;
737 guint enable_paint_unmapped : 1;
738 guint has_pointer : 1;
739 guint propagated_one_redraw : 1;
740 guint paint_volume_valid : 1;
741 guint last_paint_volume_valid : 1;
742 guint in_clone_paint : 1;
743 guint transform_valid : 1;
744 /* This is TRUE if anything has queued a redraw since we were last
745 painted. In this case effect_to_redraw will point to an effect
746 the redraw was queued from or it will be NULL if the redraw was
747 queued without an effect. */
749 guint bg_color_set : 1;
758 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
759 * when set they force a size request, when gotten they
760 * get the allocation if the allocation is valid, and the
768 /* Then the rest of these size-related properties are the "actual"
769 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
774 PROP_FIXED_POSITION_SET,
783 PROP_NATURAL_WIDTH_SET,
786 PROP_NATURAL_HEIGHT_SET,
790 /* Allocation properties are read-only */
797 PROP_CLIP_TO_ALLOCATION,
801 PROP_OFFSCREEN_REDIRECT,
814 PROP_ROTATION_ANGLE_X,
815 PROP_ROTATION_ANGLE_Y,
816 PROP_ROTATION_ANGLE_Z,
817 PROP_ROTATION_CENTER_X,
818 PROP_ROTATION_CENTER_Y,
819 PROP_ROTATION_CENTER_Z,
820 /* This property only makes sense for the z rotation because the
821 others would depend on the actor having a size along the
823 PROP_ROTATION_CENTER_Z_GRAVITY,
829 PROP_SHOW_ON_SET_PARENT,
847 PROP_BACKGROUND_COLOR,
848 PROP_BACKGROUND_COLOR_SET,
854 PROP_CONTENT_GRAVITY,
856 PROP_MINIFICATION_FILTER,
857 PROP_MAGNIFICATION_FILTER,
862 static GParamSpec *obj_props[PROP_LAST];
881 BUTTON_RELEASE_EVENT,
889 TRANSITIONS_COMPLETED,
894 static guint actor_signals[LAST_SIGNAL] = { 0, };
896 static void clutter_container_iface_init (ClutterContainerIface *iface);
897 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
898 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
899 static void atk_implementor_iface_init (AtkImplementorIface *iface);
901 /* These setters are all static for now, maybe they should be in the
902 * public API, but they are perhaps obscure enough to leave only as
905 static void clutter_actor_set_min_width (ClutterActor *self,
907 static void clutter_actor_set_min_height (ClutterActor *self,
909 static void clutter_actor_set_natural_width (ClutterActor *self,
910 gfloat natural_width);
911 static void clutter_actor_set_natural_height (ClutterActor *self,
912 gfloat natural_height);
913 static void clutter_actor_set_min_width_set (ClutterActor *self,
914 gboolean use_min_width);
915 static void clutter_actor_set_min_height_set (ClutterActor *self,
916 gboolean use_min_height);
917 static void clutter_actor_set_natural_width_set (ClutterActor *self,
918 gboolean use_natural_width);
919 static void clutter_actor_set_natural_height_set (ClutterActor *self,
920 gboolean use_natural_height);
921 static void clutter_actor_update_map_state (ClutterActor *self,
922 MapStateChange change);
923 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
925 /* Helper routines for managing anchor coords */
926 static void clutter_anchor_coord_get_units (ClutterActor *self,
927 const AnchorCoord *coord,
931 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
936 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
937 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
938 ClutterGravity gravity);
940 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
942 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
944 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
945 ClutterActor *ancestor,
948 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
950 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
952 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
953 const ClutterColor *color);
955 static void on_layout_manager_changed (ClutterLayoutManager *manager,
958 /* Helper macro which translates by the anchor coord, applies the
959 given transformation and then translates back */
960 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
961 gfloat _tx, _ty, _tz; \
962 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
963 cogl_matrix_translate ((m), _tx, _ty, _tz); \
965 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
967 static GQuark quark_shader_data = 0;
968 static GQuark quark_actor_layout_info = 0;
969 static GQuark quark_actor_transform_info = 0;
970 static GQuark quark_actor_animation_info = 0;
972 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
974 G_TYPE_INITIALLY_UNOWNED,
975 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
976 clutter_container_iface_init)
977 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
978 clutter_scriptable_iface_init)
979 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
980 clutter_animatable_iface_init)
981 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
982 atk_implementor_iface_init));
985 * clutter_actor_get_debug_name:
986 * @actor: a #ClutterActor
988 * Retrieves a printable name of @actor for debugging messages
990 * Return value: a string with a printable name
993 _clutter_actor_get_debug_name (ClutterActor *actor)
995 return actor->priv->name != NULL ? actor->priv->name
996 : G_OBJECT_TYPE_NAME (actor);
999 #ifdef CLUTTER_ENABLE_DEBUG
1000 /* XXX - this is for debugging only, remove once working (or leave
1001 * in only in some debug mode). Should leave it for a little while
1002 * until we're confident in the new map/realize/visible handling.
1005 clutter_actor_verify_map_state (ClutterActor *self)
1007 ClutterActorPrivate *priv = self->priv;
1009 if (CLUTTER_ACTOR_IS_REALIZED (self))
1011 /* all bets are off during reparent when we're potentially realized,
1012 * but should not be according to invariants
1014 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1016 if (priv->parent == NULL)
1018 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1022 g_warning ("Realized non-toplevel actor '%s' should "
1024 _clutter_actor_get_debug_name (self));
1026 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1028 g_warning ("Realized actor %s has an unrealized parent %s",
1029 _clutter_actor_get_debug_name (self),
1030 _clutter_actor_get_debug_name (priv->parent));
1035 if (CLUTTER_ACTOR_IS_MAPPED (self))
1037 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1038 g_warning ("Actor '%s' is mapped but not realized",
1039 _clutter_actor_get_debug_name (self));
1041 /* remaining bets are off during reparent when we're potentially
1042 * mapped, but should not be according to invariants
1044 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1046 if (priv->parent == NULL)
1048 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1050 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1051 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1053 g_warning ("Toplevel actor '%s' is mapped "
1055 _clutter_actor_get_debug_name (self));
1060 g_warning ("Mapped actor '%s' should have a parent",
1061 _clutter_actor_get_debug_name (self));
1066 ClutterActor *iter = self;
1068 /* check for the enable_paint_unmapped flag on the actor
1069 * and parents; if the flag is enabled at any point of this
1070 * branch of the scene graph then all the later checks
1073 while (iter != NULL)
1075 if (iter->priv->enable_paint_unmapped)
1078 iter = iter->priv->parent;
1081 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1083 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1085 _clutter_actor_get_debug_name (self),
1086 _clutter_actor_get_debug_name (priv->parent));
1089 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1091 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1093 _clutter_actor_get_debug_name (self),
1094 _clutter_actor_get_debug_name (priv->parent));
1097 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1099 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1100 g_warning ("Actor '%s' is mapped but its non-toplevel "
1101 "parent '%s' is not mapped",
1102 _clutter_actor_get_debug_name (self),
1103 _clutter_actor_get_debug_name (priv->parent));
1110 #endif /* CLUTTER_ENABLE_DEBUG */
1113 clutter_actor_set_mapped (ClutterActor *self,
1116 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1121 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1122 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1126 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1127 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1131 /* this function updates the mapped and realized states according to
1132 * invariants, in the appropriate order.
1135 clutter_actor_update_map_state (ClutterActor *self,
1136 MapStateChange change)
1138 gboolean was_mapped;
1140 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1142 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1144 /* the mapped flag on top-level actors must be set by the
1145 * per-backend implementation because it might be asynchronous.
1147 * That is, the MAPPED flag on toplevels currently tracks the X
1148 * server mapped-ness of the window, while the expected behavior
1149 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1150 * This creates some weird complexity by breaking the invariant
1151 * that if we're visible and all ancestors shown then we are
1152 * also mapped - instead, we are mapped if all ancestors
1153 * _possibly excepting_ the stage are mapped. The stage
1154 * will map/unmap for example when it is minimized or
1155 * moved to another workspace.
1157 * So, the only invariant on the stage is that if visible it
1158 * should be realized, and that it has to be visible to be
1161 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1162 clutter_actor_realize (self);
1166 case MAP_STATE_CHECK:
1169 case MAP_STATE_MAKE_MAPPED:
1170 g_assert (!was_mapped);
1171 clutter_actor_set_mapped (self, TRUE);
1174 case MAP_STATE_MAKE_UNMAPPED:
1175 g_assert (was_mapped);
1176 clutter_actor_set_mapped (self, FALSE);
1179 case MAP_STATE_MAKE_UNREALIZED:
1180 /* we only use MAKE_UNREALIZED in unparent,
1181 * and unparenting a stage isn't possible.
1182 * If someone wants to just unrealize a stage
1183 * then clutter_actor_unrealize() doesn't
1184 * go through this codepath.
1186 g_warning ("Trying to force unrealize stage is not allowed");
1190 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1191 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1192 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1194 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1195 "it is somehow still mapped",
1196 _clutter_actor_get_debug_name (self));
1201 ClutterActorPrivate *priv = self->priv;
1202 ClutterActor *parent = priv->parent;
1203 gboolean should_be_mapped;
1204 gboolean may_be_realized;
1205 gboolean must_be_realized;
1207 should_be_mapped = FALSE;
1208 may_be_realized = TRUE;
1209 must_be_realized = FALSE;
1211 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1213 may_be_realized = FALSE;
1217 /* Maintain invariant that if parent is mapped, and we are
1218 * visible, then we are mapped ... unless parent is a
1219 * stage, in which case we map regardless of parent's map
1220 * state but do require stage to be visible and realized.
1222 * If parent is realized, that does not force us to be
1223 * realized; but if parent is unrealized, that does force
1224 * us to be unrealized.
1226 * The reason we don't force children to realize with
1227 * parents is _clutter_actor_rerealize(); if we require that
1228 * a realized parent means children are realized, then to
1229 * unrealize an actor we would have to unrealize its
1230 * parents, which would end up meaning unrealizing and
1231 * hiding the entire stage. So we allow unrealizing a
1232 * child (as long as that child is not mapped) while that
1233 * child still has a realized parent.
1235 * Also, if we unrealize from leaf nodes to root, and
1236 * realize from root to leaf, the invariants are never
1237 * violated if we allow children to be unrealized
1238 * while parents are realized.
1240 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1241 * to force us to unmap, even though parent is still
1242 * mapped. This is because we're unmapping from leaf nodes
1245 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1246 change != MAP_STATE_MAKE_UNMAPPED)
1248 gboolean parent_is_visible_realized_toplevel;
1250 parent_is_visible_realized_toplevel =
1251 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1252 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1253 CLUTTER_ACTOR_IS_REALIZED (parent));
1255 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1256 parent_is_visible_realized_toplevel)
1258 must_be_realized = TRUE;
1259 should_be_mapped = TRUE;
1263 /* if the actor has been set to be painted even if unmapped
1264 * then we should map it and check for realization as well;
1265 * this is an override for the branch of the scene graph
1266 * which begins with this node
1268 if (priv->enable_paint_unmapped)
1270 if (priv->parent == NULL)
1271 g_warning ("Attempting to map an unparented actor '%s'",
1272 _clutter_actor_get_debug_name (self));
1274 should_be_mapped = TRUE;
1275 must_be_realized = TRUE;
1278 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1279 may_be_realized = FALSE;
1282 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1285 g_warning ("Attempting to map a child that does not "
1286 "meet the necessary invariants: the actor '%s' "
1288 _clutter_actor_get_debug_name (self));
1290 g_warning ("Attempting to map a child that does not "
1291 "meet the necessary invariants: the actor '%s' "
1292 "is parented to an unmapped actor '%s'",
1293 _clutter_actor_get_debug_name (self),
1294 _clutter_actor_get_debug_name (priv->parent));
1297 /* If in reparent, we temporarily suspend unmap and unrealize.
1299 * We want to go in the order "realize, map" and "unmap, unrealize"
1303 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1304 clutter_actor_set_mapped (self, FALSE);
1307 if (must_be_realized)
1308 clutter_actor_realize (self);
1310 /* if we must be realized then we may be, presumably */
1311 g_assert (!(must_be_realized && !may_be_realized));
1314 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1315 clutter_actor_unrealize_not_hiding (self);
1318 if (should_be_mapped)
1320 if (!must_be_realized)
1321 g_warning ("Somehow we think actor '%s' should be mapped but "
1322 "not realized, which isn't allowed",
1323 _clutter_actor_get_debug_name (self));
1325 /* realization is allowed to fail (though I don't know what
1326 * an app is supposed to do about that - shouldn't it just
1327 * be a g_error? anyway, we have to avoid mapping if this
1330 if (CLUTTER_ACTOR_IS_REALIZED (self))
1331 clutter_actor_set_mapped (self, TRUE);
1335 #ifdef CLUTTER_ENABLE_DEBUG
1336 /* check all invariants were kept */
1337 clutter_actor_verify_map_state (self);
1342 clutter_actor_real_map (ClutterActor *self)
1344 ClutterActorPrivate *priv = self->priv;
1345 ClutterActor *stage, *iter;
1347 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1349 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1350 _clutter_actor_get_debug_name (self));
1352 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1354 stage = _clutter_actor_get_stage_internal (self);
1355 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1357 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1359 _clutter_actor_get_debug_name (self));
1361 /* notify on parent mapped before potentially mapping
1362 * children, so apps see a top-down notification.
1364 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1366 for (iter = self->priv->first_child;
1368 iter = iter->priv->next_sibling)
1370 clutter_actor_map (iter);
1375 * clutter_actor_map:
1376 * @self: A #ClutterActor
1378 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1379 * and realizes its children if they are visible. Does nothing if the
1380 * actor is not visible.
1382 * Calling this function is strongly disencouraged: the default
1383 * implementation of #ClutterActorClass.map() will map all the children
1384 * of an actor when mapping its parent.
1386 * When overriding map, it is mandatory to chain up to the parent
1392 clutter_actor_map (ClutterActor *self)
1394 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1396 if (CLUTTER_ACTOR_IS_MAPPED (self))
1399 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1402 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1406 clutter_actor_real_unmap (ClutterActor *self)
1408 ClutterActorPrivate *priv = self->priv;
1411 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1413 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1414 _clutter_actor_get_debug_name (self));
1416 for (iter = self->priv->first_child;
1418 iter = iter->priv->next_sibling)
1420 clutter_actor_unmap (iter);
1423 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1425 /* clear the contents of the last paint volume, so that hiding + moving +
1426 * showing will not result in the wrong area being repainted
1428 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1429 priv->last_paint_volume_valid = TRUE;
1431 /* notify on parent mapped after potentially unmapping
1432 * children, so apps see a bottom-up notification.
1434 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1436 /* relinquish keyboard focus if we were unmapped while owning it */
1437 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1439 ClutterStage *stage;
1441 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1444 _clutter_stage_release_pick_id (stage, priv->pick_id);
1448 if (stage != NULL &&
1449 clutter_stage_get_key_focus (stage) == self)
1451 clutter_stage_set_key_focus (stage, NULL);
1457 * clutter_actor_unmap:
1458 * @self: A #ClutterActor
1460 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1461 * unmaps its children if they were mapped.
1463 * Calling this function is not encouraged: the default #ClutterActor
1464 * implementation of #ClutterActorClass.unmap() will also unmap any
1465 * eventual children by default when their parent is unmapped.
1467 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1468 * chain up to the parent implementation.
1470 * <note>It is important to note that the implementation of the
1471 * #ClutterActorClass.unmap() virtual function may be called after
1472 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1473 * implementation, but it is guaranteed to be called before the
1474 * #GObjectClass.finalize() implementation.</note>
1479 clutter_actor_unmap (ClutterActor *self)
1481 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1483 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1486 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1490 clutter_actor_real_show (ClutterActor *self)
1492 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1494 ClutterActorPrivate *priv = self->priv;
1496 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1498 /* we notify on the "visible" flag in the clutter_actor_show()
1499 * wrapper so the entire show signal emission completes first
1502 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1504 /* we queue a relayout unless the actor is inside a
1505 * container that explicitly told us not to
1507 if (priv->parent != NULL &&
1508 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1510 /* While an actor is hidden the parent may not have
1511 * allocated/requested so we need to start from scratch
1512 * and avoid the short-circuiting in
1513 * clutter_actor_queue_relayout().
1515 priv->needs_width_request = FALSE;
1516 priv->needs_height_request = FALSE;
1517 priv->needs_allocation = FALSE;
1518 clutter_actor_queue_relayout (self);
1524 set_show_on_set_parent (ClutterActor *self,
1527 ClutterActorPrivate *priv = self->priv;
1529 set_show = !!set_show;
1531 if (priv->show_on_set_parent == set_show)
1534 if (priv->parent == NULL)
1536 priv->show_on_set_parent = set_show;
1537 g_object_notify_by_pspec (G_OBJECT (self),
1538 obj_props[PROP_SHOW_ON_SET_PARENT]);
1543 * clutter_actor_show:
1544 * @self: A #ClutterActor
1546 * Flags an actor to be displayed. An actor that isn't shown will not
1547 * be rendered on the stage.
1549 * Actors are visible by default.
1551 * If this function is called on an actor without a parent, the
1552 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1556 clutter_actor_show (ClutterActor *self)
1558 ClutterActorPrivate *priv;
1560 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1562 /* simple optimization */
1563 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1565 /* we still need to set the :show-on-set-parent property, in
1566 * case show() is called on an unparented actor
1568 set_show_on_set_parent (self, TRUE);
1572 #ifdef CLUTTER_ENABLE_DEBUG
1573 clutter_actor_verify_map_state (self);
1578 g_object_freeze_notify (G_OBJECT (self));
1580 set_show_on_set_parent (self, TRUE);
1582 g_signal_emit (self, actor_signals[SHOW], 0);
1583 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1585 if (priv->parent != NULL)
1586 clutter_actor_queue_redraw (priv->parent);
1588 g_object_thaw_notify (G_OBJECT (self));
1592 * clutter_actor_show_all:
1593 * @self: a #ClutterActor
1595 * Calls clutter_actor_show() on all children of an actor (if any).
1599 * Deprecated: 1.10: Actors are visible by default
1602 clutter_actor_show_all (ClutterActor *self)
1604 ClutterActorClass *klass;
1606 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1608 klass = CLUTTER_ACTOR_GET_CLASS (self);
1609 if (klass->show_all)
1610 klass->show_all (self);
1614 clutter_actor_real_hide (ClutterActor *self)
1616 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1618 ClutterActorPrivate *priv = self->priv;
1620 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1622 /* we notify on the "visible" flag in the clutter_actor_hide()
1623 * wrapper so the entire hide signal emission completes first
1626 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1628 /* we queue a relayout unless the actor is inside a
1629 * container that explicitly told us not to
1631 if (priv->parent != NULL &&
1632 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1633 clutter_actor_queue_relayout (priv->parent);
1638 * clutter_actor_hide:
1639 * @self: A #ClutterActor
1641 * Flags an actor to be hidden. A hidden actor will not be
1642 * rendered on the stage.
1644 * Actors are visible by default.
1646 * If this function is called on an actor without a parent, the
1647 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1651 clutter_actor_hide (ClutterActor *self)
1653 ClutterActorPrivate *priv;
1655 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1657 /* simple optimization */
1658 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1660 /* we still need to set the :show-on-set-parent property, in
1661 * case hide() is called on an unparented actor
1663 set_show_on_set_parent (self, FALSE);
1667 #ifdef CLUTTER_ENABLE_DEBUG
1668 clutter_actor_verify_map_state (self);
1673 g_object_freeze_notify (G_OBJECT (self));
1675 set_show_on_set_parent (self, FALSE);
1677 g_signal_emit (self, actor_signals[HIDE], 0);
1678 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1680 if (priv->parent != NULL)
1681 clutter_actor_queue_redraw (priv->parent);
1683 g_object_thaw_notify (G_OBJECT (self));
1687 * clutter_actor_hide_all:
1688 * @self: a #ClutterActor
1690 * Calls clutter_actor_hide() on all child actors (if any).
1694 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1695 * prevent its children from being painted as well.
1698 clutter_actor_hide_all (ClutterActor *self)
1700 ClutterActorClass *klass;
1702 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1704 klass = CLUTTER_ACTOR_GET_CLASS (self);
1705 if (klass->hide_all)
1706 klass->hide_all (self);
1710 * clutter_actor_realize:
1711 * @self: A #ClutterActor
1713 * Realization informs the actor that it is attached to a stage. It
1714 * can use this to allocate resources if it wanted to delay allocation
1715 * until it would be rendered. However it is perfectly acceptable for
1716 * an actor to create resources before being realized because Clutter
1717 * only ever has a single rendering context so that actor is free to
1718 * be moved from one stage to another.
1720 * This function does nothing if the actor is already realized.
1722 * Because a realized actor must have realized parent actors, calling
1723 * clutter_actor_realize() will also realize all parents of the actor.
1725 * This function does not realize child actors, except in the special
1726 * case that realizing the stage, when the stage is visible, will
1727 * suddenly map (and thus realize) the children of the stage.
1730 clutter_actor_realize (ClutterActor *self)
1732 ClutterActorPrivate *priv;
1734 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1738 #ifdef CLUTTER_ENABLE_DEBUG
1739 clutter_actor_verify_map_state (self);
1742 if (CLUTTER_ACTOR_IS_REALIZED (self))
1745 /* To be realized, our parent actors must be realized first.
1746 * This will only succeed if we're inside a toplevel.
1748 if (priv->parent != NULL)
1749 clutter_actor_realize (priv->parent);
1751 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1753 /* toplevels can be realized at any time */
1757 /* "Fail" the realization if parent is missing or unrealized;
1758 * this should really be a g_warning() not some kind of runtime
1759 * failure; how can an app possibly recover? Instead it's a bug
1760 * in the app and the app should get an explanatory warning so
1761 * someone can fix it. But for now it's too hard to fix this
1762 * because e.g. ClutterTexture needs reworking.
1764 if (priv->parent == NULL ||
1765 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1769 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1771 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1772 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1774 g_signal_emit (self, actor_signals[REALIZE], 0);
1776 /* Stage actor is allowed to unset the realized flag again in its
1777 * default signal handler, though that is a pathological situation.
1780 /* If realization "failed" we'll have to update child state. */
1781 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1785 clutter_actor_real_unrealize (ClutterActor *self)
1787 /* we must be unmapped (implying our children are also unmapped) */
1788 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1792 * clutter_actor_unrealize:
1793 * @self: A #ClutterActor
1795 * Unrealization informs the actor that it may be being destroyed or
1796 * moved to another stage. The actor may want to destroy any
1797 * underlying graphics resources at this point. However it is
1798 * perfectly acceptable for it to retain the resources until the actor
1799 * is destroyed because Clutter only ever uses a single rendering
1800 * context and all of the graphics resources are valid on any stage.
1802 * Because mapped actors must be realized, actors may not be
1803 * unrealized if they are mapped. This function hides the actor to be
1804 * sure it isn't mapped, an application-visible side effect that you
1805 * may not be expecting.
1807 * This function should not be called by application code.
1810 clutter_actor_unrealize (ClutterActor *self)
1812 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1813 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1815 /* This function should not really be in the public API, because
1816 * there isn't a good reason to call it. ClutterActor will already
1817 * unrealize things for you when it's important to do so.
1819 * If you were using clutter_actor_unrealize() in a dispose
1820 * implementation, then don't, just chain up to ClutterActor's
1823 * If you were using clutter_actor_unrealize() to implement
1824 * unrealizing children of your container, then don't, ClutterActor
1825 * will already take care of that.
1827 * If you were using clutter_actor_unrealize() to re-realize to
1828 * create your resources in a different way, then use
1829 * _clutter_actor_rerealize() (inside Clutter) or just call your
1830 * code that recreates your resources directly (outside Clutter).
1833 #ifdef CLUTTER_ENABLE_DEBUG
1834 clutter_actor_verify_map_state (self);
1837 clutter_actor_hide (self);
1839 clutter_actor_unrealize_not_hiding (self);
1842 static ClutterActorTraverseVisitFlags
1843 unrealize_actor_before_children_cb (ClutterActor *self,
1847 /* If an actor is already unrealized we know its children have also
1848 * already been unrealized... */
1849 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1850 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1852 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1854 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1857 static ClutterActorTraverseVisitFlags
1858 unrealize_actor_after_children_cb (ClutterActor *self,
1862 /* We want to unset the realized flag only _after_
1863 * child actors are unrealized, to maintain invariants.
1865 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1866 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1867 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1871 * clutter_actor_unrealize_not_hiding:
1872 * @self: A #ClutterActor
1874 * Unrealization informs the actor that it may be being destroyed or
1875 * moved to another stage. The actor may want to destroy any
1876 * underlying graphics resources at this point. However it is
1877 * perfectly acceptable for it to retain the resources until the actor
1878 * is destroyed because Clutter only ever uses a single rendering
1879 * context and all of the graphics resources are valid on any stage.
1881 * Because mapped actors must be realized, actors may not be
1882 * unrealized if they are mapped. You must hide the actor or one of
1883 * its parents before attempting to unrealize.
1885 * This function is separate from clutter_actor_unrealize() because it
1886 * does not automatically hide the actor.
1887 * Actors need not be hidden to be unrealized, they just need to
1888 * be unmapped. In fact we don't want to mess up the application's
1889 * setting of the "visible" flag, so hiding is very undesirable.
1891 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1892 * backward compatibility.
1895 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1897 _clutter_actor_traverse (self,
1898 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1899 unrealize_actor_before_children_cb,
1900 unrealize_actor_after_children_cb,
1905 * _clutter_actor_rerealize:
1906 * @self: A #ClutterActor
1907 * @callback: Function to call while unrealized
1908 * @data: data for callback
1910 * If an actor is already unrealized, this just calls the callback.
1912 * If it is realized, it unrealizes temporarily, calls the callback,
1913 * and then re-realizes the actor.
1915 * As a side effect, leaves all children of the actor unrealized if
1916 * the actor was realized but not showing. This is because when we
1917 * unrealize the actor temporarily we must unrealize its children
1918 * (e.g. children of a stage can't be realized if stage window is
1919 * gone). And we aren't clever enough to save the realization state of
1920 * all children. In most cases this should not matter, because
1921 * the children will automatically realize when they next become mapped.
1924 _clutter_actor_rerealize (ClutterActor *self,
1925 ClutterCallback callback,
1928 gboolean was_mapped;
1929 gboolean was_showing;
1930 gboolean was_realized;
1932 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1934 #ifdef CLUTTER_ENABLE_DEBUG
1935 clutter_actor_verify_map_state (self);
1938 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1939 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1940 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1942 /* Must be unmapped to unrealize. Note we only have to hide this
1943 * actor if it was mapped (if all parents were showing). If actor
1944 * is merely visible (but not mapped), then that's fine, we can
1948 clutter_actor_hide (self);
1950 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1952 /* unrealize self and all children */
1953 clutter_actor_unrealize_not_hiding (self);
1955 if (callback != NULL)
1957 (* callback) (self, data);
1961 clutter_actor_show (self); /* will realize only if mapping implies it */
1962 else if (was_realized)
1963 clutter_actor_realize (self); /* realize self and all parents */
1967 clutter_actor_real_pick (ClutterActor *self,
1968 const ClutterColor *color)
1970 /* the default implementation is just to paint a rectangle
1971 * with the same size of the actor using the passed color
1973 if (clutter_actor_should_pick_paint (self))
1975 ClutterActorBox box = { 0, };
1976 float width, height;
1978 clutter_actor_get_allocation_box (self, &box);
1980 width = box.x2 - box.x1;
1981 height = box.y2 - box.y1;
1983 cogl_set_source_color4ub (color->red,
1988 cogl_rectangle (0, 0, width, height);
1991 /* XXX - this thoroughly sucks, but we need to maintain compatibility
1992 * with existing container classes that override the pick() virtual
1993 * and chain up to the default implementation - otherwise we'll end up
1994 * painting our children twice.
1996 * this has to go away for 2.0; hopefully along the pick() itself.
1998 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2002 for (iter = self->priv->first_child;
2004 iter = iter->priv->next_sibling)
2005 clutter_actor_paint (iter);
2010 * clutter_actor_should_pick_paint:
2011 * @self: A #ClutterActor
2013 * Should be called inside the implementation of the
2014 * #ClutterActor::pick virtual function in order to check whether
2015 * the actor should paint itself in pick mode or not.
2017 * This function should never be called directly by applications.
2019 * Return value: %TRUE if the actor should paint its silhouette,
2023 clutter_actor_should_pick_paint (ClutterActor *self)
2025 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2027 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2028 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2029 CLUTTER_ACTOR_IS_REACTIVE (self)))
2036 clutter_actor_real_get_preferred_width (ClutterActor *self,
2038 gfloat *min_width_p,
2039 gfloat *natural_width_p)
2041 ClutterActorPrivate *priv = self->priv;
2043 if (priv->n_children != 0 &&
2044 priv->layout_manager != NULL)
2046 ClutterContainer *container = CLUTTER_CONTAINER (self);
2048 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2049 "for the preferred width",
2050 G_OBJECT_TYPE_NAME (priv->layout_manager),
2051 priv->layout_manager);
2053 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2062 /* Default implementation is always 0x0, usually an actor
2063 * using this default is relying on someone to set the
2066 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2071 if (natural_width_p)
2072 *natural_width_p = 0;
2076 clutter_actor_real_get_preferred_height (ClutterActor *self,
2078 gfloat *min_height_p,
2079 gfloat *natural_height_p)
2081 ClutterActorPrivate *priv = self->priv;
2083 if (priv->n_children != 0 &&
2084 priv->layout_manager != NULL)
2086 ClutterContainer *container = CLUTTER_CONTAINER (self);
2088 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2089 "for the preferred height",
2090 G_OBJECT_TYPE_NAME (priv->layout_manager),
2091 priv->layout_manager);
2093 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2101 /* Default implementation is always 0x0, usually an actor
2102 * using this default is relying on someone to set the
2105 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2110 if (natural_height_p)
2111 *natural_height_p = 0;
2115 clutter_actor_store_old_geometry (ClutterActor *self,
2116 ClutterActorBox *box)
2118 *box = self->priv->allocation;
2122 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2123 const ClutterActorBox *old)
2125 ClutterActorPrivate *priv = self->priv;
2126 GObject *obj = G_OBJECT (self);
2128 g_object_freeze_notify (obj);
2130 /* to avoid excessive requisition or allocation cycles we
2131 * use the cached values.
2133 * - if we don't have an allocation we assume that we need
2135 * - if we don't have a width or a height request we notify
2137 * - if we have a valid allocation then we check the old
2138 * bounding box with the current allocation and we notify
2141 if (priv->needs_allocation)
2143 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2144 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2145 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2146 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2148 else if (priv->needs_width_request || priv->needs_height_request)
2150 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2151 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2156 gfloat width, height;
2158 x = priv->allocation.x1;
2159 y = priv->allocation.y1;
2160 width = priv->allocation.x2 - priv->allocation.x1;
2161 height = priv->allocation.y2 - priv->allocation.y1;
2164 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2167 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2169 if (width != (old->x2 - old->x1))
2170 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2172 if (height != (old->y2 - old->y1))
2173 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2176 g_object_thaw_notify (obj);
2180 * clutter_actor_set_allocation_internal:
2181 * @self: a #ClutterActor
2182 * @box: a #ClutterActorBox
2183 * @flags: allocation flags
2185 * Stores the allocation of @self.
2187 * This function only performs basic storage and property notification.
2189 * This function should be called by clutter_actor_set_allocation()
2190 * and by the default implementation of #ClutterActorClass.allocate().
2192 * Return value: %TRUE if the allocation of the #ClutterActor has been
2193 * changed, and %FALSE otherwise
2195 static inline gboolean
2196 clutter_actor_set_allocation_internal (ClutterActor *self,
2197 const ClutterActorBox *box,
2198 ClutterAllocationFlags flags)
2200 ClutterActorPrivate *priv = self->priv;
2202 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2203 gboolean flags_changed;
2205 ClutterActorBox old_alloc = { 0, };
2207 obj = G_OBJECT (self);
2209 g_object_freeze_notify (obj);
2211 clutter_actor_store_old_geometry (self, &old_alloc);
2213 x1_changed = priv->allocation.x1 != box->x1;
2214 y1_changed = priv->allocation.y1 != box->y1;
2215 x2_changed = priv->allocation.x2 != box->x2;
2216 y2_changed = priv->allocation.y2 != box->y2;
2218 flags_changed = priv->allocation_flags != flags;
2220 priv->allocation = *box;
2221 priv->allocation_flags = flags;
2223 /* allocation is authoritative */
2224 priv->needs_width_request = FALSE;
2225 priv->needs_height_request = FALSE;
2226 priv->needs_allocation = FALSE;
2228 if (x1_changed || y1_changed ||
2229 x2_changed || y2_changed ||
2232 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2233 _clutter_actor_get_debug_name (self));
2235 priv->transform_valid = FALSE;
2237 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2239 /* if the allocation changes, so does the content box */
2240 if (priv->content != NULL)
2241 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2248 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2250 g_object_thaw_notify (obj);
2255 static void clutter_actor_real_allocate (ClutterActor *self,
2256 const ClutterActorBox *box,
2257 ClutterAllocationFlags flags);
2260 clutter_actor_maybe_layout_children (ClutterActor *self,
2261 const ClutterActorBox *allocation,
2262 ClutterAllocationFlags flags)
2264 ClutterActorPrivate *priv = self->priv;
2266 /* this is going to be a bit hard to follow, so let's put an explanation
2269 * we want ClutterActor to have a default layout manager if the actor was
2270 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2272 * we also want any subclass of ClutterActor that does not override the
2273 * ::allocate() virtual function to delegate to a layout manager.
2275 * finally, we want to allow people subclassing ClutterActor and overriding
2276 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2278 * on the other hand, we want existing actor subclasses overriding the
2279 * ::allocate() virtual function and chaining up to the parent's
2280 * implementation to continue working without allocating their children
2281 * twice, or without entering an allocation loop.
2283 * for the first two points, we check if the class of the actor is
2284 * overridding the ::allocate() virtual function; if it isn't, then we
2285 * follow through with checking whether we have children and a layout
2286 * manager, and eventually calling clutter_layout_manager_allocate().
2288 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2289 * allocation flags that we got passed, and if it is present, we continue
2290 * with the check above.
2292 * if neither of these two checks yields a positive result, we just
2293 * assume that the ::allocate() virtual function that resulted in this
2294 * function being called will also allocate the children of the actor.
2297 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2300 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2306 if (priv->n_children != 0 &&
2307 priv->layout_manager != NULL)
2309 ClutterContainer *container = CLUTTER_CONTAINER (self);
2310 ClutterAllocationFlags children_flags;
2311 ClutterActorBox children_box;
2313 /* normalize the box passed to the layout manager */
2314 children_box.x1 = children_box.y1 = 0.f;
2315 children_box.x2 = (allocation->x2 - allocation->x1);
2316 children_box.y2 = (allocation->y2 - allocation->y1);
2318 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2319 * the actor's children, since it refers only to the current
2320 * actor's allocation.
2322 children_flags = flags;
2323 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2325 CLUTTER_NOTE (LAYOUT,
2326 "Allocating %d children of %s "
2327 "at { %.2f, %.2f - %.2f x %.2f } "
2330 _clutter_actor_get_debug_name (self),
2333 (allocation->x2 - allocation->x1),
2334 (allocation->y2 - allocation->y1),
2335 G_OBJECT_TYPE_NAME (priv->layout_manager));
2337 clutter_layout_manager_allocate (priv->layout_manager,
2345 clutter_actor_real_allocate (ClutterActor *self,
2346 const ClutterActorBox *box,
2347 ClutterAllocationFlags flags)
2349 ClutterActorPrivate *priv = self->priv;
2352 g_object_freeze_notify (G_OBJECT (self));
2354 changed = clutter_actor_set_allocation_internal (self, box, flags);
2356 /* we allocate our children before we notify changes in our geometry,
2357 * so that people connecting to properties will be able to get valid
2358 * data out of the sub-tree of the scene graph that has this actor at
2361 clutter_actor_maybe_layout_children (self, box, flags);
2365 ClutterActorBox signal_box = priv->allocation;
2366 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2368 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2373 g_object_thaw_notify (G_OBJECT (self));
2377 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2378 ClutterActor *origin)
2380 /* no point in queuing a redraw on a destroyed actor */
2381 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2384 /* NB: We can't bail out early here if the actor is hidden in case
2385 * the actor bas been cloned. In this case the clone will need to
2386 * receive the signal so it can queue its own redraw.
2389 /* calls klass->queue_redraw in default handler */
2390 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2394 clutter_actor_real_queue_redraw (ClutterActor *self,
2395 ClutterActor *origin)
2397 ClutterActor *parent;
2399 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2400 _clutter_actor_get_debug_name (self),
2401 origin != NULL ? _clutter_actor_get_debug_name (origin)
2404 /* no point in queuing a redraw on a destroyed actor */
2405 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2408 /* If the queue redraw is coming from a child then the actor has
2409 become dirty and any queued effect is no longer valid */
2412 self->priv->is_dirty = TRUE;
2413 self->priv->effect_to_redraw = NULL;
2416 /* If the actor isn't visible, we still had to emit the signal
2417 * to allow for a ClutterClone, but the appearance of the parent
2418 * won't change so we don't have to propagate up the hierarchy.
2420 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2423 /* Although we could determine here that a full stage redraw
2424 * has already been queued and immediately bail out, we actually
2425 * guarantee that we will propagate a queue-redraw signal to our
2426 * parent at least once so that it's possible to implement a
2427 * container that tracks which of its children have queued a
2430 if (self->priv->propagated_one_redraw)
2432 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2433 if (stage != NULL &&
2434 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2438 self->priv->propagated_one_redraw = TRUE;
2440 /* notify parents, if they are all visible eventually we'll
2441 * queue redraw on the stage, which queues the redraw idle.
2443 parent = clutter_actor_get_parent (self);
2446 /* this will go up recursively */
2447 _clutter_actor_signal_queue_redraw (parent, origin);
2452 clutter_actor_real_queue_relayout (ClutterActor *self)
2454 ClutterActorPrivate *priv = self->priv;
2456 /* no point in queueing a redraw on a destroyed actor */
2457 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2460 priv->needs_width_request = TRUE;
2461 priv->needs_height_request = TRUE;
2462 priv->needs_allocation = TRUE;
2464 /* reset the cached size requests */
2465 memset (priv->width_requests, 0,
2466 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2467 memset (priv->height_requests, 0,
2468 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2470 /* We need to go all the way up the hierarchy */
2471 if (priv->parent != NULL)
2472 _clutter_actor_queue_only_relayout (priv->parent);
2476 * clutter_actor_apply_relative_transform_to_point:
2477 * @self: A #ClutterActor
2478 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2479 * default #ClutterStage
2480 * @point: A point as #ClutterVertex
2481 * @vertex: (out caller-allocates): The translated #ClutterVertex
2483 * Transforms @point in coordinates relative to the actor into
2484 * ancestor-relative coordinates using the relevant transform
2485 * stack (i.e. scale, rotation, etc).
2487 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2488 * this case, the coordinates returned will be the coordinates on
2489 * the stage before the projection is applied. This is different from
2490 * the behaviour of clutter_actor_apply_transform_to_point().
2495 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2496 ClutterActor *ancestor,
2497 const ClutterVertex *point,
2498 ClutterVertex *vertex)
2503 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2504 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2505 g_return_if_fail (point != NULL);
2506 g_return_if_fail (vertex != NULL);
2511 if (ancestor == NULL)
2512 ancestor = _clutter_actor_get_stage_internal (self);
2514 if (ancestor == NULL)
2520 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2521 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2525 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2526 const ClutterVertex *vertices_in,
2527 ClutterVertex *vertices_out,
2530 ClutterActor *stage;
2531 CoglMatrix modelview;
2532 CoglMatrix projection;
2535 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2537 stage = _clutter_actor_get_stage_internal (self);
2539 /* We really can't do anything meaningful in this case so don't try
2540 * to do any transform */
2544 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2545 * that gets us to stage coordinates, we want to go all the way to eye
2547 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2549 /* Fetch the projection and viewport */
2550 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2551 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2557 _clutter_util_fully_transform_vertices (&modelview,
2568 * clutter_actor_apply_transform_to_point:
2569 * @self: A #ClutterActor
2570 * @point: A point as #ClutterVertex
2571 * @vertex: (out caller-allocates): The translated #ClutterVertex
2573 * Transforms @point in coordinates relative to the actor
2574 * into screen-relative coordinates with the current actor
2575 * transformation (i.e. scale, rotation, etc)
2580 clutter_actor_apply_transform_to_point (ClutterActor *self,
2581 const ClutterVertex *point,
2582 ClutterVertex *vertex)
2584 g_return_if_fail (point != NULL);
2585 g_return_if_fail (vertex != NULL);
2586 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2590 * _clutter_actor_get_relative_transformation_matrix:
2591 * @self: The actor whose coordinate space you want to transform from.
2592 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2593 * or %NULL if you want to transform all the way to eye coordinates.
2594 * @matrix: A #CoglMatrix to store the transformation
2596 * This gets a transformation @matrix that will transform coordinates from the
2597 * coordinate space of @self into the coordinate space of @ancestor.
2599 * For example if you need a matrix that can transform the local actor
2600 * coordinates of @self into stage coordinates you would pass the actor's stage
2601 * pointer as the @ancestor.
2603 * If you pass %NULL then the transformation will take you all the way through
2604 * to eye coordinates. This can be useful if you want to extract the entire
2605 * modelview transform that Clutter applies before applying the projection
2606 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2607 * using cogl_set_modelview_matrix() for example then you would want a matrix
2608 * that transforms into eye coordinates.
2610 * <note><para>This function explicitly initializes the given @matrix. If you just
2611 * want clutter to multiply a relative transformation with an existing matrix
2612 * you can use clutter_actor_apply_relative_transformation_matrix()
2613 * instead.</para></note>
2616 /* XXX: We should consider caching the stage relative modelview along with
2617 * the actor itself */
2619 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2620 ClutterActor *ancestor,
2623 cogl_matrix_init_identity (matrix);
2625 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2628 /* Project the given @box into stage window coordinates, writing the
2629 * transformed vertices to @verts[]. */
2631 _clutter_actor_transform_and_project_box (ClutterActor *self,
2632 const ClutterActorBox *box,
2633 ClutterVertex verts[])
2635 ClutterVertex box_vertices[4];
2637 box_vertices[0].x = box->x1;
2638 box_vertices[0].y = box->y1;
2639 box_vertices[0].z = 0;
2640 box_vertices[1].x = box->x2;
2641 box_vertices[1].y = box->y1;
2642 box_vertices[1].z = 0;
2643 box_vertices[2].x = box->x1;
2644 box_vertices[2].y = box->y2;
2645 box_vertices[2].z = 0;
2646 box_vertices[3].x = box->x2;
2647 box_vertices[3].y = box->y2;
2648 box_vertices[3].z = 0;
2651 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2655 * clutter_actor_get_allocation_vertices:
2656 * @self: A #ClutterActor
2657 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2658 * against, or %NULL to use the #ClutterStage
2659 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2660 * location for an array of 4 #ClutterVertex in which to store the result
2662 * Calculates the transformed coordinates of the four corners of the
2663 * actor in the plane of @ancestor. The returned vertices relate to
2664 * the #ClutterActorBox coordinates as follows:
2666 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2667 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2668 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2669 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2672 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2673 * this case, the coordinates returned will be the coordinates on
2674 * the stage before the projection is applied. This is different from
2675 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2680 clutter_actor_get_allocation_vertices (ClutterActor *self,
2681 ClutterActor *ancestor,
2682 ClutterVertex verts[])
2684 ClutterActorPrivate *priv;
2685 ClutterActorBox box;
2686 ClutterVertex vertices[4];
2687 CoglMatrix modelview;
2689 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2690 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2692 if (ancestor == NULL)
2693 ancestor = _clutter_actor_get_stage_internal (self);
2695 /* Fallback to a NOP transform if the actor isn't parented under a
2697 if (ancestor == NULL)
2702 /* if the actor needs to be allocated we force a relayout, so that
2703 * we will have valid values to use in the transformations */
2704 if (priv->needs_allocation)
2706 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2708 _clutter_stage_maybe_relayout (stage);
2711 box.x1 = box.y1 = 0;
2712 /* The result isn't really meaningful in this case but at
2713 * least try to do something *vaguely* reasonable... */
2714 clutter_actor_get_size (self, &box.x2, &box.y2);
2718 clutter_actor_get_allocation_box (self, &box);
2720 vertices[0].x = box.x1;
2721 vertices[0].y = box.y1;
2723 vertices[1].x = box.x2;
2724 vertices[1].y = box.y1;
2726 vertices[2].x = box.x1;
2727 vertices[2].y = box.y2;
2729 vertices[3].x = box.x2;
2730 vertices[3].y = box.y2;
2733 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2736 cogl_matrix_transform_points (&modelview,
2738 sizeof (ClutterVertex),
2740 sizeof (ClutterVertex),
2746 * clutter_actor_get_abs_allocation_vertices:
2747 * @self: A #ClutterActor
2748 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2749 * of 4 #ClutterVertex where to store the result.
2751 * Calculates the transformed screen coordinates of the four corners of
2752 * the actor; the returned vertices relate to the #ClutterActorBox
2753 * coordinates as follows:
2755 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2756 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2757 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2758 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2764 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2765 ClutterVertex verts[])
2767 ClutterActorPrivate *priv;
2768 ClutterActorBox actor_space_allocation;
2770 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2774 /* if the actor needs to be allocated we force a relayout, so that
2775 * the actor allocation box will be valid for
2776 * _clutter_actor_transform_and_project_box()
2778 if (priv->needs_allocation)
2780 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2781 /* There's nothing meaningful we can do now */
2785 _clutter_stage_maybe_relayout (stage);
2788 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2789 * own coordinate space... */
2790 actor_space_allocation.x1 = 0;
2791 actor_space_allocation.y1 = 0;
2792 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2793 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2794 _clutter_actor_transform_and_project_box (self,
2795 &actor_space_allocation,
2800 clutter_actor_real_apply_transform (ClutterActor *self,
2803 ClutterActorPrivate *priv = self->priv;
2805 if (!priv->transform_valid)
2807 CoglMatrix *transform = &priv->transform;
2808 const ClutterTransformInfo *info;
2810 info = _clutter_actor_get_transform_info_or_defaults (self);
2812 cogl_matrix_init_identity (transform);
2814 cogl_matrix_translate (transform,
2815 priv->allocation.x1,
2816 priv->allocation.y1,
2820 cogl_matrix_translate (transform, 0, 0, info->depth);
2823 * because the rotation involves translations, we must scale
2824 * before applying the rotations (if we apply the scale after
2825 * the rotations, the translations included in the rotation are
2826 * not scaled and so the entire object will move on the screen
2827 * as a result of rotating it).
2829 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2831 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2832 &info->scale_center,
2833 cogl_matrix_scale (transform,
2840 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2842 cogl_matrix_rotate (transform,
2847 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2849 cogl_matrix_rotate (transform,
2854 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2856 cogl_matrix_rotate (transform,
2860 if (!clutter_anchor_coord_is_zero (&info->anchor))
2864 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2865 cogl_matrix_translate (transform, -x, -y, -z);
2868 priv->transform_valid = TRUE;
2871 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2874 /* Applies the transforms associated with this actor to the given
2877 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2880 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2884 * clutter_actor_apply_relative_transformation_matrix:
2885 * @self: The actor whose coordinate space you want to transform from.
2886 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2887 * or %NULL if you want to transform all the way to eye coordinates.
2888 * @matrix: A #CoglMatrix to apply the transformation too.
2890 * This multiplies a transform with @matrix that will transform coordinates
2891 * from the coordinate space of @self into the coordinate space of @ancestor.
2893 * For example if you need a matrix that can transform the local actor
2894 * coordinates of @self into stage coordinates you would pass the actor's stage
2895 * pointer as the @ancestor.
2897 * If you pass %NULL then the transformation will take you all the way through
2898 * to eye coordinates. This can be useful if you want to extract the entire
2899 * modelview transform that Clutter applies before applying the projection
2900 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2901 * using cogl_set_modelview_matrix() for example then you would want a matrix
2902 * that transforms into eye coordinates.
2904 * <note>This function doesn't initialize the given @matrix, it simply
2905 * multiplies the requested transformation matrix with the existing contents of
2906 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2907 * before calling this function, or you can use
2908 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2911 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2912 ClutterActor *ancestor,
2915 ClutterActor *parent;
2917 /* Note we terminate before ever calling stage->apply_transform()
2918 * since that would conceptually be relative to the underlying
2919 * window OpenGL coordinates so we'd need a special @ancestor
2920 * value to represent the fake parent of the stage. */
2921 if (self == ancestor)
2924 parent = clutter_actor_get_parent (self);
2927 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2930 _clutter_actor_apply_modelview_transform (self, matrix);
2934 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2935 ClutterPaintVolume *pv,
2937 const CoglColor *color)
2939 static CoglPipeline *outline = NULL;
2940 CoglPrimitive *prim;
2941 ClutterVertex line_ends[12 * 2];
2944 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2945 /* XXX: at some point we'll query this from the stage but we can't
2946 * do that until the osx backend uses Cogl natively. */
2947 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2949 if (outline == NULL)
2950 outline = cogl_pipeline_new (ctx);
2952 _clutter_paint_volume_complete (pv);
2954 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2957 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2958 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2959 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2960 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2965 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2966 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2967 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2968 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2970 /* Lines connecting front face to back face */
2971 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2972 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2973 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2974 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2977 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2979 (CoglVertexP3 *)line_ends);
2981 cogl_pipeline_set_color (outline, color);
2982 cogl_framebuffer_draw_primitive (fb, outline, prim);
2983 cogl_object_unref (prim);
2987 PangoLayout *layout;
2988 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2989 pango_layout_set_text (layout, label, -1);
2990 cogl_pango_render_layout (layout,
2995 g_object_unref (layout);
3000 _clutter_actor_draw_paint_volume (ClutterActor *self)
3002 ClutterPaintVolume *pv;
3005 pv = _clutter_actor_get_paint_volume_mutable (self);
3008 gfloat width, height;
3009 ClutterPaintVolume fake_pv;
3011 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3012 _clutter_paint_volume_init_static (&fake_pv, stage);
3014 clutter_actor_get_size (self, &width, &height);
3015 clutter_paint_volume_set_width (&fake_pv, width);
3016 clutter_paint_volume_set_height (&fake_pv, height);
3018 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3019 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3020 _clutter_actor_get_debug_name (self),
3023 clutter_paint_volume_free (&fake_pv);
3027 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3028 _clutter_actor_draw_paint_volume_full (self, pv,
3029 _clutter_actor_get_debug_name (self),
3035 _clutter_actor_paint_cull_result (ClutterActor *self,
3037 ClutterCullResult result)
3039 ClutterPaintVolume *pv;
3044 if (result == CLUTTER_CULL_RESULT_IN)
3045 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3046 else if (result == CLUTTER_CULL_RESULT_OUT)
3047 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3049 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3052 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3054 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3055 _clutter_actor_draw_paint_volume_full (self, pv,
3056 _clutter_actor_get_debug_name (self),
3060 PangoLayout *layout;
3062 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3063 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3064 cogl_set_source_color (&color);
3066 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3067 pango_layout_set_text (layout, label, -1);
3068 cogl_pango_render_layout (layout,
3074 g_object_unref (layout);
3078 static int clone_paint_level = 0;
3081 _clutter_actor_push_clone_paint (void)
3083 clone_paint_level++;
3087 _clutter_actor_pop_clone_paint (void)
3089 clone_paint_level--;
3093 in_clone_paint (void)
3095 return clone_paint_level > 0;
3098 /* Returns TRUE if the actor can be ignored */
3099 /* FIXME: we should return a ClutterCullResult, and
3100 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3101 * means there's no point in trying to cull descendants of the current
3104 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3106 ClutterActorPrivate *priv = self->priv;
3107 ClutterActor *stage;
3108 const ClutterPlane *stage_clip;
3110 if (!priv->last_paint_volume_valid)
3112 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3113 "->last_paint_volume_valid == FALSE",
3114 _clutter_actor_get_debug_name (self));
3118 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3121 stage = _clutter_actor_get_stage_internal (self);
3122 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3123 if (G_UNLIKELY (!stage_clip))
3125 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3126 "No stage clip set",
3127 _clutter_actor_get_debug_name (self));
3131 if (cogl_get_draw_framebuffer () !=
3132 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3134 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3135 "Current framebuffer doesn't correspond to stage",
3136 _clutter_actor_get_debug_name (self));
3141 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3146 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3148 ClutterActorPrivate *priv = self->priv;
3149 const ClutterPaintVolume *pv;
3151 if (priv->last_paint_volume_valid)
3153 clutter_paint_volume_free (&priv->last_paint_volume);
3154 priv->last_paint_volume_valid = FALSE;
3157 pv = clutter_actor_get_paint_volume (self);
3160 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3161 "Actor failed to report a paint volume",
3162 _clutter_actor_get_debug_name (self));
3166 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3168 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3169 NULL); /* eye coordinates */
3171 priv->last_paint_volume_valid = TRUE;
3174 static inline gboolean
3175 actor_has_shader_data (ClutterActor *self)
3177 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3181 _clutter_actor_get_pick_id (ClutterActor *self)
3183 if (self->priv->pick_id < 0)
3186 return self->priv->pick_id;
3189 /* This is the same as clutter_actor_add_effect except that it doesn't
3190 queue a redraw and it doesn't notify on the effect property */
3192 _clutter_actor_add_effect_internal (ClutterActor *self,
3193 ClutterEffect *effect)
3195 ClutterActorPrivate *priv = self->priv;
3197 if (priv->effects == NULL)
3199 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3200 priv->effects->actor = self;
3203 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3206 /* This is the same as clutter_actor_remove_effect except that it doesn't
3207 queue a redraw and it doesn't notify on the effect property */
3209 _clutter_actor_remove_effect_internal (ClutterActor *self,
3210 ClutterEffect *effect)
3212 ClutterActorPrivate *priv = self->priv;
3214 if (priv->effects == NULL)
3217 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3221 needs_flatten_effect (ClutterActor *self)
3223 ClutterActorPrivate *priv = self->priv;
3225 if (G_UNLIKELY (clutter_paint_debug_flags &
3226 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3229 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3231 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3233 if (clutter_actor_get_paint_opacity (self) < 255 &&
3234 clutter_actor_has_overlaps (self))
3242 add_or_remove_flatten_effect (ClutterActor *self)
3244 ClutterActorPrivate *priv = self->priv;
3246 /* Add or remove the flatten effect depending on the
3247 offscreen-redirect property. */
3248 if (needs_flatten_effect (self))
3250 if (priv->flatten_effect == NULL)
3252 ClutterActorMeta *actor_meta;
3255 priv->flatten_effect = _clutter_flatten_effect_new ();
3256 /* Keep a reference to the effect so that we can queue
3258 g_object_ref_sink (priv->flatten_effect);
3260 /* Set the priority of the effect to high so that it will
3261 always be applied to the actor first. It uses an internal
3262 priority so that it won't be visible to applications */
3263 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3264 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3265 _clutter_actor_meta_set_priority (actor_meta, priority);
3267 /* This will add the effect without queueing a redraw */
3268 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3273 if (priv->flatten_effect != NULL)
3275 /* Destroy the effect so that it will lose its fbo cache of
3277 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3278 g_clear_object (&priv->flatten_effect);
3284 clutter_actor_real_paint (ClutterActor *actor)
3286 ClutterActorPrivate *priv = actor->priv;
3289 for (iter = priv->first_child;
3291 iter = iter->priv->next_sibling)
3293 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3294 _clutter_actor_get_debug_name (iter),
3295 _clutter_actor_get_debug_name (actor),
3296 iter->priv->allocation.x1,
3297 iter->priv->allocation.y1,
3298 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3299 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3301 clutter_actor_paint (iter);
3306 clutter_actor_paint_node (ClutterActor *actor,
3307 ClutterPaintNode *root)
3309 ClutterActorPrivate *priv = actor->priv;
3314 if (priv->bg_color_set &&
3315 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3317 ClutterPaintNode *node;
3318 ClutterColor bg_color;
3319 ClutterActorBox box;
3323 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3324 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3326 bg_color = priv->bg_color;
3327 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3328 * priv->bg_color.alpha
3331 node = clutter_color_node_new (&bg_color);
3332 clutter_paint_node_set_name (node, "backgroundColor");
3333 clutter_paint_node_add_rectangle (node, &box);
3334 clutter_paint_node_add_child (root, node);
3335 clutter_paint_node_unref (node);
3338 if (priv->content != NULL)
3339 _clutter_content_paint_content (priv->content, actor, root);
3341 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3342 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3344 if (clutter_paint_node_get_n_children (root) == 0)
3347 #ifdef CLUTTER_ENABLE_DEBUG
3348 if (CLUTTER_HAS_DEBUG (PAINT))
3350 /* dump the tree only if we have one */
3351 _clutter_paint_node_dump_tree (root);
3353 #endif /* CLUTTER_ENABLE_DEBUG */
3355 _clutter_paint_node_paint (root);
3358 /* XXX: Uncomment this when we disable emitting the paint signal */
3359 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3366 * clutter_actor_paint:
3367 * @self: A #ClutterActor
3369 * Renders the actor to display.
3371 * This function should not be called directly by applications.
3372 * Call clutter_actor_queue_redraw() to queue paints, instead.
3374 * This function is context-aware, and will either cause a
3375 * regular paint or a pick paint.
3377 * This function will emit the #ClutterActor::paint signal or
3378 * the #ClutterActor::pick signal, depending on the context.
3380 * This function does not paint the actor if the actor is set to 0,
3381 * unless it is performing a pick paint.
3384 clutter_actor_paint (ClutterActor *self)
3386 ClutterActorPrivate *priv;
3387 ClutterPickMode pick_mode;
3388 gboolean clip_set = FALSE;
3389 gboolean shader_applied = FALSE;
3391 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3392 "Actor real-paint counter",
3393 "Increments each time any actor is painted",
3394 0 /* no application private data */);
3395 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3396 "Actor pick-paint counter",
3397 "Increments each time any actor is painted "
3399 0 /* no application private data */);
3401 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3403 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3408 pick_mode = _clutter_context_get_pick_mode ();
3410 if (pick_mode == CLUTTER_PICK_NONE)
3411 priv->propagated_one_redraw = FALSE;
3413 /* It's an important optimization that we consider painting of
3414 * actors with 0 opacity to be a NOP... */
3415 if (pick_mode == CLUTTER_PICK_NONE &&
3416 /* ignore top-levels, since they might be transparent */
3417 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3418 /* Use the override opacity if its been set */
3419 ((priv->opacity_override >= 0) ?
3420 priv->opacity_override : priv->opacity) == 0)
3423 /* if we aren't paintable (not in a toplevel with all
3424 * parents paintable) then do nothing.
3426 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3429 /* mark that we are in the paint process */
3430 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3434 if (priv->enable_model_view_transform)
3438 /* XXX: It could be better to cache the modelview with the actor
3439 * instead of progressively building up the transformations on
3440 * the matrix stack every time we paint. */
3441 cogl_get_modelview_matrix (&matrix);
3442 _clutter_actor_apply_modelview_transform (self, &matrix);
3444 #ifdef CLUTTER_ENABLE_DEBUG
3445 /* Catch when out-of-band transforms have been made by actors not as part
3446 * of an apply_transform vfunc... */
3447 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3449 CoglMatrix expected_matrix;
3451 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3454 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3456 GString *buf = g_string_sized_new (1024);
3457 ClutterActor *parent;
3460 while (parent != NULL)
3462 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3464 if (parent->priv->parent != NULL)
3465 g_string_append (buf, "->");
3467 parent = parent->priv->parent;
3470 g_warning ("Unexpected transform found when painting actor "
3471 "\"%s\". This will be caused by one of the actor's "
3472 "ancestors (%s) using the Cogl API directly to transform "
3473 "children instead of using ::apply_transform().",
3474 _clutter_actor_get_debug_name (self),
3477 g_string_free (buf, TRUE);
3480 #endif /* CLUTTER_ENABLE_DEBUG */
3482 cogl_set_modelview_matrix (&matrix);
3487 cogl_clip_push_rectangle (priv->clip.x,
3489 priv->clip.x + priv->clip.width,
3490 priv->clip.y + priv->clip.height);
3493 else if (priv->clip_to_allocation)
3495 gfloat width, height;
3497 width = priv->allocation.x2 - priv->allocation.x1;
3498 height = priv->allocation.y2 - priv->allocation.y1;
3500 cogl_clip_push_rectangle (0, 0, width, height);
3504 if (pick_mode == CLUTTER_PICK_NONE)
3506 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3508 /* We check whether we need to add the flatten effect before
3509 each paint so that we can avoid having a mechanism for
3510 applications to notify when the value of the
3511 has_overlaps virtual changes. */
3512 add_or_remove_flatten_effect (self);
3515 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3517 /* We save the current paint volume so that the next time the
3518 * actor queues a redraw we can constrain the redraw to just
3519 * cover the union of the new bounding box and the old.
3521 * We also fetch the current paint volume to perform culling so
3522 * we can avoid painting actors outside the current clip region.
3524 * If we are painting inside a clone, we should neither update
3525 * the paint volume or use it to cull painting, since the paint
3526 * box represents the location of the source actor on the
3529 * XXX: We are starting to do a lot of vertex transforms on
3530 * the CPU in a typical paint, so at some point we should
3531 * audit these and consider caching some things.
3533 * NB: We don't perform culling while picking at this point because
3534 * clutter-stage.c doesn't setup the clipping planes appropriately.
3536 * NB: We don't want to update the last-paint-volume during picking
3537 * because the last-paint-volume is used to determine the old screen
3538 * space location of an actor that has moved so we can know the
3539 * minimal region to redraw to clear an old view of the actor. If we
3540 * update this during picking then by the time we come around to
3541 * paint then the last-paint-volume would likely represent the new
3542 * actor position not the old.
3544 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3547 /* annoyingly gcc warns if uninitialized even though
3548 * the initialization is redundant :-( */
3549 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3551 if (G_LIKELY ((clutter_paint_debug_flags &
3552 (CLUTTER_DEBUG_DISABLE_CULLING |
3553 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3554 (CLUTTER_DEBUG_DISABLE_CULLING |
3555 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3556 _clutter_actor_update_last_paint_volume (self);
3558 success = cull_actor (self, &result);
3560 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3561 _clutter_actor_paint_cull_result (self, success, result);
3562 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3566 if (priv->effects == NULL)
3568 if (pick_mode == CLUTTER_PICK_NONE &&
3569 actor_has_shader_data (self))
3571 _clutter_actor_shader_pre_paint (self, FALSE);
3572 shader_applied = TRUE;
3575 priv->next_effect_to_paint = NULL;
3578 priv->next_effect_to_paint =
3579 _clutter_meta_group_peek_metas (priv->effects);
3581 clutter_actor_continue_paint (self);
3584 _clutter_actor_shader_post_paint (self);
3586 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3587 pick_mode == CLUTTER_PICK_NONE))
3588 _clutter_actor_draw_paint_volume (self);
3591 /* If we make it here then the actor has run through a complete
3592 paint run including all the effects so it's no longer dirty */
3593 if (pick_mode == CLUTTER_PICK_NONE)
3594 priv->is_dirty = FALSE;
3601 /* paint sequence complete */
3602 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3606 * clutter_actor_continue_paint:
3607 * @self: A #ClutterActor
3609 * Run the next stage of the paint sequence. This function should only
3610 * be called within the implementation of the ‘run’ virtual of a
3611 * #ClutterEffect. It will cause the run method of the next effect to
3612 * be applied, or it will paint the actual actor if the current effect
3613 * is the last effect in the chain.
3618 clutter_actor_continue_paint (ClutterActor *self)
3620 ClutterActorPrivate *priv;
3622 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3623 /* This should only be called from with in the ‘run’ implementation
3624 of a ClutterEffect */
3625 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3629 /* Skip any effects that are disabled */
3630 while (priv->next_effect_to_paint &&
3631 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3632 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3634 /* If this has come from the last effect then we'll just paint the
3636 if (priv->next_effect_to_paint == NULL)
3638 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3640 ClutterPaintNode *dummy;
3642 /* XXX - this will go away in 2.0, when we can get rid of this
3643 * stuff and switch to a pure retained render tree of PaintNodes
3644 * for the entire frame, starting from the Stage; the paint()
3645 * virtual function can then be called directly.
3647 dummy = _clutter_dummy_node_new (self);
3648 clutter_paint_node_set_name (dummy, "Root");
3650 /* XXX - for 1.12, we use the return value of paint_node() to
3651 * decide whether we should emit the ::paint signal.
3653 clutter_actor_paint_node (self, dummy);
3654 clutter_paint_node_unref (dummy);
3656 g_signal_emit (self, actor_signals[PAINT], 0);
3660 ClutterColor col = { 0, };
3662 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3664 /* Actor will then paint silhouette of itself in supplied
3665 * color. See clutter_stage_get_actor_at_pos() for where
3666 * picking is enabled.
3668 g_signal_emit (self, actor_signals[PICK], 0, &col);
3673 ClutterEffect *old_current_effect;
3674 ClutterEffectPaintFlags run_flags = 0;
3676 /* Cache the current effect so that we can put it back before
3678 old_current_effect = priv->current_effect;
3680 priv->current_effect = priv->next_effect_to_paint->data;
3681 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3683 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3687 /* If there's an effect queued with this redraw then all
3688 effects up to that one will be considered dirty. It
3689 is expected the queued effect will paint the cached
3690 image and not call clutter_actor_continue_paint again
3691 (although it should work ok if it does) */
3692 if (priv->effect_to_redraw == NULL ||
3693 priv->current_effect != priv->effect_to_redraw)
3694 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3697 _clutter_effect_paint (priv->current_effect, run_flags);
3701 /* We can't determine when an actor has been modified since
3702 its last pick so lets just assume it has always been
3704 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3706 _clutter_effect_pick (priv->current_effect, run_flags);
3709 priv->current_effect = old_current_effect;
3713 static ClutterActorTraverseVisitFlags
3714 invalidate_queue_redraw_entry (ClutterActor *self,
3718 ClutterActorPrivate *priv = self->priv;
3720 if (priv->queue_redraw_entry != NULL)
3722 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3723 priv->queue_redraw_entry = NULL;
3726 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3730 remove_child (ClutterActor *self,
3731 ClutterActor *child)
3733 ClutterActor *prev_sibling, *next_sibling;
3735 prev_sibling = child->priv->prev_sibling;
3736 next_sibling = child->priv->next_sibling;
3738 if (prev_sibling != NULL)
3739 prev_sibling->priv->next_sibling = next_sibling;
3741 if (next_sibling != NULL)
3742 next_sibling->priv->prev_sibling = prev_sibling;
3744 if (self->priv->first_child == child)
3745 self->priv->first_child = next_sibling;
3747 if (self->priv->last_child == child)
3748 self->priv->last_child = prev_sibling;
3750 child->priv->parent = NULL;
3751 child->priv->prev_sibling = NULL;
3752 child->priv->next_sibling = NULL;
3756 REMOVE_CHILD_DESTROY_META = 1 << 0,
3757 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3758 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3759 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3760 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3761 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3763 /* default flags for public API */
3764 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3765 REMOVE_CHILD_EMIT_PARENT_SET |
3766 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3767 REMOVE_CHILD_CHECK_STATE |
3768 REMOVE_CHILD_FLUSH_QUEUE |
3769 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3771 /* flags for legacy/deprecated API */
3772 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3773 REMOVE_CHILD_FLUSH_QUEUE |
3774 REMOVE_CHILD_EMIT_PARENT_SET |
3775 REMOVE_CHILD_NOTIFY_FIRST_LAST
3776 } ClutterActorRemoveChildFlags;
3779 * clutter_actor_remove_child_internal:
3780 * @self: a #ClutterActor
3781 * @child: the child of @self that has to be removed
3782 * @flags: control the removal operations
3784 * Removes @child from the list of children of @self.
3787 clutter_actor_remove_child_internal (ClutterActor *self,
3788 ClutterActor *child,
3789 ClutterActorRemoveChildFlags flags)
3791 ClutterActor *old_first, *old_last;
3792 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3793 gboolean flush_queue;
3794 gboolean notify_first_last;
3795 gboolean was_mapped;
3797 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3798 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3799 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3800 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3801 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3802 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3804 g_object_freeze_notify (G_OBJECT (self));
3807 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3811 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3813 /* we need to unrealize *before* we set parent_actor to NULL,
3814 * because in an unrealize method actors are dissociating from the
3815 * stage, which means they need to be able to
3816 * clutter_actor_get_stage().
3818 * yhis should unmap and unrealize, unless we're reparenting.
3820 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3827 /* We take this opportunity to invalidate any queue redraw entry
3828 * associated with the actor and descendants since we won't be able to
3829 * determine the appropriate stage after this.
3831 * we do this after we updated the mapped state because actors might
3832 * end up queueing redraws inside their mapped/unmapped virtual
3833 * functions, and if we invalidate the redraw entry we could end up
3834 * with an inconsistent state and weird memory corruption. see
3837 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3838 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3840 _clutter_actor_traverse (child,
3842 invalidate_queue_redraw_entry,
3847 old_first = self->priv->first_child;
3848 old_last = self->priv->last_child;
3850 remove_child (self, child);
3852 self->priv->n_children -= 1;
3854 self->priv->age += 1;
3856 /* clutter_actor_reparent() will emit ::parent-set for us */
3857 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3858 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3860 /* if the child was mapped then we need to relayout ourselves to account
3861 * for the removed child
3864 clutter_actor_queue_relayout (self);
3866 /* we need to emit the signal before dropping the reference */
3867 if (emit_actor_removed)
3868 g_signal_emit_by_name (self, "actor-removed", child);
3870 if (notify_first_last)
3872 if (old_first != self->priv->first_child)
3873 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3875 if (old_last != self->priv->last_child)
3876 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3879 g_object_thaw_notify (G_OBJECT (self));
3881 /* remove the reference we acquired in clutter_actor_add_child() */
3882 g_object_unref (child);
3885 static const ClutterTransformInfo default_transform_info = {
3886 0.0, { 0, }, /* rotation-x */
3887 0.0, { 0, }, /* rotation-y */
3888 0.0, { 0, }, /* rotation-z */
3890 1.0, 1.0, { 0, }, /* scale */
3892 { 0, }, /* anchor */
3898 * _clutter_actor_get_transform_info_or_defaults:
3899 * @self: a #ClutterActor
3901 * Retrieves the ClutterTransformInfo structure associated to an actor.
3903 * If the actor does not have a ClutterTransformInfo structure associated
3904 * to it, then the default structure will be returned.
3906 * This function should only be used for getters.
3908 * Return value: a const pointer to the ClutterTransformInfo structure
3910 const ClutterTransformInfo *
3911 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3913 ClutterTransformInfo *info;
3915 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3919 return &default_transform_info;
3923 clutter_transform_info_free (gpointer data)
3926 g_slice_free (ClutterTransformInfo, data);
3930 * _clutter_actor_get_transform_info:
3931 * @self: a #ClutterActor
3933 * Retrieves a pointer to the ClutterTransformInfo structure.
3935 * If the actor does not have a ClutterTransformInfo associated to it, one
3936 * will be created and initialized to the default values.
3938 * This function should be used for setters.
3940 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3943 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3946 ClutterTransformInfo *
3947 _clutter_actor_get_transform_info (ClutterActor *self)
3949 ClutterTransformInfo *info;
3951 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3954 info = g_slice_new (ClutterTransformInfo);
3956 *info = default_transform_info;
3958 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3960 clutter_transform_info_free);
3967 * clutter_actor_set_rotation_angle_internal:
3968 * @self: a #ClutterActor
3969 * @axis: the axis of the angle to change
3970 * @angle: the angle of rotation
3972 * Sets the rotation angle on the given axis without affecting the
3973 * rotation center point.
3976 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3977 ClutterRotateAxis axis,
3980 GObject *obj = G_OBJECT (self);
3981 ClutterTransformInfo *info;
3983 info = _clutter_actor_get_transform_info (self);
3985 g_object_freeze_notify (obj);
3989 case CLUTTER_X_AXIS:
3990 info->rx_angle = angle;
3991 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3994 case CLUTTER_Y_AXIS:
3995 info->ry_angle = angle;
3996 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3999 case CLUTTER_Z_AXIS:
4000 info->rz_angle = angle;
4001 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4005 self->priv->transform_valid = FALSE;
4007 g_object_thaw_notify (obj);
4009 clutter_actor_queue_redraw (self);
4013 clutter_actor_set_rotation_angle (ClutterActor *self,
4014 ClutterRotateAxis axis,
4017 ClutterTransformInfo *info;
4019 info = _clutter_actor_get_transform_info (self);
4021 if (clutter_actor_get_easing_duration (self) != 0)
4023 ClutterTransition *transition;
4024 GParamSpec *pspec = NULL;
4025 double *cur_angle_p = NULL;
4029 case CLUTTER_X_AXIS:
4030 cur_angle_p = &info->rx_angle;
4031 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4034 case CLUTTER_Y_AXIS:
4035 cur_angle_p = &info->ry_angle;
4036 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4039 case CLUTTER_Z_AXIS:
4040 cur_angle_p = &info->rz_angle;
4041 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4045 g_assert (pspec != NULL);
4046 g_assert (cur_angle_p != NULL);
4048 transition = _clutter_actor_get_transition (self, pspec);
4049 if (transition == NULL)
4051 transition = _clutter_actor_create_transition (self, pspec,
4056 _clutter_actor_update_transition (self, pspec, angle);
4058 self->priv->transform_valid = FALSE;
4059 clutter_actor_queue_redraw (self);
4062 clutter_actor_set_rotation_angle_internal (self, axis, angle);
4066 * clutter_actor_set_rotation_center_internal:
4067 * @self: a #ClutterActor
4068 * @axis: the axis of the center to change
4069 * @center: the coordinates of the rotation center
4071 * Sets the rotation center on the given axis without affecting the
4075 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4076 ClutterRotateAxis axis,
4077 const ClutterVertex *center)
4079 GObject *obj = G_OBJECT (self);
4080 ClutterTransformInfo *info;
4081 ClutterVertex v = { 0, 0, 0 };
4083 info = _clutter_actor_get_transform_info (self);
4088 g_object_freeze_notify (obj);
4092 case CLUTTER_X_AXIS:
4093 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4094 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4097 case CLUTTER_Y_AXIS:
4098 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4099 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4102 case CLUTTER_Z_AXIS:
4103 /* if the previously set rotation center was fractional, then
4104 * setting explicit coordinates will have to notify the
4105 * :rotation-center-z-gravity property as well
4107 if (info->rz_center.is_fractional)
4108 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4110 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4111 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4115 self->priv->transform_valid = FALSE;
4117 g_object_thaw_notify (obj);
4119 clutter_actor_queue_redraw (self);
4123 clutter_actor_animate_scale_factor (ClutterActor *self,
4128 ClutterTransition *transition;
4130 transition = _clutter_actor_get_transition (self, pspec);
4131 if (transition == NULL)
4133 transition = _clutter_actor_create_transition (self, pspec,
4138 _clutter_actor_update_transition (self, pspec, new_factor);
4141 self->priv->transform_valid = FALSE;
4142 clutter_actor_queue_redraw (self);
4146 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4150 GObject *obj = G_OBJECT (self);
4151 ClutterTransformInfo *info;
4153 info = _clutter_actor_get_transform_info (self);
4155 if (pspec == obj_props[PROP_SCALE_X])
4156 info->scale_x = factor;
4158 info->scale_y = factor;
4160 self->priv->transform_valid = FALSE;
4161 clutter_actor_queue_redraw (self);
4162 g_object_notify_by_pspec (obj, pspec);
4166 clutter_actor_set_scale_factor (ClutterActor *self,
4167 ClutterRotateAxis axis,
4170 GObject *obj = G_OBJECT (self);
4171 ClutterTransformInfo *info;
4174 info = _clutter_actor_get_transform_info (self);
4176 g_object_freeze_notify (obj);
4180 case CLUTTER_X_AXIS:
4181 pspec = obj_props[PROP_SCALE_X];
4183 if (clutter_actor_get_easing_duration (self) != 0)
4184 clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4186 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4189 case CLUTTER_Y_AXIS:
4190 pspec = obj_props[PROP_SCALE_Y];
4192 if (clutter_actor_get_easing_duration (self) != 0)
4193 clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4195 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4199 g_assert_not_reached ();
4202 g_object_thaw_notify (obj);
4206 clutter_actor_set_scale_center (ClutterActor *self,
4207 ClutterRotateAxis axis,
4210 GObject *obj = G_OBJECT (self);
4211 ClutterTransformInfo *info;
4212 gfloat center_x, center_y;
4214 info = _clutter_actor_get_transform_info (self);
4216 g_object_freeze_notify (obj);
4218 /* get the current scale center coordinates */
4219 clutter_anchor_coord_get_units (self, &info->scale_center,
4224 /* we need to notify this too, because setting explicit coordinates will
4225 * change the gravity as a side effect
4227 if (info->scale_center.is_fractional)
4228 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4232 case CLUTTER_X_AXIS:
4233 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4234 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4237 case CLUTTER_Y_AXIS:
4238 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4239 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4243 g_assert_not_reached ();
4246 self->priv->transform_valid = FALSE;
4248 clutter_actor_queue_redraw (self);
4250 g_object_thaw_notify (obj);
4254 clutter_actor_set_scale_gravity (ClutterActor *self,
4255 ClutterGravity gravity)
4257 ClutterTransformInfo *info;
4260 info = _clutter_actor_get_transform_info (self);
4261 obj = G_OBJECT (self);
4263 if (gravity == CLUTTER_GRAVITY_NONE)
4264 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4266 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4268 self->priv->transform_valid = FALSE;
4270 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4271 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4272 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4274 clutter_actor_queue_redraw (self);
4278 clutter_actor_set_anchor_coord (ClutterActor *self,
4279 ClutterRotateAxis axis,
4282 GObject *obj = G_OBJECT (self);
4283 ClutterTransformInfo *info;
4284 gfloat anchor_x, anchor_y;
4286 info = _clutter_actor_get_transform_info (self);
4288 g_object_freeze_notify (obj);
4290 clutter_anchor_coord_get_units (self, &info->anchor,
4295 if (info->anchor.is_fractional)
4296 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4300 case CLUTTER_X_AXIS:
4301 clutter_anchor_coord_set_units (&info->anchor,
4305 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4308 case CLUTTER_Y_AXIS:
4309 clutter_anchor_coord_set_units (&info->anchor,
4313 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4317 g_assert_not_reached ();
4320 self->priv->transform_valid = FALSE;
4322 clutter_actor_queue_redraw (self);
4324 g_object_thaw_notify (obj);
4328 clutter_actor_set_property (GObject *object,
4330 const GValue *value,
4333 ClutterActor *actor = CLUTTER_ACTOR (object);
4334 ClutterActorPrivate *priv = actor->priv;
4339 clutter_actor_set_x (actor, g_value_get_float (value));
4343 clutter_actor_set_y (actor, g_value_get_float (value));
4347 clutter_actor_set_width (actor, g_value_get_float (value));
4351 clutter_actor_set_height (actor, g_value_get_float (value));
4355 clutter_actor_set_x (actor, g_value_get_float (value));
4359 clutter_actor_set_y (actor, g_value_get_float (value));
4362 case PROP_FIXED_POSITION_SET:
4363 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4366 case PROP_MIN_WIDTH:
4367 clutter_actor_set_min_width (actor, g_value_get_float (value));
4370 case PROP_MIN_HEIGHT:
4371 clutter_actor_set_min_height (actor, g_value_get_float (value));
4374 case PROP_NATURAL_WIDTH:
4375 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4378 case PROP_NATURAL_HEIGHT:
4379 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4382 case PROP_MIN_WIDTH_SET:
4383 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4386 case PROP_MIN_HEIGHT_SET:
4387 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4390 case PROP_NATURAL_WIDTH_SET:
4391 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4394 case PROP_NATURAL_HEIGHT_SET:
4395 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4398 case PROP_REQUEST_MODE:
4399 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4403 clutter_actor_set_depth (actor, g_value_get_float (value));
4407 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4410 case PROP_OFFSCREEN_REDIRECT:
4411 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4415 clutter_actor_set_name (actor, g_value_get_string (value));
4419 if (g_value_get_boolean (value) == TRUE)
4420 clutter_actor_show (actor);
4422 clutter_actor_hide (actor);
4426 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4427 g_value_get_double (value));
4431 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4432 g_value_get_double (value));
4435 case PROP_SCALE_CENTER_X:
4436 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4437 g_value_get_float (value));
4440 case PROP_SCALE_CENTER_Y:
4441 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4442 g_value_get_float (value));
4445 case PROP_SCALE_GRAVITY:
4446 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4451 const ClutterGeometry *geom = g_value_get_boxed (value);
4453 clutter_actor_set_clip (actor,
4455 geom->width, geom->height);
4459 case PROP_CLIP_TO_ALLOCATION:
4460 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4464 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4467 case PROP_ROTATION_ANGLE_X:
4468 clutter_actor_set_rotation_angle (actor,
4470 g_value_get_double (value));
4473 case PROP_ROTATION_ANGLE_Y:
4474 clutter_actor_set_rotation_angle (actor,
4476 g_value_get_double (value));
4479 case PROP_ROTATION_ANGLE_Z:
4480 clutter_actor_set_rotation_angle (actor,
4482 g_value_get_double (value));
4485 case PROP_ROTATION_CENTER_X:
4486 clutter_actor_set_rotation_center_internal (actor,
4488 g_value_get_boxed (value));
4491 case PROP_ROTATION_CENTER_Y:
4492 clutter_actor_set_rotation_center_internal (actor,
4494 g_value_get_boxed (value));
4497 case PROP_ROTATION_CENTER_Z:
4498 clutter_actor_set_rotation_center_internal (actor,
4500 g_value_get_boxed (value));
4503 case PROP_ROTATION_CENTER_Z_GRAVITY:
4505 const ClutterTransformInfo *info;
4507 info = _clutter_actor_get_transform_info_or_defaults (actor);
4508 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4509 g_value_get_enum (value));
4514 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4515 g_value_get_float (value));
4519 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4520 g_value_get_float (value));
4523 case PROP_ANCHOR_GRAVITY:
4524 clutter_actor_set_anchor_point_from_gravity (actor,
4525 g_value_get_enum (value));
4528 case PROP_SHOW_ON_SET_PARENT:
4529 priv->show_on_set_parent = g_value_get_boolean (value);
4532 case PROP_TEXT_DIRECTION:
4533 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4537 clutter_actor_add_action (actor, g_value_get_object (value));
4540 case PROP_CONSTRAINTS:
4541 clutter_actor_add_constraint (actor, g_value_get_object (value));
4545 clutter_actor_add_effect (actor, g_value_get_object (value));
4548 case PROP_LAYOUT_MANAGER:
4549 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4553 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4557 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4560 case PROP_MARGIN_TOP:
4561 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4564 case PROP_MARGIN_BOTTOM:
4565 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4568 case PROP_MARGIN_LEFT:
4569 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4572 case PROP_MARGIN_RIGHT:
4573 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4576 case PROP_BACKGROUND_COLOR:
4577 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4581 clutter_actor_set_content (actor, g_value_get_object (value));
4584 case PROP_CONTENT_GRAVITY:
4585 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4588 case PROP_MINIFICATION_FILTER:
4589 clutter_actor_set_content_scaling_filters (actor,
4590 g_value_get_enum (value),
4591 actor->priv->mag_filter);
4594 case PROP_MAGNIFICATION_FILTER:
4595 clutter_actor_set_content_scaling_filters (actor,
4596 actor->priv->min_filter,
4597 g_value_get_enum (value));
4601 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4607 clutter_actor_get_property (GObject *object,
4612 ClutterActor *actor = CLUTTER_ACTOR (object);
4613 ClutterActorPrivate *priv = actor->priv;
4618 g_value_set_float (value, clutter_actor_get_x (actor));
4622 g_value_set_float (value, clutter_actor_get_y (actor));
4626 g_value_set_float (value, clutter_actor_get_width (actor));
4630 g_value_set_float (value, clutter_actor_get_height (actor));
4635 const ClutterLayoutInfo *info;
4637 info = _clutter_actor_get_layout_info_or_defaults (actor);
4638 g_value_set_float (value, info->fixed_x);
4644 const ClutterLayoutInfo *info;
4646 info = _clutter_actor_get_layout_info_or_defaults (actor);
4647 g_value_set_float (value, info->fixed_y);
4651 case PROP_FIXED_POSITION_SET:
4652 g_value_set_boolean (value, priv->position_set);
4655 case PROP_MIN_WIDTH:
4657 const ClutterLayoutInfo *info;
4659 info = _clutter_actor_get_layout_info_or_defaults (actor);
4660 g_value_set_float (value, info->min_width);
4664 case PROP_MIN_HEIGHT:
4666 const ClutterLayoutInfo *info;
4668 info = _clutter_actor_get_layout_info_or_defaults (actor);
4669 g_value_set_float (value, info->min_height);
4673 case PROP_NATURAL_WIDTH:
4675 const ClutterLayoutInfo *info;
4677 info = _clutter_actor_get_layout_info_or_defaults (actor);
4678 g_value_set_float (value, info->natural_width);
4682 case PROP_NATURAL_HEIGHT:
4684 const ClutterLayoutInfo *info;
4686 info = _clutter_actor_get_layout_info_or_defaults (actor);
4687 g_value_set_float (value, info->natural_height);
4691 case PROP_MIN_WIDTH_SET:
4692 g_value_set_boolean (value, priv->min_width_set);
4695 case PROP_MIN_HEIGHT_SET:
4696 g_value_set_boolean (value, priv->min_height_set);
4699 case PROP_NATURAL_WIDTH_SET:
4700 g_value_set_boolean (value, priv->natural_width_set);
4703 case PROP_NATURAL_HEIGHT_SET:
4704 g_value_set_boolean (value, priv->natural_height_set);
4707 case PROP_REQUEST_MODE:
4708 g_value_set_enum (value, priv->request_mode);
4711 case PROP_ALLOCATION:
4712 g_value_set_boxed (value, &priv->allocation);
4716 g_value_set_float (value, clutter_actor_get_depth (actor));
4720 g_value_set_uint (value, priv->opacity);
4723 case PROP_OFFSCREEN_REDIRECT:
4724 g_value_set_enum (value, priv->offscreen_redirect);
4728 g_value_set_string (value, priv->name);
4732 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4736 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4740 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4744 g_value_set_boolean (value, priv->has_clip);
4749 ClutterGeometry clip;
4751 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4752 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4753 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4754 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4756 g_value_set_boxed (value, &clip);
4760 case PROP_CLIP_TO_ALLOCATION:
4761 g_value_set_boolean (value, priv->clip_to_allocation);
4766 const ClutterTransformInfo *info;
4768 info = _clutter_actor_get_transform_info_or_defaults (actor);
4769 g_value_set_double (value, info->scale_x);
4775 const ClutterTransformInfo *info;
4777 info = _clutter_actor_get_transform_info_or_defaults (actor);
4778 g_value_set_double (value, info->scale_y);
4782 case PROP_SCALE_CENTER_X:
4786 clutter_actor_get_scale_center (actor, ¢er, NULL);
4788 g_value_set_float (value, center);
4792 case PROP_SCALE_CENTER_Y:
4796 clutter_actor_get_scale_center (actor, NULL, ¢er);
4798 g_value_set_float (value, center);
4802 case PROP_SCALE_GRAVITY:
4803 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4807 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4810 case PROP_ROTATION_ANGLE_X:
4812 const ClutterTransformInfo *info;
4814 info = _clutter_actor_get_transform_info_or_defaults (actor);
4815 g_value_set_double (value, info->rx_angle);
4819 case PROP_ROTATION_ANGLE_Y:
4821 const ClutterTransformInfo *info;
4823 info = _clutter_actor_get_transform_info_or_defaults (actor);
4824 g_value_set_double (value, info->ry_angle);
4828 case PROP_ROTATION_ANGLE_Z:
4830 const ClutterTransformInfo *info;
4832 info = _clutter_actor_get_transform_info_or_defaults (actor);
4833 g_value_set_double (value, info->rz_angle);
4837 case PROP_ROTATION_CENTER_X:
4839 ClutterVertex center;
4841 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4846 g_value_set_boxed (value, ¢er);
4850 case PROP_ROTATION_CENTER_Y:
4852 ClutterVertex center;
4854 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4859 g_value_set_boxed (value, ¢er);
4863 case PROP_ROTATION_CENTER_Z:
4865 ClutterVertex center;
4867 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4872 g_value_set_boxed (value, ¢er);
4876 case PROP_ROTATION_CENTER_Z_GRAVITY:
4877 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4882 const ClutterTransformInfo *info;
4885 info = _clutter_actor_get_transform_info_or_defaults (actor);
4886 clutter_anchor_coord_get_units (actor, &info->anchor,
4890 g_value_set_float (value, anchor_x);
4896 const ClutterTransformInfo *info;
4899 info = _clutter_actor_get_transform_info_or_defaults (actor);
4900 clutter_anchor_coord_get_units (actor, &info->anchor,
4904 g_value_set_float (value, anchor_y);
4908 case PROP_ANCHOR_GRAVITY:
4909 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4912 case PROP_SHOW_ON_SET_PARENT:
4913 g_value_set_boolean (value, priv->show_on_set_parent);
4916 case PROP_TEXT_DIRECTION:
4917 g_value_set_enum (value, priv->text_direction);
4920 case PROP_HAS_POINTER:
4921 g_value_set_boolean (value, priv->has_pointer);
4924 case PROP_LAYOUT_MANAGER:
4925 g_value_set_object (value, priv->layout_manager);
4930 const ClutterLayoutInfo *info;
4932 info = _clutter_actor_get_layout_info_or_defaults (actor);
4933 g_value_set_enum (value, info->x_align);
4939 const ClutterLayoutInfo *info;
4941 info = _clutter_actor_get_layout_info_or_defaults (actor);
4942 g_value_set_enum (value, info->y_align);
4946 case PROP_MARGIN_TOP:
4948 const ClutterLayoutInfo *info;
4950 info = _clutter_actor_get_layout_info_or_defaults (actor);
4951 g_value_set_float (value, info->margin.top);
4955 case PROP_MARGIN_BOTTOM:
4957 const ClutterLayoutInfo *info;
4959 info = _clutter_actor_get_layout_info_or_defaults (actor);
4960 g_value_set_float (value, info->margin.bottom);
4964 case PROP_MARGIN_LEFT:
4966 const ClutterLayoutInfo *info;
4968 info = _clutter_actor_get_layout_info_or_defaults (actor);
4969 g_value_set_float (value, info->margin.left);
4973 case PROP_MARGIN_RIGHT:
4975 const ClutterLayoutInfo *info;
4977 info = _clutter_actor_get_layout_info_or_defaults (actor);
4978 g_value_set_float (value, info->margin.right);
4982 case PROP_BACKGROUND_COLOR_SET:
4983 g_value_set_boolean (value, priv->bg_color_set);
4986 case PROP_BACKGROUND_COLOR:
4987 g_value_set_boxed (value, &priv->bg_color);
4990 case PROP_FIRST_CHILD:
4991 g_value_set_object (value, priv->first_child);
4994 case PROP_LAST_CHILD:
4995 g_value_set_object (value, priv->last_child);
4999 g_value_set_object (value, priv->content);
5002 case PROP_CONTENT_GRAVITY:
5003 g_value_set_enum (value, priv->content_gravity);
5006 case PROP_CONTENT_BOX:
5008 ClutterActorBox box = { 0, };
5010 clutter_actor_get_content_box (actor, &box);
5011 g_value_set_boxed (value, &box);
5015 case PROP_MINIFICATION_FILTER:
5016 g_value_set_enum (value, priv->min_filter);
5019 case PROP_MAGNIFICATION_FILTER:
5020 g_value_set_enum (value, priv->mag_filter);
5024 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5030 clutter_actor_dispose (GObject *object)
5032 ClutterActor *self = CLUTTER_ACTOR (object);
5033 ClutterActorPrivate *priv = self->priv;
5035 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5037 g_type_name (G_OBJECT_TYPE (self)),
5040 g_signal_emit (self, actor_signals[DESTROY], 0);
5042 /* avoid recursing when called from clutter_actor_destroy() */
5043 if (priv->parent != NULL)
5045 ClutterActor *parent = priv->parent;
5047 /* go through the Container implementation unless this
5048 * is an internal child and has been marked as such.
5050 * removing the actor from its parent will reset the
5051 * realized and mapped states.
5053 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5054 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5056 clutter_actor_remove_child_internal (parent, self,
5057 REMOVE_CHILD_LEGACY_FLAGS);
5060 /* parent must be gone at this point */
5061 g_assert (priv->parent == NULL);
5063 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5065 /* can't be mapped or realized with no parent */
5066 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5067 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5070 g_clear_object (&priv->pango_context);
5071 g_clear_object (&priv->actions);
5072 g_clear_object (&priv->constraints);
5073 g_clear_object (&priv->effects);
5074 g_clear_object (&priv->flatten_effect);
5076 if (priv->layout_manager != NULL)
5078 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5079 g_clear_object (&priv->layout_manager);
5082 if (priv->content != NULL)
5084 _clutter_content_detached (priv->content, self);
5085 g_clear_object (&priv->content);
5088 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5092 clutter_actor_finalize (GObject *object)
5094 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5096 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5097 priv->name != NULL ? priv->name : "<none>",
5099 g_type_name (G_OBJECT_TYPE (object)));
5101 _clutter_context_release_id (priv->id);
5103 g_free (priv->name);
5105 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5110 * clutter_actor_get_accessible:
5111 * @self: a #ClutterActor
5113 * Returns the accessible object that describes the actor to an
5114 * assistive technology.
5116 * If no class-specific #AtkObject implementation is available for the
5117 * actor instance in question, it will inherit an #AtkObject
5118 * implementation from the first ancestor class for which such an
5119 * implementation is defined.
5121 * The documentation of the <ulink
5122 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5123 * library contains more information about accessible objects and
5126 * Returns: (transfer none): the #AtkObject associated with @actor
5129 clutter_actor_get_accessible (ClutterActor *self)
5131 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5133 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5137 clutter_actor_real_get_accessible (ClutterActor *actor)
5139 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5143 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5145 AtkObject *accessible;
5147 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5148 if (accessible != NULL)
5149 g_object_ref (accessible);
5155 atk_implementor_iface_init (AtkImplementorIface *iface)
5157 iface->ref_accessible = _clutter_actor_ref_accessible;
5161 clutter_actor_update_default_paint_volume (ClutterActor *self,
5162 ClutterPaintVolume *volume)
5164 ClutterActorPrivate *priv = self->priv;
5165 gboolean res = FALSE;
5167 /* we start from the allocation */
5168 clutter_paint_volume_set_width (volume,
5169 priv->allocation.x2 - priv->allocation.x1);
5170 clutter_paint_volume_set_height (volume,
5171 priv->allocation.y2 - priv->allocation.y1);
5173 /* if the actor has a clip set then we have a pretty definite
5174 * size for the paint volume: the actor cannot possibly paint
5175 * outside the clip region.
5177 if (priv->clip_to_allocation)
5179 /* the allocation has already been set, so we just flip the
5186 ClutterActor *child;
5188 if (priv->has_clip &&
5189 priv->clip.width >= 0 &&
5190 priv->clip.height >= 0)
5192 ClutterVertex origin;
5194 origin.x = priv->clip.x;
5195 origin.y = priv->clip.y;
5198 clutter_paint_volume_set_origin (volume, &origin);
5199 clutter_paint_volume_set_width (volume, priv->clip.width);
5200 clutter_paint_volume_set_height (volume, priv->clip.height);
5205 /* if we don't have children we just bail out here... */
5206 if (priv->n_children == 0)
5209 /* ...but if we have children then we ask for their paint volume in
5210 * our coordinates. if any of our children replies that it doesn't
5211 * have a paint volume, we bail out
5213 for (child = priv->first_child;
5215 child = child->priv->next_sibling)
5217 const ClutterPaintVolume *child_volume;
5219 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5220 if (child_volume == NULL)
5226 clutter_paint_volume_union (volume, child_volume);
5236 clutter_actor_real_get_paint_volume (ClutterActor *self,
5237 ClutterPaintVolume *volume)
5239 ClutterActorClass *klass;
5242 klass = CLUTTER_ACTOR_GET_CLASS (self);
5244 /* XXX - this thoroughly sucks, but we don't want to penalize users
5245 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5246 * redraw. This should go away in 2.0.
5248 if (klass->paint == clutter_actor_real_paint &&
5249 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5255 /* this is the default return value: we cannot know if a class
5256 * is going to paint outside its allocation, so we take the
5257 * conservative approach.
5262 if (clutter_actor_update_default_paint_volume (self, volume))
5269 * clutter_actor_get_default_paint_volume:
5270 * @self: a #ClutterActor
5272 * Retrieves the default paint volume for @self.
5274 * This function provides the same #ClutterPaintVolume that would be
5275 * computed by the default implementation inside #ClutterActor of the
5276 * #ClutterActorClass.get_paint_volume() virtual function.
5278 * This function should only be used by #ClutterActor subclasses that
5279 * cannot chain up to the parent implementation when computing their
5282 * Return value: (transfer none): a pointer to the default
5283 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5284 * the actor could not compute a valid paint volume. The returned value
5285 * is not guaranteed to be stable across multiple frames, so if you
5286 * want to retain it, you will need to copy it using
5287 * clutter_paint_volume_copy().
5291 const ClutterPaintVolume *
5292 clutter_actor_get_default_paint_volume (ClutterActor *self)
5294 ClutterPaintVolume volume;
5295 ClutterPaintVolume *res;
5297 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5300 _clutter_paint_volume_init_static (&volume, self);
5301 if (clutter_actor_update_default_paint_volume (self, &volume))
5303 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5307 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5308 _clutter_paint_volume_copy_static (&volume, res);
5312 clutter_paint_volume_free (&volume);
5318 clutter_actor_real_has_overlaps (ClutterActor *self)
5320 /* By default we'll assume that all actors need an offscreen redirect to get
5321 * the correct opacity. Actors such as ClutterTexture that would never need
5322 * an offscreen redirect can override this to return FALSE. */
5327 clutter_actor_real_destroy (ClutterActor *actor)
5329 ClutterActorIter iter;
5331 g_object_freeze_notify (G_OBJECT (actor));
5333 clutter_actor_iter_init (&iter, actor);
5334 while (clutter_actor_iter_next (&iter, NULL))
5335 clutter_actor_iter_destroy (&iter);
5337 g_object_thaw_notify (G_OBJECT (actor));
5341 clutter_actor_constructor (GType gtype,
5343 GObjectConstructParam *props)
5345 GObjectClass *gobject_class;
5349 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5350 retval = gobject_class->constructor (gtype, n_props, props);
5351 self = CLUTTER_ACTOR (retval);
5353 if (self->priv->layout_manager == NULL)
5355 ClutterLayoutManager *default_layout;
5357 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5359 default_layout = clutter_fixed_layout_new ();
5360 clutter_actor_set_layout_manager (self, default_layout);
5367 clutter_actor_class_init (ClutterActorClass *klass)
5369 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5371 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5372 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5373 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5374 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5376 object_class->constructor = clutter_actor_constructor;
5377 object_class->set_property = clutter_actor_set_property;
5378 object_class->get_property = clutter_actor_get_property;
5379 object_class->dispose = clutter_actor_dispose;
5380 object_class->finalize = clutter_actor_finalize;
5382 klass->show = clutter_actor_real_show;
5383 klass->show_all = clutter_actor_show;
5384 klass->hide = clutter_actor_real_hide;
5385 klass->hide_all = clutter_actor_hide;
5386 klass->map = clutter_actor_real_map;
5387 klass->unmap = clutter_actor_real_unmap;
5388 klass->unrealize = clutter_actor_real_unrealize;
5389 klass->pick = clutter_actor_real_pick;
5390 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5391 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5392 klass->allocate = clutter_actor_real_allocate;
5393 klass->queue_redraw = clutter_actor_real_queue_redraw;
5394 klass->queue_relayout = clutter_actor_real_queue_relayout;
5395 klass->apply_transform = clutter_actor_real_apply_transform;
5396 klass->get_accessible = clutter_actor_real_get_accessible;
5397 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5398 klass->has_overlaps = clutter_actor_real_has_overlaps;
5399 klass->paint = clutter_actor_real_paint;
5400 klass->destroy = clutter_actor_real_destroy;
5402 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5407 * X coordinate of the actor in pixels. If written, forces a fixed
5408 * position for the actor. If read, returns the fixed position if any,
5409 * otherwise the allocation if available, otherwise 0.
5411 * The #ClutterActor:x property is animatable.
5414 g_param_spec_float ("x",
5416 P_("X coordinate of the actor"),
5417 -G_MAXFLOAT, G_MAXFLOAT,
5420 G_PARAM_STATIC_STRINGS |
5421 CLUTTER_PARAM_ANIMATABLE);
5426 * Y coordinate of the actor in pixels. If written, forces a fixed
5427 * position for the actor. If read, returns the fixed position if
5428 * any, otherwise the allocation if available, otherwise 0.
5430 * The #ClutterActor:y property is animatable.
5433 g_param_spec_float ("y",
5435 P_("Y coordinate of the actor"),
5436 -G_MAXFLOAT, G_MAXFLOAT,
5439 G_PARAM_STATIC_STRINGS |
5440 CLUTTER_PARAM_ANIMATABLE);
5443 * ClutterActor:width:
5445 * Width of the actor (in pixels). If written, forces the minimum and
5446 * natural size request of the actor to the given width. If read, returns
5447 * the allocated width if available, otherwise the width request.
5449 * The #ClutterActor:width property is animatable.
5451 obj_props[PROP_WIDTH] =
5452 g_param_spec_float ("width",
5454 P_("Width of the actor"),
5458 G_PARAM_STATIC_STRINGS |
5459 CLUTTER_PARAM_ANIMATABLE);
5462 * ClutterActor:height:
5464 * Height of the actor (in pixels). If written, forces the minimum and
5465 * natural size request of the actor to the given height. If read, returns
5466 * the allocated height if available, otherwise the height request.
5468 * The #ClutterActor:height property is animatable.
5470 obj_props[PROP_HEIGHT] =
5471 g_param_spec_float ("height",
5473 P_("Height of the actor"),
5477 G_PARAM_STATIC_STRINGS |
5478 CLUTTER_PARAM_ANIMATABLE);
5481 * ClutterActor:fixed-x:
5483 * The fixed X position of the actor in pixels.
5485 * Writing this property sets #ClutterActor:fixed-position-set
5486 * property as well, as a side effect
5490 obj_props[PROP_FIXED_X] =
5491 g_param_spec_float ("fixed-x",
5493 P_("Forced X position of the actor"),
5494 -G_MAXFLOAT, G_MAXFLOAT,
5496 CLUTTER_PARAM_READWRITE);
5499 * ClutterActor:fixed-y:
5501 * The fixed Y position of the actor in pixels.
5503 * Writing this property sets the #ClutterActor:fixed-position-set
5504 * property as well, as a side effect
5508 obj_props[PROP_FIXED_Y] =
5509 g_param_spec_float ("fixed-y",
5511 P_("Forced Y position of the actor"),
5512 -G_MAXFLOAT, G_MAXFLOAT,
5514 CLUTTER_PARAM_READWRITE);
5517 * ClutterActor:fixed-position-set:
5519 * This flag controls whether the #ClutterActor:fixed-x and
5520 * #ClutterActor:fixed-y properties are used
5524 obj_props[PROP_FIXED_POSITION_SET] =
5525 g_param_spec_boolean ("fixed-position-set",
5526 P_("Fixed position set"),
5527 P_("Whether to use fixed positioning for the actor"),
5529 CLUTTER_PARAM_READWRITE);
5532 * ClutterActor:min-width:
5534 * A forced minimum width request for the actor, in pixels
5536 * Writing this property sets the #ClutterActor:min-width-set property
5537 * as well, as a side effect.
5539 *This property overrides the usual width request of the actor.
5543 obj_props[PROP_MIN_WIDTH] =
5544 g_param_spec_float ("min-width",
5546 P_("Forced minimum width request for the actor"),
5549 CLUTTER_PARAM_READWRITE);
5552 * ClutterActor:min-height:
5554 * A forced minimum height request for the actor, in pixels
5556 * Writing this property sets the #ClutterActor:min-height-set property
5557 * as well, as a side effect. This property overrides the usual height
5558 * request of the actor.
5562 obj_props[PROP_MIN_HEIGHT] =
5563 g_param_spec_float ("min-height",
5565 P_("Forced minimum height request for the actor"),
5568 CLUTTER_PARAM_READWRITE);
5571 * ClutterActor:natural-width:
5573 * A forced natural width request for the actor, in pixels
5575 * Writing this property sets the #ClutterActor:natural-width-set
5576 * property as well, as a side effect. This property overrides the
5577 * usual width request of the actor
5581 obj_props[PROP_NATURAL_WIDTH] =
5582 g_param_spec_float ("natural-width",
5583 P_("Natural Width"),
5584 P_("Forced natural width request for the actor"),
5587 CLUTTER_PARAM_READWRITE);
5590 * ClutterActor:natural-height:
5592 * A forced natural height request for the actor, in pixels
5594 * Writing this property sets the #ClutterActor:natural-height-set
5595 * property as well, as a side effect. This property overrides the
5596 * usual height request of the actor
5600 obj_props[PROP_NATURAL_HEIGHT] =
5601 g_param_spec_float ("natural-height",
5602 P_("Natural Height"),
5603 P_("Forced natural height request for the actor"),
5606 CLUTTER_PARAM_READWRITE);
5609 * ClutterActor:min-width-set:
5611 * This flag controls whether the #ClutterActor:min-width property
5616 obj_props[PROP_MIN_WIDTH_SET] =
5617 g_param_spec_boolean ("min-width-set",
5618 P_("Minimum width set"),
5619 P_("Whether to use the min-width property"),
5621 CLUTTER_PARAM_READWRITE);
5624 * ClutterActor:min-height-set:
5626 * This flag controls whether the #ClutterActor:min-height property
5631 obj_props[PROP_MIN_HEIGHT_SET] =
5632 g_param_spec_boolean ("min-height-set",
5633 P_("Minimum height set"),
5634 P_("Whether to use the min-height property"),
5636 CLUTTER_PARAM_READWRITE);
5639 * ClutterActor:natural-width-set:
5641 * This flag controls whether the #ClutterActor:natural-width property
5646 obj_props[PROP_NATURAL_WIDTH_SET] =
5647 g_param_spec_boolean ("natural-width-set",
5648 P_("Natural width set"),
5649 P_("Whether to use the natural-width property"),
5651 CLUTTER_PARAM_READWRITE);
5654 * ClutterActor:natural-height-set:
5656 * This flag controls whether the #ClutterActor:natural-height property
5661 obj_props[PROP_NATURAL_HEIGHT_SET] =
5662 g_param_spec_boolean ("natural-height-set",
5663 P_("Natural height set"),
5664 P_("Whether to use the natural-height property"),
5666 CLUTTER_PARAM_READWRITE);
5669 * ClutterActor:allocation:
5671 * The allocation for the actor, in pixels
5673 * This is property is read-only, but you might monitor it to know when an
5674 * actor moves or resizes
5678 obj_props[PROP_ALLOCATION] =
5679 g_param_spec_boxed ("allocation",
5681 P_("The actor's allocation"),
5682 CLUTTER_TYPE_ACTOR_BOX,
5683 CLUTTER_PARAM_READABLE);
5686 * ClutterActor:request-mode:
5688 * Request mode for the #ClutterActor. The request mode determines the
5689 * type of geometry management used by the actor, either height for width
5690 * (the default) or width for height.
5692 * For actors implementing height for width, the parent container should get
5693 * the preferred width first, and then the preferred height for that width.
5695 * For actors implementing width for height, the parent container should get
5696 * the preferred height first, and then the preferred width for that height.
5701 * ClutterRequestMode mode;
5702 * gfloat natural_width, min_width;
5703 * gfloat natural_height, min_height;
5705 * mode = clutter_actor_get_request_mode (child);
5706 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5708 * clutter_actor_get_preferred_width (child, -1,
5710 * &natural_width);
5711 * clutter_actor_get_preferred_height (child, natural_width,
5713 * &natural_height);
5717 * clutter_actor_get_preferred_height (child, -1,
5719 * &natural_height);
5720 * clutter_actor_get_preferred_width (child, natural_height,
5722 * &natural_width);
5726 * will retrieve the minimum and natural width and height depending on the
5727 * preferred request mode of the #ClutterActor "child".
5729 * The clutter_actor_get_preferred_size() function will implement this
5734 obj_props[PROP_REQUEST_MODE] =
5735 g_param_spec_enum ("request-mode",
5737 P_("The actor's request mode"),
5738 CLUTTER_TYPE_REQUEST_MODE,
5739 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5740 CLUTTER_PARAM_READWRITE);
5743 * ClutterActor:depth:
5745 * The position of the actor on the Z axis.
5747 * The #ClutterActor:depth property is relative to the parent's
5750 * The #ClutterActor:depth property is animatable.
5754 obj_props[PROP_DEPTH] =
5755 g_param_spec_float ("depth",
5757 P_("Position on the Z axis"),
5758 -G_MAXFLOAT, G_MAXFLOAT,
5761 G_PARAM_STATIC_STRINGS |
5762 CLUTTER_PARAM_ANIMATABLE);
5765 * ClutterActor:opacity:
5767 * Opacity of an actor, between 0 (fully transparent) and
5768 * 255 (fully opaque)
5770 * The #ClutterActor:opacity property is animatable.
5772 obj_props[PROP_OPACITY] =
5773 g_param_spec_uint ("opacity",
5775 P_("Opacity of an actor"),
5779 G_PARAM_STATIC_STRINGS |
5780 CLUTTER_PARAM_ANIMATABLE);
5783 * ClutterActor:offscreen-redirect:
5785 * Determines the conditions in which the actor will be redirected
5786 * to an offscreen framebuffer while being painted. For example this
5787 * can be used to cache an actor in a framebuffer or for improved
5788 * handling of transparent actors. See
5789 * clutter_actor_set_offscreen_redirect() for details.
5793 obj_props[PROP_OFFSCREEN_REDIRECT] =
5794 g_param_spec_flags ("offscreen-redirect",
5795 P_("Offscreen redirect"),
5796 P_("Flags controlling when to flatten the actor into a single image"),
5797 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5799 CLUTTER_PARAM_READWRITE);
5802 * ClutterActor:visible:
5804 * Whether the actor is set to be visible or not
5806 * See also #ClutterActor:mapped
5808 obj_props[PROP_VISIBLE] =
5809 g_param_spec_boolean ("visible",
5811 P_("Whether the actor is visible or not"),
5813 CLUTTER_PARAM_READWRITE);
5816 * ClutterActor:mapped:
5818 * Whether the actor is mapped (will be painted when the stage
5819 * to which it belongs is mapped)
5823 obj_props[PROP_MAPPED] =
5824 g_param_spec_boolean ("mapped",
5826 P_("Whether the actor will be painted"),
5828 CLUTTER_PARAM_READABLE);
5831 * ClutterActor:realized:
5833 * Whether the actor has been realized
5837 obj_props[PROP_REALIZED] =
5838 g_param_spec_boolean ("realized",
5840 P_("Whether the actor has been realized"),
5842 CLUTTER_PARAM_READABLE);
5845 * ClutterActor:reactive:
5847 * Whether the actor is reactive to events or not
5849 * Only reactive actors will emit event-related signals
5853 obj_props[PROP_REACTIVE] =
5854 g_param_spec_boolean ("reactive",
5856 P_("Whether the actor is reactive to events"),
5858 CLUTTER_PARAM_READWRITE);
5861 * ClutterActor:has-clip:
5863 * Whether the actor has the #ClutterActor:clip property set or not
5865 obj_props[PROP_HAS_CLIP] =
5866 g_param_spec_boolean ("has-clip",
5868 P_("Whether the actor has a clip set"),
5870 CLUTTER_PARAM_READABLE);
5873 * ClutterActor:clip:
5875 * The clip region for the actor, in actor-relative coordinates
5877 * Every part of the actor outside the clip region will not be
5880 obj_props[PROP_CLIP] =
5881 g_param_spec_boxed ("clip",
5883 P_("The clip region for the actor"),
5884 CLUTTER_TYPE_GEOMETRY,
5885 CLUTTER_PARAM_READWRITE);
5888 * ClutterActor:name:
5890 * The name of the actor
5894 obj_props[PROP_NAME] =
5895 g_param_spec_string ("name",
5897 P_("Name of the actor"),
5899 CLUTTER_PARAM_READWRITE);
5902 * ClutterActor:scale-x:
5904 * The horizontal scale of the actor.
5906 * The #ClutterActor:scale-x property is animatable.
5910 obj_props[PROP_SCALE_X] =
5911 g_param_spec_double ("scale-x",
5913 P_("Scale factor on the X axis"),
5917 G_PARAM_STATIC_STRINGS |
5918 CLUTTER_PARAM_ANIMATABLE);
5921 * ClutterActor:scale-y:
5923 * The vertical scale of the actor.
5925 * The #ClutterActor:scale-y property is animatable.
5929 obj_props[PROP_SCALE_Y] =
5930 g_param_spec_double ("scale-y",
5932 P_("Scale factor on the Y axis"),
5936 G_PARAM_STATIC_STRINGS |
5937 CLUTTER_PARAM_ANIMATABLE);
5940 * ClutterActor:scale-center-x:
5942 * The horizontal center point for scaling
5946 obj_props[PROP_SCALE_CENTER_X] =
5947 g_param_spec_float ("scale-center-x",
5948 P_("Scale Center X"),
5949 P_("Horizontal scale center"),
5950 -G_MAXFLOAT, G_MAXFLOAT,
5952 CLUTTER_PARAM_READWRITE);
5955 * ClutterActor:scale-center-y:
5957 * The vertical center point for scaling
5961 obj_props[PROP_SCALE_CENTER_Y] =
5962 g_param_spec_float ("scale-center-y",
5963 P_("Scale Center Y"),
5964 P_("Vertical scale center"),
5965 -G_MAXFLOAT, G_MAXFLOAT,
5967 CLUTTER_PARAM_READWRITE);
5970 * ClutterActor:scale-gravity:
5972 * The center point for scaling expressed as a #ClutterGravity
5976 obj_props[PROP_SCALE_GRAVITY] =
5977 g_param_spec_enum ("scale-gravity",
5978 P_("Scale Gravity"),
5979 P_("The center of scaling"),
5980 CLUTTER_TYPE_GRAVITY,
5981 CLUTTER_GRAVITY_NONE,
5982 CLUTTER_PARAM_READWRITE);
5985 * ClutterActor:rotation-angle-x:
5987 * The rotation angle on the X axis.
5989 * The #ClutterActor:rotation-angle-x property is animatable.
5993 obj_props[PROP_ROTATION_ANGLE_X] =
5994 g_param_spec_double ("rotation-angle-x",
5995 P_("Rotation Angle X"),
5996 P_("The rotation angle on the X axis"),
5997 -G_MAXDOUBLE, G_MAXDOUBLE,
6000 G_PARAM_STATIC_STRINGS |
6001 CLUTTER_PARAM_ANIMATABLE);
6004 * ClutterActor:rotation-angle-y:
6006 * The rotation angle on the Y axis
6008 * The #ClutterActor:rotation-angle-y property is animatable.
6012 obj_props[PROP_ROTATION_ANGLE_Y] =
6013 g_param_spec_double ("rotation-angle-y",
6014 P_("Rotation Angle Y"),
6015 P_("The rotation angle on the Y axis"),
6016 -G_MAXDOUBLE, G_MAXDOUBLE,
6019 G_PARAM_STATIC_STRINGS |
6020 CLUTTER_PARAM_ANIMATABLE);
6023 * ClutterActor:rotation-angle-z:
6025 * The rotation angle on the Z axis
6027 * The #ClutterActor:rotation-angle-z property is animatable.
6031 obj_props[PROP_ROTATION_ANGLE_Z] =
6032 g_param_spec_double ("rotation-angle-z",
6033 P_("Rotation Angle Z"),
6034 P_("The rotation angle on the Z axis"),
6035 -G_MAXDOUBLE, G_MAXDOUBLE,
6038 G_PARAM_STATIC_STRINGS |
6039 CLUTTER_PARAM_ANIMATABLE);
6042 * ClutterActor:rotation-center-x:
6044 * The rotation center on the X axis.
6048 obj_props[PROP_ROTATION_CENTER_X] =
6049 g_param_spec_boxed ("rotation-center-x",
6050 P_("Rotation Center X"),
6051 P_("The rotation center on the X axis"),
6052 CLUTTER_TYPE_VERTEX,
6053 CLUTTER_PARAM_READWRITE);
6056 * ClutterActor:rotation-center-y:
6058 * The rotation center on the Y axis.
6062 obj_props[PROP_ROTATION_CENTER_Y] =
6063 g_param_spec_boxed ("rotation-center-y",
6064 P_("Rotation Center Y"),
6065 P_("The rotation center on the Y axis"),
6066 CLUTTER_TYPE_VERTEX,
6067 CLUTTER_PARAM_READWRITE);
6070 * ClutterActor:rotation-center-z:
6072 * The rotation center on the Z axis.
6076 obj_props[PROP_ROTATION_CENTER_Z] =
6077 g_param_spec_boxed ("rotation-center-z",
6078 P_("Rotation Center Z"),
6079 P_("The rotation center on the Z axis"),
6080 CLUTTER_TYPE_VERTEX,
6081 CLUTTER_PARAM_READWRITE);
6084 * ClutterActor:rotation-center-z-gravity:
6086 * The rotation center on the Z axis expressed as a #ClutterGravity.
6090 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6091 g_param_spec_enum ("rotation-center-z-gravity",
6092 P_("Rotation Center Z Gravity"),
6093 P_("Center point for rotation around the Z axis"),
6094 CLUTTER_TYPE_GRAVITY,
6095 CLUTTER_GRAVITY_NONE,
6096 CLUTTER_PARAM_READWRITE);
6099 * ClutterActor:anchor-x:
6101 * The X coordinate of an actor's anchor point, relative to
6102 * the actor coordinate space, in pixels
6106 obj_props[PROP_ANCHOR_X] =
6107 g_param_spec_float ("anchor-x",
6109 P_("X coordinate of the anchor point"),
6110 -G_MAXFLOAT, G_MAXFLOAT,
6112 CLUTTER_PARAM_READWRITE);
6115 * ClutterActor:anchor-y:
6117 * The Y coordinate of an actor's anchor point, relative to
6118 * the actor coordinate space, in pixels
6122 obj_props[PROP_ANCHOR_Y] =
6123 g_param_spec_float ("anchor-y",
6125 P_("Y coordinate of the anchor point"),
6126 -G_MAXFLOAT, G_MAXFLOAT,
6128 CLUTTER_PARAM_READWRITE);
6131 * ClutterActor:anchor-gravity:
6133 * The anchor point expressed as a #ClutterGravity
6137 obj_props[PROP_ANCHOR_GRAVITY] =
6138 g_param_spec_enum ("anchor-gravity",
6139 P_("Anchor Gravity"),
6140 P_("The anchor point as a ClutterGravity"),
6141 CLUTTER_TYPE_GRAVITY,
6142 CLUTTER_GRAVITY_NONE,
6143 CLUTTER_PARAM_READWRITE);
6146 * ClutterActor:show-on-set-parent:
6148 * If %TRUE, the actor is automatically shown when parented.
6150 * Calling clutter_actor_hide() on an actor which has not been
6151 * parented will set this property to %FALSE as a side effect.
6155 obj_props[PROP_SHOW_ON_SET_PARENT] =
6156 g_param_spec_boolean ("show-on-set-parent",
6157 P_("Show on set parent"),
6158 P_("Whether the actor is shown when parented"),
6160 CLUTTER_PARAM_READWRITE);
6163 * ClutterActor:clip-to-allocation:
6165 * Whether the clip region should track the allocated area
6168 * This property is ignored if a clip area has been explicitly
6169 * set using clutter_actor_set_clip().
6173 obj_props[PROP_CLIP_TO_ALLOCATION] =
6174 g_param_spec_boolean ("clip-to-allocation",
6175 P_("Clip to Allocation"),
6176 P_("Sets the clip region to track the actor's allocation"),
6178 CLUTTER_PARAM_READWRITE);
6181 * ClutterActor:text-direction:
6183 * The direction of the text inside a #ClutterActor.
6187 obj_props[PROP_TEXT_DIRECTION] =
6188 g_param_spec_enum ("text-direction",
6189 P_("Text Direction"),
6190 P_("Direction of the text"),
6191 CLUTTER_TYPE_TEXT_DIRECTION,
6192 CLUTTER_TEXT_DIRECTION_LTR,
6193 CLUTTER_PARAM_READWRITE);
6196 * ClutterActor:has-pointer:
6198 * Whether the actor contains the pointer of a #ClutterInputDevice
6203 obj_props[PROP_HAS_POINTER] =
6204 g_param_spec_boolean ("has-pointer",
6206 P_("Whether the actor contains the pointer of an input device"),
6208 CLUTTER_PARAM_READABLE);
6211 * ClutterActor:actions:
6213 * Adds a #ClutterAction to the actor
6217 obj_props[PROP_ACTIONS] =
6218 g_param_spec_object ("actions",
6220 P_("Adds an action to the actor"),
6221 CLUTTER_TYPE_ACTION,
6222 CLUTTER_PARAM_WRITABLE);
6225 * ClutterActor:constraints:
6227 * Adds a #ClutterConstraint to the actor
6231 obj_props[PROP_CONSTRAINTS] =
6232 g_param_spec_object ("constraints",
6234 P_("Adds a constraint to the actor"),
6235 CLUTTER_TYPE_CONSTRAINT,
6236 CLUTTER_PARAM_WRITABLE);
6239 * ClutterActor:effect:
6241 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6245 obj_props[PROP_EFFECT] =
6246 g_param_spec_object ("effect",
6248 P_("Add an effect to be applied on the actor"),
6249 CLUTTER_TYPE_EFFECT,
6250 CLUTTER_PARAM_WRITABLE);
6253 * ClutterActor:layout-manager:
6255 * A delegate object for controlling the layout of the children of
6260 obj_props[PROP_LAYOUT_MANAGER] =
6261 g_param_spec_object ("layout-manager",
6262 P_("Layout Manager"),
6263 P_("The object controlling the layout of an actor's children"),
6264 CLUTTER_TYPE_LAYOUT_MANAGER,
6265 CLUTTER_PARAM_READWRITE);
6269 * ClutterActor:x-align:
6271 * The alignment of an actor on the X axis, if the actor has been given
6272 * extra space for its allocation.
6276 obj_props[PROP_X_ALIGN] =
6277 g_param_spec_enum ("x-align",
6279 P_("The alignment of the actor on the X axis within its allocation"),
6280 CLUTTER_TYPE_ACTOR_ALIGN,
6281 CLUTTER_ACTOR_ALIGN_FILL,
6282 CLUTTER_PARAM_READWRITE);
6285 * ClutterActor:y-align:
6287 * The alignment of an actor on the Y axis, if the actor has been given
6288 * extra space for its allocation.
6292 obj_props[PROP_Y_ALIGN] =
6293 g_param_spec_enum ("y-align",
6295 P_("The alignment of the actor on the Y axis within its allocation"),
6296 CLUTTER_TYPE_ACTOR_ALIGN,
6297 CLUTTER_ACTOR_ALIGN_FILL,
6298 CLUTTER_PARAM_READWRITE);
6301 * ClutterActor:margin-top:
6303 * The margin (in pixels) from the top of the actor.
6305 * This property adds a margin to the actor's preferred size; the margin
6306 * will be automatically taken into account when allocating the actor.
6310 obj_props[PROP_MARGIN_TOP] =
6311 g_param_spec_float ("margin-top",
6313 P_("Extra space at the top"),
6316 CLUTTER_PARAM_READWRITE);
6319 * ClutterActor:margin-bottom:
6321 * The margin (in pixels) from the bottom of the actor.
6323 * This property adds a margin to the actor's preferred size; the margin
6324 * will be automatically taken into account when allocating the actor.
6328 obj_props[PROP_MARGIN_BOTTOM] =
6329 g_param_spec_float ("margin-bottom",
6330 P_("Margin Bottom"),
6331 P_("Extra space at the bottom"),
6334 CLUTTER_PARAM_READWRITE);
6337 * ClutterActor:margin-left:
6339 * The margin (in pixels) from the left of the actor.
6341 * This property adds a margin to the actor's preferred size; the margin
6342 * will be automatically taken into account when allocating the actor.
6346 obj_props[PROP_MARGIN_LEFT] =
6347 g_param_spec_float ("margin-left",
6349 P_("Extra space at the left"),
6352 CLUTTER_PARAM_READWRITE);
6355 * ClutterActor:margin-right:
6357 * The margin (in pixels) from the right of the actor.
6359 * This property adds a margin to the actor's preferred size; the margin
6360 * will be automatically taken into account when allocating the actor.
6364 obj_props[PROP_MARGIN_RIGHT] =
6365 g_param_spec_float ("margin-right",
6367 P_("Extra space at the right"),
6370 CLUTTER_PARAM_READWRITE);
6373 * ClutterActor:background-color-set:
6375 * Whether the #ClutterActor:background-color property has been set.
6379 obj_props[PROP_BACKGROUND_COLOR_SET] =
6380 g_param_spec_boolean ("background-color-set",
6381 P_("Background Color Set"),
6382 P_("Whether the background color is set"),
6384 CLUTTER_PARAM_READABLE);
6387 * ClutterActor:background-color:
6389 * Paints a solid fill of the actor's allocation using the specified
6392 * The #ClutterActor:background-color property is animatable.
6396 obj_props[PROP_BACKGROUND_COLOR] =
6397 clutter_param_spec_color ("background-color",
6398 P_("Background color"),
6399 P_("The actor's background color"),
6400 CLUTTER_COLOR_Transparent,
6402 G_PARAM_STATIC_STRINGS |
6403 CLUTTER_PARAM_ANIMATABLE);
6406 * ClutterActor:first-child:
6408 * The actor's first child.
6412 obj_props[PROP_FIRST_CHILD] =
6413 g_param_spec_object ("first-child",
6415 P_("The actor's first child"),
6417 CLUTTER_PARAM_READABLE);
6420 * ClutterActor:last-child:
6422 * The actor's last child.
6426 obj_props[PROP_LAST_CHILD] =
6427 g_param_spec_object ("last-child",
6429 P_("The actor's last child"),
6431 CLUTTER_PARAM_READABLE);
6434 * ClutterActor:content:
6436 * The #ClutterContent implementation that controls the content
6441 obj_props[PROP_CONTENT] =
6442 g_param_spec_object ("content",
6444 P_("Delegate object for painting the actor's content"),
6445 CLUTTER_TYPE_CONTENT,
6446 CLUTTER_PARAM_READWRITE);
6449 * ClutterActor:content-gravity:
6451 * The alignment that should be honoured by the #ClutterContent
6452 * set with the #ClutterActor:content property.
6454 * Changing the value of this property will change the bounding box of
6455 * the content; you can use the #ClutterActor:content-box property to
6456 * get the position and size of the content within the actor's
6459 * This property is meaningful only for #ClutterContent implementations
6460 * that have a preferred size, and if the preferred size is smaller than
6461 * the actor's allocation.
6465 obj_props[PROP_CONTENT_GRAVITY] =
6466 g_param_spec_enum ("content-gravity",
6467 P_("Content Gravity"),
6468 P_("Alignment of the actor's content"),
6469 CLUTTER_TYPE_CONTENT_GRAVITY,
6470 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6471 CLUTTER_PARAM_READWRITE);
6474 * ClutterActor:content-box:
6476 * The bounding box for the #ClutterContent used by the actor.
6478 * The value of this property is controlled by the #ClutterActor:allocation
6479 * and #ClutterActor:content-gravity properties of #ClutterActor.
6481 * The bounding box for the content is guaranteed to never exceed the
6482 * allocation's of the actor.
6486 obj_props[PROP_CONTENT_BOX] =
6487 g_param_spec_boxed ("content-box",
6489 P_("The bounding box of the actor's content"),
6490 CLUTTER_TYPE_ACTOR_BOX,
6491 CLUTTER_PARAM_READABLE);
6493 obj_props[PROP_MINIFICATION_FILTER] =
6494 g_param_spec_enum ("minification-filter",
6495 P_("Minification Filter"),
6496 P_("The filter used when reducing the size of the content"),
6497 CLUTTER_TYPE_SCALING_FILTER,
6498 CLUTTER_SCALING_FILTER_LINEAR,
6499 CLUTTER_PARAM_READWRITE);
6501 obj_props[PROP_MAGNIFICATION_FILTER] =
6502 g_param_spec_enum ("magnification-filter",
6503 P_("Magnification Filter"),
6504 P_("The filter used when increasing the size of the content"),
6505 CLUTTER_TYPE_SCALING_FILTER,
6506 CLUTTER_SCALING_FILTER_LINEAR,
6507 CLUTTER_PARAM_READWRITE);
6509 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6512 * ClutterActor::destroy:
6513 * @actor: the #ClutterActor which emitted the signal
6515 * The ::destroy signal notifies that all references held on the
6516 * actor which emitted it should be released.
6518 * The ::destroy signal should be used by all holders of a reference
6521 * This signal might result in the finalization of the #ClutterActor
6522 * if all references are released.
6524 * Composite actors and actors implementing the #ClutterContainer
6525 * interface should override the default implementation of the
6526 * class handler of this signal and call clutter_actor_destroy() on
6527 * their children. When overriding the default class handler, it is
6528 * required to chain up to the parent's implementation.
6532 actor_signals[DESTROY] =
6533 g_signal_new (I_("destroy"),
6534 G_TYPE_FROM_CLASS (object_class),
6535 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6536 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6538 _clutter_marshal_VOID__VOID,
6541 * ClutterActor::show:
6542 * @actor: the object which received the signal
6544 * The ::show signal is emitted when an actor is visible and
6545 * rendered on the stage.
6549 actor_signals[SHOW] =
6550 g_signal_new (I_("show"),
6551 G_TYPE_FROM_CLASS (object_class),
6553 G_STRUCT_OFFSET (ClutterActorClass, show),
6555 _clutter_marshal_VOID__VOID,
6558 * ClutterActor::hide:
6559 * @actor: the object which received the signal
6561 * The ::hide signal is emitted when an actor is no longer rendered
6566 actor_signals[HIDE] =
6567 g_signal_new (I_("hide"),
6568 G_TYPE_FROM_CLASS (object_class),
6570 G_STRUCT_OFFSET (ClutterActorClass, hide),
6572 _clutter_marshal_VOID__VOID,
6575 * ClutterActor::parent-set:
6576 * @actor: the object which received the signal
6577 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6579 * This signal is emitted when the parent of the actor changes.
6583 actor_signals[PARENT_SET] =
6584 g_signal_new (I_("parent-set"),
6585 G_TYPE_FROM_CLASS (object_class),
6587 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6589 _clutter_marshal_VOID__OBJECT,
6591 CLUTTER_TYPE_ACTOR);
6594 * ClutterActor::queue-redraw:
6595 * @actor: the actor we're bubbling the redraw request through
6596 * @origin: the actor which initiated the redraw request
6598 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6599 * is called on @origin.
6601 * The default implementation for #ClutterActor chains up to the
6602 * parent actor and queues a redraw on the parent, thus "bubbling"
6603 * the redraw queue up through the actor graph. The default
6604 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6605 * in a main loop idle handler.
6607 * Note that the @origin actor may be the stage, or a container; it
6608 * does not have to be a leaf node in the actor graph.
6610 * Toolkits embedding a #ClutterStage which require a redraw and
6611 * relayout cycle can stop the emission of this signal using the
6612 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6617 * on_redraw_complete (gpointer data)
6619 * ClutterStage *stage = data;
6621 * /* execute the Clutter drawing pipeline */
6622 * clutter_stage_ensure_redraw (stage);
6626 * on_stage_queue_redraw (ClutterStage *stage)
6628 * /* this prevents the default handler to run */
6629 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6631 * /* queue a redraw with the host toolkit and call
6632 * * a function when the redraw has been completed
6634 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6638 * <note><para>This signal is emitted before the Clutter paint
6639 * pipeline is executed. If you want to know when the pipeline has
6640 * been completed you should connect to the ::paint signal on the
6641 * Stage with g_signal_connect_after().</para></note>
6645 actor_signals[QUEUE_REDRAW] =
6646 g_signal_new (I_("queue-redraw"),
6647 G_TYPE_FROM_CLASS (object_class),
6650 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6652 _clutter_marshal_VOID__OBJECT,
6654 CLUTTER_TYPE_ACTOR);
6657 * ClutterActor::queue-relayout
6658 * @actor: the actor being queued for relayout
6660 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6661 * is called on an actor.
6663 * The default implementation for #ClutterActor chains up to the
6664 * parent actor and queues a relayout on the parent, thus "bubbling"
6665 * the relayout queue up through the actor graph.
6667 * The main purpose of this signal is to allow relayout to be propagated
6668 * properly in the procense of #ClutterClone actors. Applications will
6669 * not normally need to connect to this signal.
6673 actor_signals[QUEUE_RELAYOUT] =
6674 g_signal_new (I_("queue-relayout"),
6675 G_TYPE_FROM_CLASS (object_class),
6678 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6680 _clutter_marshal_VOID__VOID,
6684 * ClutterActor::event:
6685 * @actor: the actor which received the event
6686 * @event: a #ClutterEvent
6688 * The ::event signal is emitted each time an event is received
6689 * by the @actor. This signal will be emitted on every actor,
6690 * following the hierarchy chain, until it reaches the top-level
6691 * container (the #ClutterStage).
6693 * Return value: %TRUE if the event has been handled by the actor,
6694 * or %FALSE to continue the emission.
6698 actor_signals[EVENT] =
6699 g_signal_new (I_("event"),
6700 G_TYPE_FROM_CLASS (object_class),
6702 G_STRUCT_OFFSET (ClutterActorClass, event),
6703 _clutter_boolean_handled_accumulator, NULL,
6704 _clutter_marshal_BOOLEAN__BOXED,
6706 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6708 * ClutterActor::button-press-event:
6709 * @actor: the actor which received the event
6710 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6712 * The ::button-press-event signal is emitted each time a mouse button
6713 * is pressed on @actor.
6715 * Return value: %TRUE if the event has been handled by the actor,
6716 * or %FALSE to continue the emission.
6720 actor_signals[BUTTON_PRESS_EVENT] =
6721 g_signal_new (I_("button-press-event"),
6722 G_TYPE_FROM_CLASS (object_class),
6724 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6725 _clutter_boolean_handled_accumulator, NULL,
6726 _clutter_marshal_BOOLEAN__BOXED,
6728 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6730 * ClutterActor::button-release-event:
6731 * @actor: the actor which received the event
6732 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6734 * The ::button-release-event signal is emitted each time a mouse button
6735 * is released on @actor.
6737 * Return value: %TRUE if the event has been handled by the actor,
6738 * or %FALSE to continue the emission.
6742 actor_signals[BUTTON_RELEASE_EVENT] =
6743 g_signal_new (I_("button-release-event"),
6744 G_TYPE_FROM_CLASS (object_class),
6746 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6747 _clutter_boolean_handled_accumulator, NULL,
6748 _clutter_marshal_BOOLEAN__BOXED,
6750 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6752 * ClutterActor::scroll-event:
6753 * @actor: the actor which received the event
6754 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6756 * The ::scroll-event signal is emitted each time the mouse is
6757 * scrolled on @actor
6759 * Return value: %TRUE if the event has been handled by the actor,
6760 * or %FALSE to continue the emission.
6764 actor_signals[SCROLL_EVENT] =
6765 g_signal_new (I_("scroll-event"),
6766 G_TYPE_FROM_CLASS (object_class),
6768 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6769 _clutter_boolean_handled_accumulator, NULL,
6770 _clutter_marshal_BOOLEAN__BOXED,
6772 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6774 * ClutterActor::key-press-event:
6775 * @actor: the actor which received the event
6776 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6778 * The ::key-press-event signal is emitted each time a keyboard button
6779 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6781 * Return value: %TRUE if the event has been handled by the actor,
6782 * or %FALSE to continue the emission.
6786 actor_signals[KEY_PRESS_EVENT] =
6787 g_signal_new (I_("key-press-event"),
6788 G_TYPE_FROM_CLASS (object_class),
6790 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6791 _clutter_boolean_handled_accumulator, NULL,
6792 _clutter_marshal_BOOLEAN__BOXED,
6794 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6796 * ClutterActor::key-release-event:
6797 * @actor: the actor which received the event
6798 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6800 * The ::key-release-event signal is emitted each time a keyboard button
6801 * is released while @actor has key focus (see
6802 * clutter_stage_set_key_focus()).
6804 * Return value: %TRUE if the event has been handled by the actor,
6805 * or %FALSE to continue the emission.
6809 actor_signals[KEY_RELEASE_EVENT] =
6810 g_signal_new (I_("key-release-event"),
6811 G_TYPE_FROM_CLASS (object_class),
6813 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6814 _clutter_boolean_handled_accumulator, NULL,
6815 _clutter_marshal_BOOLEAN__BOXED,
6817 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6819 * ClutterActor::motion-event:
6820 * @actor: the actor which received the event
6821 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6823 * The ::motion-event signal is emitted each time the mouse pointer is
6824 * moved over @actor.
6826 * Return value: %TRUE if the event has been handled by the actor,
6827 * or %FALSE to continue the emission.
6831 actor_signals[MOTION_EVENT] =
6832 g_signal_new (I_("motion-event"),
6833 G_TYPE_FROM_CLASS (object_class),
6835 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6836 _clutter_boolean_handled_accumulator, NULL,
6837 _clutter_marshal_BOOLEAN__BOXED,
6839 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6842 * ClutterActor::key-focus-in:
6843 * @actor: the actor which now has key focus
6845 * The ::key-focus-in signal is emitted when @actor receives key focus.
6849 actor_signals[KEY_FOCUS_IN] =
6850 g_signal_new (I_("key-focus-in"),
6851 G_TYPE_FROM_CLASS (object_class),
6853 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6855 _clutter_marshal_VOID__VOID,
6859 * ClutterActor::key-focus-out:
6860 * @actor: the actor which now has key focus
6862 * The ::key-focus-out signal is emitted when @actor loses key focus.
6866 actor_signals[KEY_FOCUS_OUT] =
6867 g_signal_new (I_("key-focus-out"),
6868 G_TYPE_FROM_CLASS (object_class),
6870 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6872 _clutter_marshal_VOID__VOID,
6876 * ClutterActor::enter-event:
6877 * @actor: the actor which the pointer has entered.
6878 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6880 * The ::enter-event signal is emitted when the pointer enters the @actor
6882 * Return value: %TRUE if the event has been handled by the actor,
6883 * or %FALSE to continue the emission.
6887 actor_signals[ENTER_EVENT] =
6888 g_signal_new (I_("enter-event"),
6889 G_TYPE_FROM_CLASS (object_class),
6891 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6892 _clutter_boolean_handled_accumulator, NULL,
6893 _clutter_marshal_BOOLEAN__BOXED,
6895 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6898 * ClutterActor::leave-event:
6899 * @actor: the actor which the pointer has left
6900 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6902 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6904 * Return value: %TRUE if the event has been handled by the actor,
6905 * or %FALSE to continue the emission.
6909 actor_signals[LEAVE_EVENT] =
6910 g_signal_new (I_("leave-event"),
6911 G_TYPE_FROM_CLASS (object_class),
6913 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6914 _clutter_boolean_handled_accumulator, NULL,
6915 _clutter_marshal_BOOLEAN__BOXED,
6917 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6920 * ClutterActor::captured-event:
6921 * @actor: the actor which received the signal
6922 * @event: a #ClutterEvent
6924 * The ::captured-event signal is emitted when an event is captured
6925 * by Clutter. This signal will be emitted starting from the top-level
6926 * container (the #ClutterStage) to the actor which received the event
6927 * going down the hierarchy. This signal can be used to intercept every
6928 * event before the specialized events (like
6929 * ClutterActor::button-press-event or ::key-released-event) are
6932 * Return value: %TRUE if the event has been handled by the actor,
6933 * or %FALSE to continue the emission.
6937 actor_signals[CAPTURED_EVENT] =
6938 g_signal_new (I_("captured-event"),
6939 G_TYPE_FROM_CLASS (object_class),
6941 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6942 _clutter_boolean_handled_accumulator, NULL,
6943 _clutter_marshal_BOOLEAN__BOXED,
6945 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6948 * ClutterActor::paint:
6949 * @actor: the #ClutterActor that received the signal
6951 * The ::paint signal is emitted each time an actor is being painted.
6953 * Subclasses of #ClutterActor should override the class signal handler
6954 * and paint themselves in that function.
6956 * It is possible to connect a handler to the ::paint signal in order
6957 * to set up some custom aspect of a paint.
6961 actor_signals[PAINT] =
6962 g_signal_new (I_("paint"),
6963 G_TYPE_FROM_CLASS (object_class),
6966 G_STRUCT_OFFSET (ClutterActorClass, paint),
6968 _clutter_marshal_VOID__VOID,
6971 * ClutterActor::realize:
6972 * @actor: the #ClutterActor that received the signal
6974 * The ::realize signal is emitted each time an actor is being
6979 actor_signals[REALIZE] =
6980 g_signal_new (I_("realize"),
6981 G_TYPE_FROM_CLASS (object_class),
6983 G_STRUCT_OFFSET (ClutterActorClass, realize),
6985 _clutter_marshal_VOID__VOID,
6988 * ClutterActor::unrealize:
6989 * @actor: the #ClutterActor that received the signal
6991 * The ::unrealize signal is emitted each time an actor is being
6996 actor_signals[UNREALIZE] =
6997 g_signal_new (I_("unrealize"),
6998 G_TYPE_FROM_CLASS (object_class),
7000 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7002 _clutter_marshal_VOID__VOID,
7006 * ClutterActor::pick:
7007 * @actor: the #ClutterActor that received the signal
7008 * @color: the #ClutterColor to be used when picking
7010 * The ::pick signal is emitted each time an actor is being painted
7011 * in "pick mode". The pick mode is used to identify the actor during
7012 * the event handling phase, or by clutter_stage_get_actor_at_pos().
7013 * The actor should paint its shape using the passed @pick_color.
7015 * Subclasses of #ClutterActor should override the class signal handler
7016 * and paint themselves in that function.
7018 * It is possible to connect a handler to the ::pick signal in order
7019 * to set up some custom aspect of a paint in pick mode.
7023 actor_signals[PICK] =
7024 g_signal_new (I_("pick"),
7025 G_TYPE_FROM_CLASS (object_class),
7027 G_STRUCT_OFFSET (ClutterActorClass, pick),
7029 _clutter_marshal_VOID__BOXED,
7031 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7034 * ClutterActor::allocation-changed:
7035 * @actor: the #ClutterActor that emitted the signal
7036 * @box: a #ClutterActorBox with the new allocation
7037 * @flags: #ClutterAllocationFlags for the allocation
7039 * The ::allocation-changed signal is emitted when the
7040 * #ClutterActor:allocation property changes. Usually, application
7041 * code should just use the notifications for the :allocation property
7042 * but if you want to track the allocation flags as well, for instance
7043 * to know whether the absolute origin of @actor changed, then you might
7044 * want use this signal instead.
7048 actor_signals[ALLOCATION_CHANGED] =
7049 g_signal_new (I_("allocation-changed"),
7050 G_TYPE_FROM_CLASS (object_class),
7054 _clutter_marshal_VOID__BOXED_FLAGS,
7056 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7057 CLUTTER_TYPE_ALLOCATION_FLAGS);
7060 * ClutterActor::transitions-completed:
7061 * @actor: a #ClutterActor
7063 * The ::transitions-completed signal is emitted once all transitions
7064 * involving @actor are complete.
7068 actor_signals[TRANSITIONS_COMPLETED] =
7069 g_signal_new (I_("transitions-completed"),
7070 G_TYPE_FROM_CLASS (object_class),
7074 _clutter_marshal_VOID__VOID,
7079 clutter_actor_init (ClutterActor *self)
7081 ClutterActorPrivate *priv;
7083 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7085 priv->id = _clutter_context_acquire_id (self);
7088 priv->opacity = 0xff;
7089 priv->show_on_set_parent = TRUE;
7091 priv->needs_width_request = TRUE;
7092 priv->needs_height_request = TRUE;
7093 priv->needs_allocation = TRUE;
7095 priv->cached_width_age = 1;
7096 priv->cached_height_age = 1;
7098 priv->opacity_override = -1;
7099 priv->enable_model_view_transform = TRUE;
7101 /* Initialize an empty paint volume to start with */
7102 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7103 priv->last_paint_volume_valid = TRUE;
7105 priv->transform_valid = FALSE;
7107 /* the default is to stretch the content, to match the
7108 * current behaviour of basically all actors. also, it's
7109 * the easiest thing to compute.
7111 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7112 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7113 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7117 * clutter_actor_new:
7119 * Creates a new #ClutterActor.
7121 * A newly created actor has a floating reference, which will be sunk
7122 * when it is added to another actor.
7124 * Return value: (transfer full): the newly created #ClutterActor
7129 clutter_actor_new (void)
7131 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7135 * clutter_actor_destroy:
7136 * @self: a #ClutterActor
7138 * Destroys an actor. When an actor is destroyed, it will break any
7139 * references it holds to other objects. If the actor is inside a
7140 * container, the actor will be removed.
7142 * When you destroy a container, its children will be destroyed as well.
7144 * Note: you cannot destroy the #ClutterStage returned by
7145 * clutter_stage_get_default().
7148 clutter_actor_destroy (ClutterActor *self)
7150 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7152 g_object_ref (self);
7154 /* avoid recursion while destroying */
7155 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7157 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7159 g_object_run_dispose (G_OBJECT (self));
7161 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7164 g_object_unref (self);
7168 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7169 ClutterPaintVolume *clip)
7171 ClutterActorPrivate *priv = self->priv;
7172 ClutterPaintVolume *pv;
7175 /* Remove queue entry early in the process, otherwise a new
7176 queue_redraw() during signal handling could put back this
7177 object in the stage redraw list (but the entry is freed as
7178 soon as we return from this function, causing a segfault
7181 priv->queue_redraw_entry = NULL;
7183 /* If we've been explicitly passed a clip volume then there's
7184 * nothing more to calculate, but otherwise the only thing we know
7185 * is that the change is constrained to the given actor.
7187 * The idea is that if we know the paint volume for where the actor
7188 * was last drawn (in eye coordinates) and we also have the paint
7189 * volume for where it will be drawn next (in actor coordinates)
7190 * then if we queue a redraw for both these volumes that will cover
7191 * everything that needs to be redrawn to clear the old view and
7192 * show the latest view of the actor.
7194 * Don't clip this redraw if we don't know what position we had for
7195 * the previous redraw since we don't know where to set the clip so
7196 * it will clear the actor as it is currently.
7200 _clutter_actor_set_queue_redraw_clip (self, clip);
7203 else if (G_LIKELY (priv->last_paint_volume_valid))
7205 pv = _clutter_actor_get_paint_volume_mutable (self);
7208 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7210 /* make sure we redraw the actors old position... */
7211 _clutter_actor_set_queue_redraw_clip (stage,
7212 &priv->last_paint_volume);
7213 _clutter_actor_signal_queue_redraw (stage, stage);
7214 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7216 /* XXX: Ideally the redraw signal would take a clip volume
7217 * argument, but that would be an ABI break. Until we can
7218 * break the ABI we pass the argument out-of-band
7221 /* setup the clip for the actors new position... */
7222 _clutter_actor_set_queue_redraw_clip (self, pv);
7231 _clutter_actor_signal_queue_redraw (self, self);
7233 /* Just in case anyone is manually firing redraw signals without
7234 * using the public queue_redraw() API we are careful to ensure that
7235 * our out-of-band clip member is cleared before returning...
7237 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7239 if (G_LIKELY (clipped))
7240 _clutter_actor_set_queue_redraw_clip (self, NULL);
7244 _clutter_actor_get_allocation_clip (ClutterActor *self,
7245 ClutterActorBox *clip)
7247 ClutterActorBox allocation;
7249 /* XXX: we don't care if we get an out of date allocation here
7250 * because clutter_actor_queue_redraw_with_clip knows to ignore
7251 * the clip if the actor's allocation is invalid.
7253 * This is noted because clutter_actor_get_allocation_box does some
7254 * unnecessary work to support buggy code with a comment suggesting
7255 * that it could be changed later which would be good for this use
7258 clutter_actor_get_allocation_box (self, &allocation);
7260 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7261 * actor's own coordinate space but the allocation is in parent
7265 clip->x2 = allocation.x2 - allocation.x1;
7266 clip->y2 = allocation.y2 - allocation.y1;
7270 _clutter_actor_queue_redraw_full (ClutterActor *self,
7271 ClutterRedrawFlags flags,
7272 ClutterPaintVolume *volume,
7273 ClutterEffect *effect)
7275 ClutterActorPrivate *priv = self->priv;
7276 ClutterPaintVolume allocation_pv;
7277 ClutterPaintVolume *pv;
7278 gboolean should_free_pv;
7279 ClutterActor *stage;
7281 /* Here's an outline of the actor queue redraw mechanism:
7283 * The process starts in one of the following two functions which
7284 * are wrappers for this function:
7285 * clutter_actor_queue_redraw
7286 * _clutter_actor_queue_redraw_with_clip
7288 * additionally, an effect can queue a redraw by wrapping this
7289 * function in clutter_effect_queue_rerun
7291 * This functions queues an entry in a list associated with the
7292 * stage which is a list of actors that queued a redraw while
7293 * updating the timelines, performing layouting and processing other
7294 * mainloop sources before the next paint starts.
7296 * We aim to minimize the processing done at this point because
7297 * there is a good chance other events will happen while updating
7298 * the scenegraph that would invalidate any expensive work we might
7299 * otherwise try to do here. For example we don't try and resolve
7300 * the screen space bounding box of an actor at this stage so as to
7301 * minimize how much of the screen redraw because it's possible
7302 * something else will happen which will force a full redraw anyway.
7304 * When all updates are complete and we come to paint the stage then
7305 * we iterate this list and actually emit the "queue-redraw" signals
7306 * for each of the listed actors which will bubble up to the stage
7307 * for each actor and at that point we will transform the actors
7308 * paint volume into screen coordinates to determine the clip region
7309 * for what needs to be redrawn in the next paint.
7311 * Besides minimizing redundant work another reason for this
7312 * deferred design is that it's more likely we will be able to
7313 * determine the paint volume of an actor once we've finished
7314 * updating the scenegraph because its allocation should be up to
7315 * date. NB: If we can't determine an actors paint volume then we
7316 * can't automatically queue a clipped redraw which can make a big
7317 * difference to performance.
7319 * So the control flow goes like this:
7320 * One of clutter_actor_queue_redraw,
7321 * _clutter_actor_queue_redraw_with_clip
7322 * or clutter_effect_queue_rerun
7324 * then control moves to:
7325 * _clutter_stage_queue_actor_redraw
7327 * later during _clutter_stage_do_update, once relayouting is done
7328 * and the scenegraph has been updated we will call:
7329 * _clutter_stage_finish_queue_redraws
7331 * _clutter_stage_finish_queue_redraws will call
7332 * _clutter_actor_finish_queue_redraw for each listed actor.
7333 * Note: actors *are* allowed to queue further redraws during this
7334 * process (considering clone actors or texture_new_from_actor which
7335 * respond to their source queueing a redraw by queuing a redraw
7336 * themselves). We repeat the process until the list is empty.
7338 * This will result in the "queue-redraw" signal being fired for
7339 * each actor which will pass control to the default signal handler:
7340 * clutter_actor_real_queue_redraw
7342 * This will bubble up to the stages handler:
7343 * clutter_stage_real_queue_redraw
7345 * clutter_stage_real_queue_redraw will transform the actors paint
7346 * volume into screen space and add it as a clip region for the next
7350 /* ignore queueing a redraw for actors being destroyed */
7351 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7354 stage = _clutter_actor_get_stage_internal (self);
7356 /* Ignore queueing a redraw for actors not descended from a stage */
7360 /* ignore queueing a redraw on stages that are being destroyed */
7361 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7364 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7366 ClutterActorBox allocation_clip;
7367 ClutterVertex origin;
7369 /* If the actor doesn't have a valid allocation then we will
7370 * queue a full stage redraw. */
7371 if (priv->needs_allocation)
7373 /* NB: NULL denotes an undefined clip which will result in a
7375 _clutter_actor_set_queue_redraw_clip (self, NULL);
7376 _clutter_actor_signal_queue_redraw (self, self);
7380 _clutter_paint_volume_init_static (&allocation_pv, self);
7381 pv = &allocation_pv;
7383 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7385 origin.x = allocation_clip.x1;
7386 origin.y = allocation_clip.y1;
7388 clutter_paint_volume_set_origin (pv, &origin);
7389 clutter_paint_volume_set_width (pv,
7390 allocation_clip.x2 - allocation_clip.x1);
7391 clutter_paint_volume_set_height (pv,
7392 allocation_clip.y2 -
7393 allocation_clip.y1);
7394 should_free_pv = TRUE;
7399 should_free_pv = FALSE;
7402 self->priv->queue_redraw_entry =
7403 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7404 priv->queue_redraw_entry,
7409 clutter_paint_volume_free (pv);
7411 /* If this is the first redraw queued then we can directly use the
7413 if (!priv->is_dirty)
7414 priv->effect_to_redraw = effect;
7415 /* Otherwise we need to merge it with the existing effect parameter */
7416 else if (effect != NULL)
7418 /* If there's already an effect then we need to use whichever is
7419 later in the chain of actors. Otherwise a full redraw has
7420 already been queued on the actor so we need to ignore the
7422 if (priv->effect_to_redraw != NULL)
7424 if (priv->effects == NULL)
7425 g_warning ("Redraw queued with an effect that is "
7426 "not applied to the actor");
7431 for (l = _clutter_meta_group_peek_metas (priv->effects);
7435 if (l->data == priv->effect_to_redraw ||
7437 priv->effect_to_redraw = l->data;
7444 /* If no effect is specified then we need to redraw the whole
7446 priv->effect_to_redraw = NULL;
7449 priv->is_dirty = TRUE;
7453 * clutter_actor_queue_redraw:
7454 * @self: A #ClutterActor
7456 * Queues up a redraw of an actor and any children. The redraw occurs
7457 * once the main loop becomes idle (after the current batch of events
7458 * has been processed, roughly).
7460 * Applications rarely need to call this, as redraws are handled
7461 * automatically by modification functions.
7463 * This function will not do anything if @self is not visible, or
7464 * if the actor is inside an invisible part of the scenegraph.
7466 * Also be aware that painting is a NOP for actors with an opacity of
7469 * When you are implementing a custom actor you must queue a redraw
7470 * whenever some private state changes that will affect painting or
7471 * picking of your actor.
7474 clutter_actor_queue_redraw (ClutterActor *self)
7476 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7478 _clutter_actor_queue_redraw_full (self,
7480 NULL, /* clip volume */
7485 * _clutter_actor_queue_redraw_with_clip:
7486 * @self: A #ClutterActor
7487 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7488 * this queue redraw.
7489 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7490 * redrawn or %NULL if you are just using a @flag to state your
7493 * Queues up a clipped redraw of an actor and any children. The redraw
7494 * occurs once the main loop becomes idle (after the current batch of
7495 * events has been processed, roughly).
7497 * If no flags are given the clip volume is defined by @volume
7498 * specified in actor coordinates and tells Clutter that only content
7499 * within this volume has been changed so Clutter can optionally
7500 * optimize the redraw.
7502 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7503 * should be %NULL and this tells Clutter to use the actor's current
7504 * allocation as a clip box. This flag can only be used for 2D actors,
7505 * because any actor with depth may be projected outside its
7508 * Applications rarely need to call this, as redraws are handled
7509 * automatically by modification functions.
7511 * This function will not do anything if @self is not visible, or if
7512 * the actor is inside an invisible part of the scenegraph.
7514 * Also be aware that painting is a NOP for actors with an opacity of
7517 * When you are implementing a custom actor you must queue a redraw
7518 * whenever some private state changes that will affect painting or
7519 * picking of your actor.
7522 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7523 ClutterRedrawFlags flags,
7524 ClutterPaintVolume *volume)
7526 _clutter_actor_queue_redraw_full (self,
7528 volume, /* clip volume */
7533 _clutter_actor_queue_only_relayout (ClutterActor *self)
7535 ClutterActorPrivate *priv = self->priv;
7537 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7540 if (priv->needs_width_request &&
7541 priv->needs_height_request &&
7542 priv->needs_allocation)
7543 return; /* save some cpu cycles */
7545 #if CLUTTER_ENABLE_DEBUG
7546 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7548 g_warning ("The actor '%s' is currently inside an allocation "
7549 "cycle; calling clutter_actor_queue_relayout() is "
7551 _clutter_actor_get_debug_name (self));
7553 #endif /* CLUTTER_ENABLE_DEBUG */
7555 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7559 * clutter_actor_queue_redraw_with_clip:
7560 * @self: a #ClutterActor
7561 * @clip: (allow-none): a rectangular clip region, or %NULL
7563 * Queues a redraw on @self limited to a specific, actor-relative
7566 * If @clip is %NULL this function is equivalent to
7567 * clutter_actor_queue_redraw().
7572 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7573 const cairo_rectangle_int_t *clip)
7575 ClutterPaintVolume volume;
7576 ClutterVertex origin;
7578 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7582 clutter_actor_queue_redraw (self);
7586 _clutter_paint_volume_init_static (&volume, self);
7592 clutter_paint_volume_set_origin (&volume, &origin);
7593 clutter_paint_volume_set_width (&volume, clip->width);
7594 clutter_paint_volume_set_height (&volume, clip->height);
7596 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7598 clutter_paint_volume_free (&volume);
7602 * clutter_actor_queue_relayout:
7603 * @self: A #ClutterActor
7605 * Indicates that the actor's size request or other layout-affecting
7606 * properties may have changed. This function is used inside #ClutterActor
7607 * subclass implementations, not by applications directly.
7609 * Queueing a new layout automatically queues a redraw as well.
7614 clutter_actor_queue_relayout (ClutterActor *self)
7616 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7618 _clutter_actor_queue_only_relayout (self);
7619 clutter_actor_queue_redraw (self);
7623 * clutter_actor_get_preferred_size:
7624 * @self: a #ClutterActor
7625 * @min_width_p: (out) (allow-none): return location for the minimum
7627 * @min_height_p: (out) (allow-none): return location for the minimum
7629 * @natural_width_p: (out) (allow-none): return location for the natural
7631 * @natural_height_p: (out) (allow-none): return location for the natural
7634 * Computes the preferred minimum and natural size of an actor, taking into
7635 * account the actor's geometry management (either height-for-width
7636 * or width-for-height).
7638 * The width and height used to compute the preferred height and preferred
7639 * width are the actor's natural ones.
7641 * If you need to control the height for the preferred width, or the width for
7642 * the preferred height, you should use clutter_actor_get_preferred_width()
7643 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7644 * geometry management using the #ClutterActor:request-mode property.
7649 clutter_actor_get_preferred_size (ClutterActor *self,
7650 gfloat *min_width_p,
7651 gfloat *min_height_p,
7652 gfloat *natural_width_p,
7653 gfloat *natural_height_p)
7655 ClutterActorPrivate *priv;
7656 gfloat min_width, min_height;
7657 gfloat natural_width, natural_height;
7659 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7663 min_width = min_height = 0;
7664 natural_width = natural_height = 0;
7666 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7668 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7669 clutter_actor_get_preferred_width (self, -1,
7672 clutter_actor_get_preferred_height (self, natural_width,
7678 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7679 clutter_actor_get_preferred_height (self, -1,
7682 clutter_actor_get_preferred_width (self, natural_height,
7688 *min_width_p = min_width;
7691 *min_height_p = min_height;
7693 if (natural_width_p)
7694 *natural_width_p = natural_width;
7696 if (natural_height_p)
7697 *natural_height_p = natural_height;
7702 * @align: a #ClutterActorAlign
7703 * @direction: a #ClutterTextDirection
7705 * Retrieves the correct alignment depending on the text direction
7707 * Return value: the effective alignment
7709 static ClutterActorAlign
7710 effective_align (ClutterActorAlign align,
7711 ClutterTextDirection direction)
7713 ClutterActorAlign res;
7717 case CLUTTER_ACTOR_ALIGN_START:
7718 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7719 ? CLUTTER_ACTOR_ALIGN_END
7720 : CLUTTER_ACTOR_ALIGN_START;
7723 case CLUTTER_ACTOR_ALIGN_END:
7724 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7725 ? CLUTTER_ACTOR_ALIGN_START
7726 : CLUTTER_ACTOR_ALIGN_END;
7738 adjust_for_margin (float margin_start,
7740 float *minimum_size,
7741 float *natural_size,
7742 float *allocated_start,
7743 float *allocated_end)
7745 *minimum_size -= (margin_start + margin_end);
7746 *natural_size -= (margin_start + margin_end);
7747 *allocated_start += margin_start;
7748 *allocated_end -= margin_end;
7752 adjust_for_alignment (ClutterActorAlign alignment,
7754 float *allocated_start,
7755 float *allocated_end)
7757 float allocated_size = *allocated_end - *allocated_start;
7761 case CLUTTER_ACTOR_ALIGN_FILL:
7765 case CLUTTER_ACTOR_ALIGN_START:
7767 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7770 case CLUTTER_ACTOR_ALIGN_END:
7771 if (allocated_size > natural_size)
7773 *allocated_start += (allocated_size - natural_size);
7774 *allocated_end = *allocated_start + natural_size;
7778 case CLUTTER_ACTOR_ALIGN_CENTER:
7779 if (allocated_size > natural_size)
7781 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7782 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7789 * clutter_actor_adjust_width:
7790 * @self: a #ClutterActor
7791 * @minimum_width: (inout): the actor's preferred minimum width, which
7792 * will be adjusted depending on the margin
7793 * @natural_width: (inout): the actor's preferred natural width, which
7794 * will be adjusted depending on the margin
7795 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7796 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7798 * Adjusts the preferred and allocated position and size of an actor,
7799 * depending on the margin and alignment properties.
7802 clutter_actor_adjust_width (ClutterActor *self,
7803 gfloat *minimum_width,
7804 gfloat *natural_width,
7805 gfloat *adjusted_x1,
7806 gfloat *adjusted_x2)
7808 ClutterTextDirection text_dir;
7809 const ClutterLayoutInfo *info;
7811 info = _clutter_actor_get_layout_info_or_defaults (self);
7812 text_dir = clutter_actor_get_text_direction (self);
7814 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7816 /* this will tweak natural_width to remove the margin, so that
7817 * adjust_for_alignment() will use the correct size
7819 adjust_for_margin (info->margin.left, info->margin.right,
7820 minimum_width, natural_width,
7821 adjusted_x1, adjusted_x2);
7823 adjust_for_alignment (effective_align (info->x_align, text_dir),
7825 adjusted_x1, adjusted_x2);
7829 * clutter_actor_adjust_height:
7830 * @self: a #ClutterActor
7831 * @minimum_height: (inout): the actor's preferred minimum height, which
7832 * will be adjusted depending on the margin
7833 * @natural_height: (inout): the actor's preferred natural height, which
7834 * will be adjusted depending on the margin
7835 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7836 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7838 * Adjusts the preferred and allocated position and size of an actor,
7839 * depending on the margin and alignment properties.
7842 clutter_actor_adjust_height (ClutterActor *self,
7843 gfloat *minimum_height,
7844 gfloat *natural_height,
7845 gfloat *adjusted_y1,
7846 gfloat *adjusted_y2)
7848 const ClutterLayoutInfo *info;
7850 info = _clutter_actor_get_layout_info_or_defaults (self);
7852 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7854 /* this will tweak natural_height to remove the margin, so that
7855 * adjust_for_alignment() will use the correct size
7857 adjust_for_margin (info->margin.top, info->margin.bottom,
7858 minimum_height, natural_height,
7862 /* we don't use effective_align() here, because text direction
7863 * only affects the horizontal axis
7865 adjust_for_alignment (info->y_align,
7872 /* looks for a cached size request for this for_size. If not
7873 * found, returns the oldest entry so it can be overwritten */
7875 _clutter_actor_get_cached_size_request (gfloat for_size,
7876 SizeRequest *cached_size_requests,
7877 SizeRequest **result)
7881 *result = &cached_size_requests[0];
7883 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7887 sr = &cached_size_requests[i];
7890 sr->for_size == for_size)
7892 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7896 else if (sr->age < (*result)->age)
7902 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7908 * clutter_actor_get_preferred_width:
7909 * @self: A #ClutterActor
7910 * @for_height: available height when computing the preferred width,
7911 * or a negative value to indicate that no height is defined
7912 * @min_width_p: (out) (allow-none): return location for minimum width,
7914 * @natural_width_p: (out) (allow-none): return location for the natural
7917 * Computes the requested minimum and natural widths for an actor,
7918 * optionally depending on the specified height, or if they are
7919 * already computed, returns the cached values.
7921 * An actor may not get its request - depending on the layout
7922 * manager that's in effect.
7924 * A request should not incorporate the actor's scale or anchor point;
7925 * those transformations do not affect layout, only rendering.
7930 clutter_actor_get_preferred_width (ClutterActor *self,
7932 gfloat *min_width_p,
7933 gfloat *natural_width_p)
7935 float request_min_width, request_natural_width;
7936 SizeRequest *cached_size_request;
7937 const ClutterLayoutInfo *info;
7938 ClutterActorPrivate *priv;
7939 gboolean found_in_cache;
7941 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7945 info = _clutter_actor_get_layout_info_or_defaults (self);
7947 /* we shortcircuit the case of a fixed size set using set_width() */
7948 if (priv->min_width_set && priv->natural_width_set)
7950 if (min_width_p != NULL)
7951 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7953 if (natural_width_p != NULL)
7954 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7959 /* the remaining cases are:
7961 * - either min_width or natural_width have been set
7962 * - neither min_width or natural_width have been set
7964 * in both cases, we go through the cache (and through the actor in case
7965 * of cache misses) and determine the authoritative value depending on
7969 if (!priv->needs_width_request)
7972 _clutter_actor_get_cached_size_request (for_height,
7973 priv->width_requests,
7974 &cached_size_request);
7978 /* if the actor needs a width request we use the first slot */
7979 found_in_cache = FALSE;
7980 cached_size_request = &priv->width_requests[0];
7983 if (!found_in_cache)
7985 gfloat minimum_width, natural_width;
7986 ClutterActorClass *klass;
7988 minimum_width = natural_width = 0;
7990 /* adjust for the margin */
7991 if (for_height >= 0)
7993 for_height -= (info->margin.top + info->margin.bottom);
7998 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8000 klass = CLUTTER_ACTOR_GET_CLASS (self);
8001 klass->get_preferred_width (self, for_height,
8005 /* adjust for the margin */
8006 minimum_width += (info->margin.left + info->margin.right);
8007 natural_width += (info->margin.left + info->margin.right);
8009 /* Due to accumulated float errors, it's better not to warn
8010 * on this, but just fix it.
8012 if (natural_width < minimum_width)
8013 natural_width = minimum_width;
8015 cached_size_request->min_size = minimum_width;
8016 cached_size_request->natural_size = natural_width;
8017 cached_size_request->for_size = for_height;
8018 cached_size_request->age = priv->cached_width_age;
8020 priv->cached_width_age += 1;
8021 priv->needs_width_request = FALSE;
8024 if (!priv->min_width_set)
8025 request_min_width = cached_size_request->min_size;
8027 request_min_width = info->min_width;
8029 if (!priv->natural_width_set)
8030 request_natural_width = cached_size_request->natural_size;
8032 request_natural_width = info->natural_width;
8035 *min_width_p = request_min_width;
8037 if (natural_width_p)
8038 *natural_width_p = request_natural_width;
8042 * clutter_actor_get_preferred_height:
8043 * @self: A #ClutterActor
8044 * @for_width: available width to assume in computing desired height,
8045 * or a negative value to indicate that no width is defined
8046 * @min_height_p: (out) (allow-none): return location for minimum height,
8048 * @natural_height_p: (out) (allow-none): return location for natural
8051 * Computes the requested minimum and natural heights for an actor,
8052 * or if they are already computed, returns the cached values.
8054 * An actor may not get its request - depending on the layout
8055 * manager that's in effect.
8057 * A request should not incorporate the actor's scale or anchor point;
8058 * those transformations do not affect layout, only rendering.
8063 clutter_actor_get_preferred_height (ClutterActor *self,
8065 gfloat *min_height_p,
8066 gfloat *natural_height_p)
8068 float request_min_height, request_natural_height;
8069 SizeRequest *cached_size_request;
8070 const ClutterLayoutInfo *info;
8071 ClutterActorPrivate *priv;
8072 gboolean found_in_cache;
8074 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8078 info = _clutter_actor_get_layout_info_or_defaults (self);
8080 /* we shortcircuit the case of a fixed size set using set_height() */
8081 if (priv->min_height_set && priv->natural_height_set)
8083 if (min_height_p != NULL)
8084 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
8086 if (natural_height_p != NULL)
8087 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
8092 /* the remaining cases are:
8094 * - either min_height or natural_height have been set
8095 * - neither min_height or natural_height have been set
8097 * in both cases, we go through the cache (and through the actor in case
8098 * of cache misses) and determine the authoritative value depending on
8102 if (!priv->needs_height_request)
8105 _clutter_actor_get_cached_size_request (for_width,
8106 priv->height_requests,
8107 &cached_size_request);
8111 found_in_cache = FALSE;
8112 cached_size_request = &priv->height_requests[0];
8115 if (!found_in_cache)
8117 gfloat minimum_height, natural_height;
8118 ClutterActorClass *klass;
8120 minimum_height = natural_height = 0;
8122 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8124 /* adjust for margin */
8127 for_width -= (info->margin.left + info->margin.right);
8132 klass = CLUTTER_ACTOR_GET_CLASS (self);
8133 klass->get_preferred_height (self, for_width,
8137 /* adjust for margin */
8138 minimum_height += (info->margin.top + info->margin.bottom);
8139 natural_height += (info->margin.top + info->margin.bottom);
8141 /* Due to accumulated float errors, it's better not to warn
8142 * on this, but just fix it.
8144 if (natural_height < minimum_height)
8145 natural_height = minimum_height;
8147 cached_size_request->min_size = minimum_height;
8148 cached_size_request->natural_size = natural_height;
8149 cached_size_request->for_size = for_width;
8150 cached_size_request->age = priv->cached_height_age;
8152 priv->cached_height_age += 1;
8153 priv->needs_height_request = FALSE;
8156 if (!priv->min_height_set)
8157 request_min_height = cached_size_request->min_size;
8159 request_min_height = info->min_height;
8161 if (!priv->natural_height_set)
8162 request_natural_height = cached_size_request->natural_size;
8164 request_natural_height = info->natural_height;
8167 *min_height_p = request_min_height;
8169 if (natural_height_p)
8170 *natural_height_p = request_natural_height;
8174 * clutter_actor_get_allocation_box:
8175 * @self: A #ClutterActor
8176 * @box: (out): the function fills this in with the actor's allocation
8178 * Gets the layout box an actor has been assigned. The allocation can
8179 * only be assumed valid inside a paint() method; anywhere else, it
8180 * may be out-of-date.
8182 * An allocation does not incorporate the actor's scale or anchor point;
8183 * those transformations do not affect layout, only rendering.
8185 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8186 * of functions inside the implementation of the get_preferred_width()
8187 * or get_preferred_height() virtual functions.</note>
8192 clutter_actor_get_allocation_box (ClutterActor *self,
8193 ClutterActorBox *box)
8195 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8197 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8198 * which limits calling get_allocation to inside paint() basically; or
8199 * we can 2) force a layout, which could be expensive if someone calls
8200 * get_allocation somewhere silly; or we can 3) just return the latest
8201 * value, allowing it to be out-of-date, and assume people know what
8204 * The least-surprises approach that keeps existing code working is
8205 * likely to be 2). People can end up doing some inefficient things,
8206 * though, and in general code that requires 2) is probably broken.
8209 /* this implements 2) */
8210 if (G_UNLIKELY (self->priv->needs_allocation))
8212 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8214 /* do not queue a relayout on an unparented actor */
8216 _clutter_stage_maybe_relayout (stage);
8219 /* commenting out the code above and just keeping this assigment
8222 *box = self->priv->allocation;
8226 * clutter_actor_get_allocation_geometry:
8227 * @self: A #ClutterActor
8228 * @geom: (out): allocation geometry in pixels
8230 * Gets the layout box an actor has been assigned. The allocation can
8231 * only be assumed valid inside a paint() method; anywhere else, it
8232 * may be out-of-date.
8234 * An allocation does not incorporate the actor's scale or anchor point;
8235 * those transformations do not affect layout, only rendering.
8237 * The returned rectangle is in pixels.
8242 clutter_actor_get_allocation_geometry (ClutterActor *self,
8243 ClutterGeometry *geom)
8245 ClutterActorBox box;
8247 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8248 g_return_if_fail (geom != NULL);
8250 clutter_actor_get_allocation_box (self, &box);
8252 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8253 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8254 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8255 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8259 clutter_actor_update_constraints (ClutterActor *self,
8260 ClutterActorBox *allocation)
8262 ClutterActorPrivate *priv = self->priv;
8263 const GList *constraints, *l;
8265 if (priv->constraints == NULL)
8268 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8269 for (l = constraints; l != NULL; l = l->next)
8271 ClutterConstraint *constraint = l->data;
8272 ClutterActorMeta *meta = l->data;
8274 if (clutter_actor_meta_get_enabled (meta))
8276 _clutter_constraint_update_allocation (constraint,
8280 CLUTTER_NOTE (LAYOUT,
8281 "Allocation of '%s' after constraint '%s': "
8282 "{ %.2f, %.2f, %.2f, %.2f }",
8283 _clutter_actor_get_debug_name (self),
8284 _clutter_actor_meta_get_debug_name (meta),
8294 * clutter_actor_adjust_allocation:
8295 * @self: a #ClutterActor
8296 * @allocation: (inout): the allocation to adjust
8298 * Adjusts the passed allocation box taking into account the actor's
8299 * layout information, like alignment, expansion, and margin.
8302 clutter_actor_adjust_allocation (ClutterActor *self,
8303 ClutterActorBox *allocation)
8305 ClutterActorBox adj_allocation;
8306 float alloc_width, alloc_height;
8307 float min_width, min_height;
8308 float nat_width, nat_height;
8309 ClutterRequestMode req_mode;
8311 adj_allocation = *allocation;
8313 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8315 /* we want to hit the cache, so we use the public API */
8316 req_mode = clutter_actor_get_request_mode (self);
8318 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8320 clutter_actor_get_preferred_width (self, -1,
8323 clutter_actor_get_preferred_height (self, alloc_width,
8327 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8329 clutter_actor_get_preferred_height (self, -1,
8332 clutter_actor_get_preferred_height (self, alloc_height,
8337 #ifdef CLUTTER_ENABLE_DEBUG
8338 /* warn about underallocations */
8339 if (_clutter_diagnostic_enabled () &&
8340 (floorf (min_width - alloc_width) > 0 ||
8341 floorf (min_height - alloc_height) > 0))
8343 ClutterActor *parent = clutter_actor_get_parent (self);
8345 /* the only actors that are allowed to be underallocated are the Stage,
8346 * as it doesn't have an implicit size, and Actors that specifically
8347 * told us that they want to opt-out from layout control mechanisms
8348 * through the NO_LAYOUT escape hatch.
8350 if (parent != NULL &&
8351 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8353 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8354 "of %.2f x %.2f from its parent actor '%s', but its "
8355 "requested minimum size is of %.2f x %.2f",
8356 _clutter_actor_get_debug_name (self),
8357 alloc_width, alloc_height,
8358 _clutter_actor_get_debug_name (parent),
8359 min_width, min_height);
8364 clutter_actor_adjust_width (self,
8368 &adj_allocation.x2);
8370 clutter_actor_adjust_height (self,
8374 &adj_allocation.y2);
8376 /* we maintain the invariant that an allocation cannot be adjusted
8377 * to be outside the parent-given box
8379 if (adj_allocation.x1 < allocation->x1 ||
8380 adj_allocation.y1 < allocation->y1 ||
8381 adj_allocation.x2 > allocation->x2 ||
8382 adj_allocation.y2 > allocation->y2)
8384 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8385 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8386 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8387 _clutter_actor_get_debug_name (self),
8388 adj_allocation.x1, adj_allocation.y1,
8389 adj_allocation.x2 - adj_allocation.x1,
8390 adj_allocation.y2 - adj_allocation.y1,
8391 allocation->x1, allocation->y1,
8392 allocation->x2 - allocation->x1,
8393 allocation->y2 - allocation->y1);
8397 *allocation = adj_allocation;
8401 * clutter_actor_allocate:
8402 * @self: A #ClutterActor
8403 * @box: new allocation of the actor, in parent-relative coordinates
8404 * @flags: flags that control the allocation
8406 * Called by the parent of an actor to assign the actor its size.
8407 * Should never be called by applications (except when implementing
8408 * a container or layout manager).
8410 * Actors can know from their allocation box whether they have moved
8411 * with respect to their parent actor. The @flags parameter describes
8412 * additional information about the allocation, for instance whether
8413 * the parent has moved with respect to the stage, for example because
8414 * a grandparent's origin has moved.
8419 clutter_actor_allocate (ClutterActor *self,
8420 const ClutterActorBox *box,
8421 ClutterAllocationFlags flags)
8423 ClutterActorPrivate *priv;
8424 ClutterActorClass *klass;
8425 ClutterActorBox old_allocation, real_allocation;
8426 gboolean origin_changed, child_moved, size_changed;
8427 gboolean stage_allocation_changed;
8429 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8430 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8432 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8433 "which isn't a descendent of the stage!\n",
8434 self, _clutter_actor_get_debug_name (self));
8440 old_allocation = priv->allocation;
8441 real_allocation = *box;
8443 /* constraints are allowed to modify the allocation only here; we do
8444 * this prior to all the other checks so that we can bail out if the
8445 * allocation did not change
8447 clutter_actor_update_constraints (self, &real_allocation);
8449 /* adjust the allocation depending on the align/margin properties */
8450 clutter_actor_adjust_allocation (self, &real_allocation);
8452 if (real_allocation.x2 < real_allocation.x1 ||
8453 real_allocation.y2 < real_allocation.y1)
8455 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8456 _clutter_actor_get_debug_name (self),
8457 real_allocation.x2 - real_allocation.x1,
8458 real_allocation.y2 - real_allocation.y1);
8461 /* we allow 0-sized actors, but not negative-sized ones */
8462 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8463 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8465 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8467 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8468 real_allocation.y1 != old_allocation.y1);
8470 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8471 real_allocation.y2 != old_allocation.y2);
8473 if (origin_changed || child_moved || size_changed)
8474 stage_allocation_changed = TRUE;
8476 stage_allocation_changed = FALSE;
8478 /* If we get an allocation "out of the blue"
8479 * (we did not queue relayout), then we want to
8480 * ignore it. But if we have needs_allocation set,
8481 * we want to guarantee that allocate() virtual
8482 * method is always called, i.e. that queue_relayout()
8483 * always results in an allocate() invocation on
8486 * The optimization here is to avoid re-allocating
8487 * actors that did not queue relayout and were
8490 if (!priv->needs_allocation && !stage_allocation_changed)
8492 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8496 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8497 * clutter_actor_allocate(), it indicates whether the parent has its
8498 * absolute origin moved; when passed in to ClutterActor::allocate()
8499 * virtual method though, it indicates whether the child has its
8500 * absolute origin moved. So we set it when child_moved is TRUE
8503 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8505 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8507 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8508 _clutter_actor_get_debug_name (self));
8510 klass = CLUTTER_ACTOR_GET_CLASS (self);
8511 klass->allocate (self, &real_allocation, flags);
8513 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8515 if (stage_allocation_changed)
8516 clutter_actor_queue_redraw (self);
8520 * clutter_actor_set_allocation:
8521 * @self: a #ClutterActor
8522 * @box: a #ClutterActorBox
8523 * @flags: allocation flags
8525 * Stores the allocation of @self as defined by @box.
8527 * This function can only be called from within the implementation of
8528 * the #ClutterActorClass.allocate() virtual function.
8530 * The allocation should have been adjusted to take into account constraints,
8531 * alignment, and margin properties. If you are implementing a #ClutterActor
8532 * subclass that provides its own layout management policy for its children
8533 * instead of using a #ClutterLayoutManager delegate, you should not call
8534 * this function on the children of @self; instead, you should call
8535 * clutter_actor_allocate(), which will adjust the allocation box for
8538 * This function should only be used by subclasses of #ClutterActor
8539 * that wish to store their allocation but cannot chain up to the
8540 * parent's implementation; the default implementation of the
8541 * #ClutterActorClass.allocate() virtual function will call this
8544 * It is important to note that, while chaining up was the recommended
8545 * behaviour for #ClutterActor subclasses prior to the introduction of
8546 * this function, it is recommended to call clutter_actor_set_allocation()
8549 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8550 * to handle the allocation of its children, this function will call
8551 * the clutter_layout_manager_allocate() function only if the
8552 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8553 * expected that the subclass will call clutter_layout_manager_allocate()
8554 * by itself. For instance, the following code:
8558 * my_actor_allocate (ClutterActor *actor,
8559 * const ClutterActorBox *allocation,
8560 * ClutterAllocationFlags flags)
8562 * ClutterActorBox new_alloc;
8563 * ClutterAllocationFlags new_flags;
8565 * adjust_allocation (allocation, &new_alloc);
8567 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8569 * /* this will use the layout manager set on the actor */
8570 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8574 * is equivalent to this:
8578 * my_actor_allocate (ClutterActor *actor,
8579 * const ClutterActorBox *allocation,
8580 * ClutterAllocationFlags flags)
8582 * ClutterLayoutManager *layout;
8583 * ClutterActorBox new_alloc;
8585 * adjust_allocation (allocation, &new_alloc);
8587 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8589 * layout = clutter_actor_get_layout_manager (actor);
8590 * clutter_layout_manager_allocate (layout,
8591 * CLUTTER_CONTAINER (actor),
8600 clutter_actor_set_allocation (ClutterActor *self,
8601 const ClutterActorBox *box,
8602 ClutterAllocationFlags flags)
8604 ClutterActorPrivate *priv;
8607 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8608 g_return_if_fail (box != NULL);
8610 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8612 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8613 "can only be called from within the implementation of "
8614 "the ClutterActor::allocate() virtual function.");
8620 g_object_freeze_notify (G_OBJECT (self));
8622 changed = clutter_actor_set_allocation_internal (self, box, flags);
8624 /* we allocate our children before we notify changes in our geometry,
8625 * so that people connecting to properties will be able to get valid
8626 * data out of the sub-tree of the scene graph that has this actor at
8629 clutter_actor_maybe_layout_children (self, box, flags);
8633 ClutterActorBox signal_box = priv->allocation;
8634 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8636 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8641 g_object_thaw_notify (G_OBJECT (self));
8645 * clutter_actor_set_geometry:
8646 * @self: A #ClutterActor
8647 * @geometry: A #ClutterGeometry
8649 * Sets the actor's fixed position and forces its minimum and natural
8650 * size, in pixels. This means the untransformed actor will have the
8651 * given geometry. This is the same as calling clutter_actor_set_position()
8652 * and clutter_actor_set_size().
8654 * Deprecated: 1.10: Use clutter_actor_set_position() and
8655 * clutter_actor_set_size() instead.
8658 clutter_actor_set_geometry (ClutterActor *self,
8659 const ClutterGeometry *geometry)
8661 g_object_freeze_notify (G_OBJECT (self));
8663 clutter_actor_set_position (self, geometry->x, geometry->y);
8664 clutter_actor_set_size (self, geometry->width, geometry->height);
8666 g_object_thaw_notify (G_OBJECT (self));
8670 * clutter_actor_get_geometry:
8671 * @self: A #ClutterActor
8672 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8674 * Gets the size and position of an actor relative to its parent
8675 * actor. This is the same as calling clutter_actor_get_position() and
8676 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8677 * requested size and position if the actor's allocation is invalid.
8679 * Deprecated: 1.10: Use clutter_actor_get_position() and
8680 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8684 clutter_actor_get_geometry (ClutterActor *self,
8685 ClutterGeometry *geometry)
8687 gfloat x, y, width, height;
8689 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8690 g_return_if_fail (geometry != NULL);
8692 clutter_actor_get_position (self, &x, &y);
8693 clutter_actor_get_size (self, &width, &height);
8695 geometry->x = (int) x;
8696 geometry->y = (int) y;
8697 geometry->width = (int) width;
8698 geometry->height = (int) height;
8702 * clutter_actor_set_position:
8703 * @self: A #ClutterActor
8704 * @x: New left position of actor in pixels.
8705 * @y: New top position of actor in pixels.
8707 * Sets the actor's fixed position in pixels relative to any parent
8710 * If a layout manager is in use, this position will override the
8711 * layout manager and force a fixed position.
8714 clutter_actor_set_position (ClutterActor *self,
8718 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8720 g_object_freeze_notify (G_OBJECT (self));
8722 clutter_actor_set_x (self, x);
8723 clutter_actor_set_y (self, y);
8725 g_object_thaw_notify (G_OBJECT (self));
8729 * clutter_actor_get_fixed_position_set:
8730 * @self: A #ClutterActor
8732 * Checks whether an actor has a fixed position set (and will thus be
8733 * unaffected by any layout manager).
8735 * Return value: %TRUE if the fixed position is set on the actor
8740 clutter_actor_get_fixed_position_set (ClutterActor *self)
8742 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8744 return self->priv->position_set;
8748 * clutter_actor_set_fixed_position_set:
8749 * @self: A #ClutterActor
8750 * @is_set: whether to use fixed position
8752 * Sets whether an actor has a fixed position set (and will thus be
8753 * unaffected by any layout manager).
8758 clutter_actor_set_fixed_position_set (ClutterActor *self,
8761 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8763 if (self->priv->position_set == (is_set != FALSE))
8766 self->priv->position_set = is_set != FALSE;
8767 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8769 clutter_actor_queue_relayout (self);
8773 * clutter_actor_move_by:
8774 * @self: A #ClutterActor
8775 * @dx: Distance to move Actor on X axis.
8776 * @dy: Distance to move Actor on Y axis.
8778 * Moves an actor by the specified distance relative to its current
8779 * position in pixels.
8781 * This function modifies the fixed position of an actor and thus removes
8782 * it from any layout management. Another way to move an actor is with an
8783 * anchor point, see clutter_actor_set_anchor_point().
8788 clutter_actor_move_by (ClutterActor *self,
8792 const ClutterLayoutInfo *info;
8795 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8797 info = _clutter_actor_get_layout_info_or_defaults (self);
8801 clutter_actor_set_position (self, x + dx, y + dy);
8805 clutter_actor_set_min_width (ClutterActor *self,
8808 ClutterActorPrivate *priv = self->priv;
8809 ClutterActorBox old = { 0, };
8810 ClutterLayoutInfo *info;
8812 /* if we are setting the size on a top-level actor and the
8813 * backend only supports static top-levels (e.g. framebuffers)
8814 * then we ignore the passed value and we override it with
8815 * the stage implementation's preferred size.
8817 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8818 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8821 info = _clutter_actor_get_layout_info (self);
8823 if (priv->min_width_set && min_width == info->min_width)
8826 g_object_freeze_notify (G_OBJECT (self));
8828 clutter_actor_store_old_geometry (self, &old);
8830 info->min_width = min_width;
8831 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8832 clutter_actor_set_min_width_set (self, TRUE);
8834 clutter_actor_notify_if_geometry_changed (self, &old);
8836 g_object_thaw_notify (G_OBJECT (self));
8838 clutter_actor_queue_relayout (self);
8842 clutter_actor_set_min_height (ClutterActor *self,
8846 ClutterActorPrivate *priv = self->priv;
8847 ClutterActorBox old = { 0, };
8848 ClutterLayoutInfo *info;
8850 /* if we are setting the size on a top-level actor and the
8851 * backend only supports static top-levels (e.g. framebuffers)
8852 * then we ignore the passed value and we override it with
8853 * the stage implementation's preferred size.
8855 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8856 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8859 info = _clutter_actor_get_layout_info (self);
8861 if (priv->min_height_set && min_height == info->min_height)
8864 g_object_freeze_notify (G_OBJECT (self));
8866 clutter_actor_store_old_geometry (self, &old);
8868 info->min_height = min_height;
8869 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8870 clutter_actor_set_min_height_set (self, TRUE);
8872 clutter_actor_notify_if_geometry_changed (self, &old);
8874 g_object_thaw_notify (G_OBJECT (self));
8876 clutter_actor_queue_relayout (self);
8880 clutter_actor_set_natural_width (ClutterActor *self,
8881 gfloat natural_width)
8883 ClutterActorPrivate *priv = self->priv;
8884 ClutterActorBox old = { 0, };
8885 ClutterLayoutInfo *info;
8887 /* if we are setting the size on a top-level actor and the
8888 * backend only supports static top-levels (e.g. framebuffers)
8889 * then we ignore the passed value and we override it with
8890 * the stage implementation's preferred size.
8892 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8893 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8896 info = _clutter_actor_get_layout_info (self);
8898 if (priv->natural_width_set && natural_width == info->natural_width)
8901 g_object_freeze_notify (G_OBJECT (self));
8903 clutter_actor_store_old_geometry (self, &old);
8905 info->natural_width = natural_width;
8906 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8907 clutter_actor_set_natural_width_set (self, TRUE);
8909 clutter_actor_notify_if_geometry_changed (self, &old);
8911 g_object_thaw_notify (G_OBJECT (self));
8913 clutter_actor_queue_relayout (self);
8917 clutter_actor_set_natural_height (ClutterActor *self,
8918 gfloat natural_height)
8920 ClutterActorPrivate *priv = self->priv;
8921 ClutterActorBox old = { 0, };
8922 ClutterLayoutInfo *info;
8924 /* if we are setting the size on a top-level actor and the
8925 * backend only supports static top-levels (e.g. framebuffers)
8926 * then we ignore the passed value and we override it with
8927 * the stage implementation's preferred size.
8929 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8930 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8933 info = _clutter_actor_get_layout_info (self);
8935 if (priv->natural_height_set && natural_height == info->natural_height)
8938 g_object_freeze_notify (G_OBJECT (self));
8940 clutter_actor_store_old_geometry (self, &old);
8942 info->natural_height = natural_height;
8943 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8944 clutter_actor_set_natural_height_set (self, TRUE);
8946 clutter_actor_notify_if_geometry_changed (self, &old);
8948 g_object_thaw_notify (G_OBJECT (self));
8950 clutter_actor_queue_relayout (self);
8954 clutter_actor_set_min_width_set (ClutterActor *self,
8955 gboolean use_min_width)
8957 ClutterActorPrivate *priv = self->priv;
8958 ClutterActorBox old = { 0, };
8960 if (priv->min_width_set == (use_min_width != FALSE))
8963 clutter_actor_store_old_geometry (self, &old);
8965 priv->min_width_set = use_min_width != FALSE;
8966 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8968 clutter_actor_notify_if_geometry_changed (self, &old);
8970 clutter_actor_queue_relayout (self);
8974 clutter_actor_set_min_height_set (ClutterActor *self,
8975 gboolean use_min_height)
8977 ClutterActorPrivate *priv = self->priv;
8978 ClutterActorBox old = { 0, };
8980 if (priv->min_height_set == (use_min_height != FALSE))
8983 clutter_actor_store_old_geometry (self, &old);
8985 priv->min_height_set = use_min_height != FALSE;
8986 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8988 clutter_actor_notify_if_geometry_changed (self, &old);
8990 clutter_actor_queue_relayout (self);
8994 clutter_actor_set_natural_width_set (ClutterActor *self,
8995 gboolean use_natural_width)
8997 ClutterActorPrivate *priv = self->priv;
8998 ClutterActorBox old = { 0, };
9000 if (priv->natural_width_set == (use_natural_width != FALSE))
9003 clutter_actor_store_old_geometry (self, &old);
9005 priv->natural_width_set = use_natural_width != FALSE;
9006 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9008 clutter_actor_notify_if_geometry_changed (self, &old);
9010 clutter_actor_queue_relayout (self);
9014 clutter_actor_set_natural_height_set (ClutterActor *self,
9015 gboolean use_natural_height)
9017 ClutterActorPrivate *priv = self->priv;
9018 ClutterActorBox old = { 0, };
9020 if (priv->natural_height_set == (use_natural_height != FALSE))
9023 clutter_actor_store_old_geometry (self, &old);
9025 priv->natural_height_set = use_natural_height != FALSE;
9026 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9028 clutter_actor_notify_if_geometry_changed (self, &old);
9030 clutter_actor_queue_relayout (self);
9034 * clutter_actor_set_request_mode:
9035 * @self: a #ClutterActor
9036 * @mode: the request mode
9038 * Sets the geometry request mode of @self.
9040 * The @mode determines the order for invoking
9041 * clutter_actor_get_preferred_width() and
9042 * clutter_actor_get_preferred_height()
9047 clutter_actor_set_request_mode (ClutterActor *self,
9048 ClutterRequestMode mode)
9050 ClutterActorPrivate *priv;
9052 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9056 if (priv->request_mode == mode)
9059 priv->request_mode = mode;
9061 priv->needs_width_request = TRUE;
9062 priv->needs_height_request = TRUE;
9064 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9066 clutter_actor_queue_relayout (self);
9070 * clutter_actor_get_request_mode:
9071 * @self: a #ClutterActor
9073 * Retrieves the geometry request mode of @self
9075 * Return value: the request mode for the actor
9080 clutter_actor_get_request_mode (ClutterActor *self)
9082 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9083 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9085 return self->priv->request_mode;
9088 /* variant of set_width() without checks and without notification
9089 * freeze+thaw, for internal usage only
9092 clutter_actor_set_width_internal (ClutterActor *self,
9097 /* the Stage will use the :min-width to control the minimum
9098 * width to be resized to, so we should not be setting it
9099 * along with the :natural-width
9101 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9102 clutter_actor_set_min_width (self, width);
9104 clutter_actor_set_natural_width (self, width);
9108 /* we only unset the :natural-width for the Stage */
9109 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9110 clutter_actor_set_min_width_set (self, FALSE);
9112 clutter_actor_set_natural_width_set (self, FALSE);
9116 /* variant of set_height() without checks and without notification
9117 * freeze+thaw, for internal usage only
9120 clutter_actor_set_height_internal (ClutterActor *self,
9125 /* see the comment above in set_width_internal() */
9126 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9127 clutter_actor_set_min_height (self, height);
9129 clutter_actor_set_natural_height (self, height);
9133 /* see the comment above in set_width_internal() */
9134 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9135 clutter_actor_set_min_height_set (self, FALSE);
9137 clutter_actor_set_natural_height_set (self, FALSE);
9142 * clutter_actor_set_size:
9143 * @self: A #ClutterActor
9144 * @width: New width of actor in pixels, or -1
9145 * @height: New height of actor in pixels, or -1
9147 * Sets the actor's size request in pixels. This overrides any
9148 * "normal" size request the actor would have. For example
9149 * a text actor might normally request the size of the text;
9150 * this function would force a specific size instead.
9152 * If @width and/or @height are -1 the actor will use its
9153 * "normal" size request instead of overriding it, i.e.
9154 * you can "unset" the size with -1.
9156 * This function sets or unsets both the minimum and natural size.
9159 clutter_actor_set_size (ClutterActor *self,
9163 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9165 g_object_freeze_notify (G_OBJECT (self));
9167 clutter_actor_set_width (self, width);
9168 clutter_actor_set_height (self, height);
9170 g_object_thaw_notify (G_OBJECT (self));
9174 * clutter_actor_get_size:
9175 * @self: A #ClutterActor
9176 * @width: (out) (allow-none): return location for the width, or %NULL.
9177 * @height: (out) (allow-none): return location for the height, or %NULL.
9179 * This function tries to "do what you mean" and return
9180 * the size an actor will have. If the actor has a valid
9181 * allocation, the allocation will be returned; otherwise,
9182 * the actors natural size request will be returned.
9184 * If you care whether you get the request vs. the allocation, you
9185 * should probably call a different function like
9186 * clutter_actor_get_allocation_box() or
9187 * clutter_actor_get_preferred_width().
9192 clutter_actor_get_size (ClutterActor *self,
9196 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9199 *width = clutter_actor_get_width (self);
9202 *height = clutter_actor_get_height (self);
9206 * clutter_actor_get_position:
9207 * @self: a #ClutterActor
9208 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9209 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9211 * This function tries to "do what you mean" and tell you where the
9212 * actor is, prior to any transformations. Retrieves the fixed
9213 * position of an actor in pixels, if one has been set; otherwise, if
9214 * the allocation is valid, returns the actor's allocated position;
9215 * otherwise, returns 0,0.
9217 * The returned position is in pixels.
9222 clutter_actor_get_position (ClutterActor *self,
9226 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9229 *x = clutter_actor_get_x (self);
9232 *y = clutter_actor_get_y (self);
9236 * clutter_actor_get_transformed_position:
9237 * @self: A #ClutterActor
9238 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9239 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9241 * Gets the absolute position of an actor, in pixels relative to the stage.
9246 clutter_actor_get_transformed_position (ClutterActor *self,
9253 v1.x = v1.y = v1.z = 0;
9254 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9264 * clutter_actor_get_transformed_size:
9265 * @self: A #ClutterActor
9266 * @width: (out) (allow-none): return location for the width, or %NULL
9267 * @height: (out) (allow-none): return location for the height, or %NULL
9269 * Gets the absolute size of an actor in pixels, taking into account the
9272 * If the actor has a valid allocation, the allocated size will be used.
9273 * If the actor has not a valid allocation then the preferred size will
9274 * be transformed and returned.
9276 * If you want the transformed allocation, see
9277 * clutter_actor_get_abs_allocation_vertices() instead.
9279 * <note>When the actor (or one of its ancestors) is rotated around the
9280 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9281 * as a generic quadrangle; in that case this function returns the size
9282 * of the smallest rectangle that encapsulates the entire quad. Please
9283 * note that in this case no assumptions can be made about the relative
9284 * position of this envelope to the absolute position of the actor, as
9285 * returned by clutter_actor_get_transformed_position(); if you need this
9286 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9287 * to get the coords of the actual quadrangle.</note>
9292 clutter_actor_get_transformed_size (ClutterActor *self,
9296 ClutterActorPrivate *priv;
9298 gfloat x_min, x_max, y_min, y_max;
9301 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9305 /* if the actor hasn't been allocated yet, get the preferred
9306 * size and transform that
9308 if (priv->needs_allocation)
9310 gfloat natural_width, natural_height;
9311 ClutterActorBox box;
9313 /* Make a fake allocation to transform.
9315 * NB: _clutter_actor_transform_and_project_box expects a box in
9316 * the actor's coordinate space... */
9321 natural_width = natural_height = 0;
9322 clutter_actor_get_preferred_size (self, NULL, NULL,
9326 box.x2 = natural_width;
9327 box.y2 = natural_height;
9329 _clutter_actor_transform_and_project_box (self, &box, v);
9332 clutter_actor_get_abs_allocation_vertices (self, v);
9334 x_min = x_max = v[0].x;
9335 y_min = y_max = v[0].y;
9337 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9353 *width = x_max - x_min;
9356 *height = y_max - y_min;
9360 * clutter_actor_get_width:
9361 * @self: A #ClutterActor
9363 * Retrieves the width of a #ClutterActor.
9365 * If the actor has a valid allocation, this function will return the
9366 * width of the allocated area given to the actor.
9368 * If the actor does not have a valid allocation, this function will
9369 * return the actor's natural width, that is the preferred width of
9372 * If you care whether you get the preferred width or the width that
9373 * has been assigned to the actor, you should probably call a different
9374 * function like clutter_actor_get_allocation_box() to retrieve the
9375 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9378 * If an actor has a fixed width, for instance a width that has been
9379 * assigned using clutter_actor_set_width(), the width returned will
9380 * be the same value.
9382 * Return value: the width of the actor, in pixels
9385 clutter_actor_get_width (ClutterActor *self)
9387 ClutterActorPrivate *priv;
9389 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9393 if (priv->needs_allocation)
9395 gfloat natural_width = 0;
9397 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9398 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9401 gfloat natural_height = 0;
9403 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9404 clutter_actor_get_preferred_width (self, natural_height,
9409 return natural_width;
9412 return priv->allocation.x2 - priv->allocation.x1;
9416 * clutter_actor_get_height:
9417 * @self: A #ClutterActor
9419 * Retrieves the height of a #ClutterActor.
9421 * If the actor has a valid allocation, this function will return the
9422 * height of the allocated area given to the actor.
9424 * If the actor does not have a valid allocation, this function will
9425 * return the actor's natural height, that is the preferred height of
9428 * If you care whether you get the preferred height or the height that
9429 * has been assigned to the actor, you should probably call a different
9430 * function like clutter_actor_get_allocation_box() to retrieve the
9431 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9434 * If an actor has a fixed height, for instance a height that has been
9435 * assigned using clutter_actor_set_height(), the height returned will
9436 * be the same value.
9438 * Return value: the height of the actor, in pixels
9441 clutter_actor_get_height (ClutterActor *self)
9443 ClutterActorPrivate *priv;
9445 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9449 if (priv->needs_allocation)
9451 gfloat natural_height = 0;
9453 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9455 gfloat natural_width = 0;
9457 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9458 clutter_actor_get_preferred_height (self, natural_width,
9459 NULL, &natural_height);
9462 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9464 return natural_height;
9467 return priv->allocation.y2 - priv->allocation.y1;
9471 * clutter_actor_set_width:
9472 * @self: A #ClutterActor
9473 * @width: Requested new width for the actor, in pixels, or -1
9475 * Forces a width on an actor, causing the actor's preferred width
9476 * and height (if any) to be ignored.
9478 * If @width is -1 the actor will use its preferred width request
9479 * instead of overriding it, i.e. you can "unset" the width with -1.
9481 * This function sets both the minimum and natural size of the actor.
9486 clutter_actor_set_width (ClutterActor *self,
9489 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9491 if (clutter_actor_get_easing_duration (self) != 0)
9493 ClutterTransition *transition;
9495 transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9496 if (transition == NULL)
9498 float old_width = clutter_actor_get_width (self);
9500 transition = _clutter_actor_create_transition (self,
9501 obj_props[PROP_WIDTH],
9506 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9508 clutter_actor_queue_relayout (self);
9512 g_object_freeze_notify (G_OBJECT (self));
9514 clutter_actor_set_width_internal (self, width);
9516 g_object_thaw_notify (G_OBJECT (self));
9521 * clutter_actor_set_height:
9522 * @self: A #ClutterActor
9523 * @height: Requested new height for the actor, in pixels, or -1
9525 * Forces a height on an actor, causing the actor's preferred width
9526 * and height (if any) to be ignored.
9528 * If @height is -1 the actor will use its preferred height instead of
9529 * overriding it, i.e. you can "unset" the height with -1.
9531 * This function sets both the minimum and natural size of the actor.
9536 clutter_actor_set_height (ClutterActor *self,
9539 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9541 if (clutter_actor_get_easing_duration (self) != 0)
9543 ClutterTransition *transition;
9545 transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9546 if (transition == NULL)
9548 float old_height = clutter_actor_get_height (self);
9550 transition = _clutter_actor_create_transition (self,
9551 obj_props[PROP_HEIGHT],
9556 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9558 clutter_actor_queue_relayout (self);
9562 g_object_freeze_notify (G_OBJECT (self));
9564 clutter_actor_set_height_internal (self, height);
9566 g_object_thaw_notify (G_OBJECT (self));
9571 clutter_actor_set_x_internal (ClutterActor *self,
9574 ClutterActorPrivate *priv = self->priv;
9575 ClutterLayoutInfo *linfo;
9576 ClutterActorBox old = { 0, };
9578 linfo = _clutter_actor_get_layout_info (self);
9580 if (priv->position_set && linfo->fixed_x == x)
9583 clutter_actor_store_old_geometry (self, &old);
9586 clutter_actor_set_fixed_position_set (self, TRUE);
9588 clutter_actor_notify_if_geometry_changed (self, &old);
9590 clutter_actor_queue_relayout (self);
9594 clutter_actor_set_y_internal (ClutterActor *self,
9597 ClutterActorPrivate *priv = self->priv;
9598 ClutterLayoutInfo *linfo;
9599 ClutterActorBox old = { 0, };
9601 linfo = _clutter_actor_get_layout_info (self);
9603 if (priv->position_set && linfo->fixed_y == y)
9606 clutter_actor_store_old_geometry (self, &old);
9609 clutter_actor_set_fixed_position_set (self, TRUE);
9611 clutter_actor_notify_if_geometry_changed (self, &old);
9613 clutter_actor_queue_relayout (self);
9617 * clutter_actor_set_x:
9618 * @self: a #ClutterActor
9619 * @x: the actor's position on the X axis
9621 * Sets the actor's X coordinate, relative to its parent, in pixels.
9623 * Overrides any layout manager and forces a fixed position for
9626 * The #ClutterActor:x property is animatable.
9631 clutter_actor_set_x (ClutterActor *self,
9634 const ClutterLayoutInfo *linfo;
9636 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9638 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9640 if (clutter_actor_get_easing_duration (self) != 0)
9642 ClutterTransition *transition;
9644 transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9645 if (transition == NULL)
9647 transition = _clutter_actor_create_transition (self,
9653 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9655 clutter_actor_queue_relayout (self);
9658 clutter_actor_set_x_internal (self, x);
9662 * clutter_actor_set_y:
9663 * @self: a #ClutterActor
9664 * @y: the actor's position on the Y axis
9666 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9668 * Overrides any layout manager and forces a fixed position for
9671 * The #ClutterActor:y property is animatable.
9676 clutter_actor_set_y (ClutterActor *self,
9679 const ClutterLayoutInfo *linfo;
9681 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9683 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9685 if (clutter_actor_get_easing_duration (self) != 0)
9687 ClutterTransition *transition;
9689 transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9690 if (transition == NULL)
9692 transition = _clutter_actor_create_transition (self,
9698 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9700 clutter_actor_queue_relayout (self);
9703 clutter_actor_set_y_internal (self, y);
9705 clutter_actor_queue_relayout (self);
9709 * clutter_actor_get_x:
9710 * @self: A #ClutterActor
9712 * Retrieves the X coordinate of a #ClutterActor.
9714 * This function tries to "do what you mean", by returning the
9715 * correct value depending on the actor's state.
9717 * If the actor has a valid allocation, this function will return
9718 * the X coordinate of the origin of the allocation box.
9720 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9721 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9722 * function will return that coordinate.
9724 * If both the allocation and a fixed position are missing, this function
9727 * Return value: the X coordinate, in pixels, ignoring any
9728 * transformation (i.e. scaling, rotation)
9731 clutter_actor_get_x (ClutterActor *self)
9733 ClutterActorPrivate *priv;
9735 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9739 if (priv->needs_allocation)
9741 if (priv->position_set)
9743 const ClutterLayoutInfo *info;
9745 info = _clutter_actor_get_layout_info_or_defaults (self);
9747 return info->fixed_x;
9753 return priv->allocation.x1;
9757 * clutter_actor_get_y:
9758 * @self: A #ClutterActor
9760 * Retrieves the Y coordinate of a #ClutterActor.
9762 * This function tries to "do what you mean", by returning the
9763 * correct value depending on the actor's state.
9765 * If the actor has a valid allocation, this function will return
9766 * the Y coordinate of the origin of the allocation box.
9768 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9769 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9770 * function will return that coordinate.
9772 * If both the allocation and a fixed position are missing, this function
9775 * Return value: the Y coordinate, in pixels, ignoring any
9776 * transformation (i.e. scaling, rotation)
9779 clutter_actor_get_y (ClutterActor *self)
9781 ClutterActorPrivate *priv;
9783 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9787 if (priv->needs_allocation)
9789 if (priv->position_set)
9791 const ClutterLayoutInfo *info;
9793 info = _clutter_actor_get_layout_info_or_defaults (self);
9795 return info->fixed_y;
9801 return priv->allocation.y1;
9805 * clutter_actor_set_scale:
9806 * @self: A #ClutterActor
9807 * @scale_x: double factor to scale actor by horizontally.
9808 * @scale_y: double factor to scale actor by vertically.
9810 * Scales an actor with the given factors. The scaling is relative to
9811 * the scale center and the anchor point. The scale center is
9812 * unchanged by this function and defaults to 0,0.
9814 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9820 clutter_actor_set_scale (ClutterActor *self,
9824 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9826 g_object_freeze_notify (G_OBJECT (self));
9828 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9829 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9831 g_object_thaw_notify (G_OBJECT (self));
9835 * clutter_actor_set_scale_full:
9836 * @self: A #ClutterActor
9837 * @scale_x: double factor to scale actor by horizontally.
9838 * @scale_y: double factor to scale actor by vertically.
9839 * @center_x: X coordinate of the center of the scale.
9840 * @center_y: Y coordinate of the center of the scale
9842 * Scales an actor with the given factors around the given center
9843 * point. The center point is specified in pixels relative to the
9844 * anchor point (usually the top left corner of the actor).
9846 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9852 clutter_actor_set_scale_full (ClutterActor *self,
9858 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9860 g_object_freeze_notify (G_OBJECT (self));
9862 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9863 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9864 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9865 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9867 g_object_thaw_notify (G_OBJECT (self));
9871 * clutter_actor_set_scale_with_gravity:
9872 * @self: A #ClutterActor
9873 * @scale_x: double factor to scale actor by horizontally.
9874 * @scale_y: double factor to scale actor by vertically.
9875 * @gravity: the location of the scale center expressed as a compass
9878 * Scales an actor with the given factors around the given
9879 * center point. The center point is specified as one of the compass
9880 * directions in #ClutterGravity. For example, setting it to north
9881 * will cause the top of the actor to remain unchanged and the rest of
9882 * the actor to expand left, right and downwards.
9884 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9890 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9893 ClutterGravity gravity)
9895 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9897 g_object_freeze_notify (G_OBJECT (self));
9899 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9900 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9901 clutter_actor_set_scale_gravity (self, gravity);
9903 g_object_thaw_notify (G_OBJECT (self));
9907 * clutter_actor_get_scale:
9908 * @self: A #ClutterActor
9909 * @scale_x: (out) (allow-none): Location to store horizonal
9910 * scale factor, or %NULL.
9911 * @scale_y: (out) (allow-none): Location to store vertical
9912 * scale factor, or %NULL.
9914 * Retrieves an actors scale factors.
9919 clutter_actor_get_scale (ClutterActor *self,
9923 const ClutterTransformInfo *info;
9925 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9927 info = _clutter_actor_get_transform_info_or_defaults (self);
9930 *scale_x = info->scale_x;
9933 *scale_y = info->scale_y;
9937 * clutter_actor_get_scale_center:
9938 * @self: A #ClutterActor
9939 * @center_x: (out) (allow-none): Location to store the X position
9940 * of the scale center, or %NULL.
9941 * @center_y: (out) (allow-none): Location to store the Y position
9942 * of the scale center, or %NULL.
9944 * Retrieves the scale center coordinate in pixels relative to the top
9945 * left corner of the actor. If the scale center was specified using a
9946 * #ClutterGravity this will calculate the pixel offset using the
9947 * current size of the actor.
9952 clutter_actor_get_scale_center (ClutterActor *self,
9956 const ClutterTransformInfo *info;
9958 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9960 info = _clutter_actor_get_transform_info_or_defaults (self);
9962 clutter_anchor_coord_get_units (self, &info->scale_center,
9969 * clutter_actor_get_scale_gravity:
9970 * @self: A #ClutterActor
9972 * Retrieves the scale center as a compass direction. If the scale
9973 * center was specified in pixels or units this will return
9974 * %CLUTTER_GRAVITY_NONE.
9976 * Return value: the scale gravity
9981 clutter_actor_get_scale_gravity (ClutterActor *self)
9983 const ClutterTransformInfo *info;
9985 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9987 info = _clutter_actor_get_transform_info_or_defaults (self);
9989 return clutter_anchor_coord_get_gravity (&info->scale_center);
9993 clutter_actor_set_opacity_internal (ClutterActor *self,
9996 ClutterActorPrivate *priv = self->priv;
9998 if (priv->opacity != opacity)
10000 priv->opacity = opacity;
10002 /* Queue a redraw from the flatten effect so that it can use
10003 its cached image if available instead of having to redraw the
10004 actual actor. If it doesn't end up using the FBO then the
10005 effect is still able to continue the paint anyway. If there
10006 is no flatten effect yet then this is equivalent to queueing
10008 _clutter_actor_queue_redraw_full (self,
10011 priv->flatten_effect);
10013 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10018 * clutter_actor_set_opacity:
10019 * @self: A #ClutterActor
10020 * @opacity: New opacity value for the actor.
10022 * Sets the actor's opacity, with zero being completely transparent and
10023 * 255 (0xff) being fully opaque.
10025 * The #ClutterActor:opacity property is animatable.
10028 clutter_actor_set_opacity (ClutterActor *self,
10031 ClutterActorPrivate *priv;
10033 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10037 if (clutter_actor_get_easing_duration (self) != 0)
10039 ClutterTransition *transition;
10041 transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
10042 if (transition == NULL)
10044 transition = _clutter_actor_create_transition (self,
10045 obj_props[PROP_OPACITY],
10050 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10052 clutter_actor_queue_redraw (self);
10055 clutter_actor_set_opacity_internal (self, opacity);
10059 * clutter_actor_get_paint_opacity_internal:
10060 * @self: a #ClutterActor
10062 * Retrieves the absolute opacity of the actor, as it appears on the stage
10064 * This function does not do type checks
10066 * Return value: the absolute opacity of the actor
10069 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10071 ClutterActorPrivate *priv = self->priv;
10072 ClutterActor *parent;
10074 /* override the top-level opacity to always be 255; even in
10075 * case of ClutterStage:use-alpha being TRUE we want the rest
10076 * of the scene to be painted
10078 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10081 if (priv->opacity_override >= 0)
10082 return priv->opacity_override;
10084 parent = priv->parent;
10086 /* Factor in the actual actors opacity with parents */
10087 if (parent != NULL)
10089 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10091 if (opacity != 0xff)
10092 return (opacity * priv->opacity) / 0xff;
10095 return priv->opacity;
10100 * clutter_actor_get_paint_opacity:
10101 * @self: A #ClutterActor
10103 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10105 * This function traverses the hierarchy chain and composites the opacity of
10106 * the actor with that of its parents.
10108 * This function is intended for subclasses to use in the paint virtual
10109 * function, to paint themselves with the correct opacity.
10111 * Return value: The actor opacity value.
10116 clutter_actor_get_paint_opacity (ClutterActor *self)
10118 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10120 return clutter_actor_get_paint_opacity_internal (self);
10124 * clutter_actor_get_opacity:
10125 * @self: a #ClutterActor
10127 * Retrieves the opacity value of an actor, as set by
10128 * clutter_actor_set_opacity().
10130 * For retrieving the absolute opacity of the actor inside a paint
10131 * virtual function, see clutter_actor_get_paint_opacity().
10133 * Return value: the opacity of the actor
10136 clutter_actor_get_opacity (ClutterActor *self)
10138 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10140 return self->priv->opacity;
10144 * clutter_actor_set_offscreen_redirect:
10145 * @self: A #ClutterActor
10146 * @redirect: New offscreen redirect flags for the actor.
10148 * Defines the circumstances where the actor should be redirected into
10149 * an offscreen image. The offscreen image is used to flatten the
10150 * actor into a single image while painting for two main reasons.
10151 * Firstly, when the actor is painted a second time without any of its
10152 * contents changing it can simply repaint the cached image without
10153 * descending further down the actor hierarchy. Secondly, it will make
10154 * the opacity look correct even if there are overlapping primitives
10157 * Caching the actor could in some cases be a performance win and in
10158 * some cases be a performance lose so it is important to determine
10159 * which value is right for an actor before modifying this value. For
10160 * example, there is never any reason to flatten an actor that is just
10161 * a single texture (such as a #ClutterTexture) because it is
10162 * effectively already cached in an image so the offscreen would be
10163 * redundant. Also if the actor contains primitives that are far apart
10164 * with a large transparent area in the middle (such as a large
10165 * CluterGroup with a small actor in the top left and a small actor in
10166 * the bottom right) then the cached image will contain the entire
10167 * image of the large area and the paint will waste time blending all
10168 * of the transparent pixels in the middle.
10170 * The default method of implementing opacity on a container simply
10171 * forwards on the opacity to all of the children. If the children are
10172 * overlapping then it will appear as if they are two separate glassy
10173 * objects and there will be a break in the color where they
10174 * overlap. By redirecting to an offscreen buffer it will be as if the
10175 * two opaque objects are combined into one and then made transparent
10176 * which is usually what is expected.
10178 * The image below demonstrates the difference between redirecting and
10179 * not. The image shows two Clutter groups, each containing a red and
10180 * a green rectangle which overlap. The opacity on the group is set to
10181 * 128 (which is 50%). When the offscreen redirect is not used, the
10182 * red rectangle can be seen through the blue rectangle as if the two
10183 * rectangles were separately transparent. When the redirect is used
10184 * the group as a whole is transparent instead so the red rectangle is
10185 * not visible where they overlap.
10187 * <figure id="offscreen-redirect">
10188 * <title>Sample of using an offscreen redirect for transparency</title>
10189 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10192 * The default value for this property is 0, so we effectively will
10193 * never redirect an actor offscreen by default. This means that there
10194 * are times that transparent actors may look glassy as described
10195 * above. The reason this is the default is because there is a
10196 * performance trade off between quality and performance here. In many
10197 * cases the default form of glassy opacity looks good enough, but if
10198 * it's not you will need to set the
10199 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10200 * redirection for opacity.
10202 * Custom actors that don't contain any overlapping primitives are
10203 * recommended to override the has_overlaps() virtual to return %FALSE
10204 * for maximum efficiency.
10209 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10210 ClutterOffscreenRedirect redirect)
10212 ClutterActorPrivate *priv;
10214 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10218 if (priv->offscreen_redirect != redirect)
10220 priv->offscreen_redirect = redirect;
10222 /* Queue a redraw from the effect so that it can use its cached
10223 image if available instead of having to redraw the actual
10224 actor. If it doesn't end up using the FBO then the effect is
10225 still able to continue the paint anyway. If there is no
10226 effect then this is equivalent to queuing a full redraw */
10227 _clutter_actor_queue_redraw_full (self,
10230 priv->flatten_effect);
10232 g_object_notify_by_pspec (G_OBJECT (self),
10233 obj_props[PROP_OFFSCREEN_REDIRECT]);
10238 * clutter_actor_get_offscreen_redirect:
10239 * @self: a #ClutterActor
10241 * Retrieves whether to redirect the actor to an offscreen buffer, as
10242 * set by clutter_actor_set_offscreen_redirect().
10244 * Return value: the value of the offscreen-redirect property of the actor
10248 ClutterOffscreenRedirect
10249 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10251 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10253 return self->priv->offscreen_redirect;
10257 * clutter_actor_set_name:
10258 * @self: A #ClutterActor
10259 * @name: Textual tag to apply to actor
10261 * Sets the given name to @self. The name can be used to identify
10265 clutter_actor_set_name (ClutterActor *self,
10268 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10270 g_free (self->priv->name);
10271 self->priv->name = g_strdup (name);
10273 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10277 * clutter_actor_get_name:
10278 * @self: A #ClutterActor
10280 * Retrieves the name of @self.
10282 * Return value: the name of the actor, or %NULL. The returned string is
10283 * owned by the actor and should not be modified or freed.
10286 clutter_actor_get_name (ClutterActor *self)
10288 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10290 return self->priv->name;
10294 * clutter_actor_get_gid:
10295 * @self: A #ClutterActor
10297 * Retrieves the unique id for @self.
10299 * Return value: Globally unique value for this object instance.
10303 * Deprecated: 1.8: The id is not used any longer.
10306 clutter_actor_get_gid (ClutterActor *self)
10308 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10310 return self->priv->id;
10314 clutter_actor_set_depth_internal (ClutterActor *self,
10317 ClutterTransformInfo *info;
10319 info = _clutter_actor_get_transform_info (self);
10321 if (info->depth != depth)
10323 /* Sets Z value - XXX 2.0: should we invert? */
10324 info->depth = depth;
10326 self->priv->transform_valid = FALSE;
10328 /* FIXME - remove this crap; sadly, there are still containers
10329 * in Clutter that depend on this utter brain damage
10331 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10333 clutter_actor_queue_redraw (self);
10335 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10340 * clutter_actor_set_depth:
10341 * @self: a #ClutterActor
10344 * Sets the Z coordinate of @self to @depth.
10346 * The unit used by @depth is dependant on the perspective setup. See
10347 * also clutter_stage_set_perspective().
10350 clutter_actor_set_depth (ClutterActor *self,
10353 const ClutterTransformInfo *tinfo;
10355 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10357 tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10359 if (clutter_actor_get_easing_duration (self) != 0)
10361 ClutterTransition *transition;
10363 transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10364 if (transition == NULL)
10366 transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10371 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10373 clutter_actor_queue_redraw (self);
10376 clutter_actor_set_depth_internal (self, depth);
10380 * clutter_actor_get_depth:
10381 * @self: a #ClutterActor
10383 * Retrieves the depth of @self.
10385 * Return value: the depth of the actor
10388 clutter_actor_get_depth (ClutterActor *self)
10390 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10392 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10396 * clutter_actor_set_rotation:
10397 * @self: a #ClutterActor
10398 * @axis: the axis of rotation
10399 * @angle: the angle of rotation
10400 * @x: X coordinate of the rotation center
10401 * @y: Y coordinate of the rotation center
10402 * @z: Z coordinate of the rotation center
10404 * Sets the rotation angle of @self around the given axis.
10406 * The rotation center coordinates used depend on the value of @axis:
10408 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10409 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10410 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10413 * The rotation coordinates are relative to the anchor point of the
10414 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10415 * point is set, the upper left corner is assumed as the origin.
10420 clutter_actor_set_rotation (ClutterActor *self,
10421 ClutterRotateAxis axis,
10429 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10435 g_object_freeze_notify (G_OBJECT (self));
10437 clutter_actor_set_rotation_angle (self, axis, angle);
10438 clutter_actor_set_rotation_center_internal (self, axis, &v);
10440 g_object_thaw_notify (G_OBJECT (self));
10444 * clutter_actor_set_z_rotation_from_gravity:
10445 * @self: a #ClutterActor
10446 * @angle: the angle of rotation
10447 * @gravity: the center point of the rotation
10449 * Sets the rotation angle of @self around the Z axis using the center
10450 * point specified as a compass point. For example to rotate such that
10451 * the center of the actor remains static you can use
10452 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10453 * will move accordingly.
10458 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10460 ClutterGravity gravity)
10462 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10464 if (gravity == CLUTTER_GRAVITY_NONE)
10465 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10468 GObject *obj = G_OBJECT (self);
10469 ClutterTransformInfo *info;
10471 info = _clutter_actor_get_transform_info (self);
10473 g_object_freeze_notify (obj);
10475 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10477 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10478 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10479 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10481 g_object_thaw_notify (obj);
10486 * clutter_actor_get_rotation:
10487 * @self: a #ClutterActor
10488 * @axis: the axis of rotation
10489 * @x: (out): return value for the X coordinate of the center of rotation
10490 * @y: (out): return value for the Y coordinate of the center of rotation
10491 * @z: (out): return value for the Z coordinate of the center of rotation
10493 * Retrieves the angle and center of rotation on the given axis,
10494 * set using clutter_actor_set_rotation().
10496 * Return value: the angle of rotation
10501 clutter_actor_get_rotation (ClutterActor *self,
10502 ClutterRotateAxis axis,
10507 const ClutterTransformInfo *info;
10508 const AnchorCoord *anchor_coord;
10509 gdouble retval = 0;
10511 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10513 info = _clutter_actor_get_transform_info_or_defaults (self);
10517 case CLUTTER_X_AXIS:
10518 anchor_coord = &info->rx_center;
10519 retval = info->rx_angle;
10522 case CLUTTER_Y_AXIS:
10523 anchor_coord = &info->ry_center;
10524 retval = info->ry_angle;
10527 case CLUTTER_Z_AXIS:
10528 anchor_coord = &info->rz_center;
10529 retval = info->rz_angle;
10533 anchor_coord = NULL;
10538 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10544 * clutter_actor_get_z_rotation_gravity:
10545 * @self: A #ClutterActor
10547 * Retrieves the center for the rotation around the Z axis as a
10548 * compass direction. If the center was specified in pixels or units
10549 * this will return %CLUTTER_GRAVITY_NONE.
10551 * Return value: the Z rotation center
10556 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10558 const ClutterTransformInfo *info;
10560 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10562 info = _clutter_actor_get_transform_info_or_defaults (self);
10564 return clutter_anchor_coord_get_gravity (&info->rz_center);
10568 * clutter_actor_set_clip:
10569 * @self: A #ClutterActor
10570 * @xoff: X offset of the clip rectangle
10571 * @yoff: Y offset of the clip rectangle
10572 * @width: Width of the clip rectangle
10573 * @height: Height of the clip rectangle
10575 * Sets clip area for @self. The clip area is always computed from the
10576 * upper left corner of the actor, even if the anchor point is set
10582 clutter_actor_set_clip (ClutterActor *self,
10588 ClutterActorPrivate *priv;
10590 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10594 if (priv->has_clip &&
10595 priv->clip.x == xoff &&
10596 priv->clip.y == yoff &&
10597 priv->clip.width == width &&
10598 priv->clip.height == height)
10601 priv->clip.x = xoff;
10602 priv->clip.y = yoff;
10603 priv->clip.width = width;
10604 priv->clip.height = height;
10606 priv->has_clip = TRUE;
10608 clutter_actor_queue_redraw (self);
10610 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10611 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10615 * clutter_actor_remove_clip:
10616 * @self: A #ClutterActor
10618 * Removes clip area from @self.
10621 clutter_actor_remove_clip (ClutterActor *self)
10623 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10625 if (!self->priv->has_clip)
10628 self->priv->has_clip = FALSE;
10630 clutter_actor_queue_redraw (self);
10632 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10636 * clutter_actor_has_clip:
10637 * @self: a #ClutterActor
10639 * Determines whether the actor has a clip area set or not.
10641 * Return value: %TRUE if the actor has a clip area set.
10646 clutter_actor_has_clip (ClutterActor *self)
10648 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10650 return self->priv->has_clip;
10654 * clutter_actor_get_clip:
10655 * @self: a #ClutterActor
10656 * @xoff: (out) (allow-none): return location for the X offset of
10657 * the clip rectangle, or %NULL
10658 * @yoff: (out) (allow-none): return location for the Y offset of
10659 * the clip rectangle, or %NULL
10660 * @width: (out) (allow-none): return location for the width of
10661 * the clip rectangle, or %NULL
10662 * @height: (out) (allow-none): return location for the height of
10663 * the clip rectangle, or %NULL
10665 * Gets the clip area for @self, if any is set
10670 clutter_actor_get_clip (ClutterActor *self,
10676 ClutterActorPrivate *priv;
10678 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10682 if (!priv->has_clip)
10686 *xoff = priv->clip.x;
10689 *yoff = priv->clip.y;
10692 *width = priv->clip.width;
10694 if (height != NULL)
10695 *height = priv->clip.height;
10699 * clutter_actor_get_children:
10700 * @self: a #ClutterActor
10702 * Retrieves the list of children of @self.
10704 * Return value: (transfer container) (element-type ClutterActor): A newly
10705 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10711 clutter_actor_get_children (ClutterActor *self)
10713 ClutterActor *iter;
10716 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10718 /* we walk the list backward so that we can use prepend(),
10721 for (iter = self->priv->last_child, res = NULL;
10723 iter = iter->priv->prev_sibling)
10725 res = g_list_prepend (res, iter);
10732 * insert_child_at_depth:
10733 * @self: a #ClutterActor
10734 * @child: a #ClutterActor
10736 * Inserts @child inside the list of children held by @self, using
10737 * the depth as the insertion criteria.
10739 * This sadly makes the insertion not O(1), but we can keep the
10740 * list sorted so that the painters algorithm we use for painting
10741 * the children will work correctly.
10744 insert_child_at_depth (ClutterActor *self,
10745 ClutterActor *child,
10746 gpointer dummy G_GNUC_UNUSED)
10748 ClutterActor *iter;
10751 child->priv->parent = self;
10754 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10756 /* special-case the first child */
10757 if (self->priv->n_children == 0)
10759 self->priv->first_child = child;
10760 self->priv->last_child = child;
10762 child->priv->next_sibling = NULL;
10763 child->priv->prev_sibling = NULL;
10768 /* Find the right place to insert the child so that it will still be
10769 sorted and the child will be after all of the actors at the same
10771 for (iter = self->priv->first_child;
10773 iter = iter->priv->next_sibling)
10778 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10780 if (iter_depth > child_depth)
10786 ClutterActor *tmp = iter->priv->prev_sibling;
10789 tmp->priv->next_sibling = child;
10791 /* Insert the node before the found one */
10792 child->priv->prev_sibling = iter->priv->prev_sibling;
10793 child->priv->next_sibling = iter;
10794 iter->priv->prev_sibling = child;
10798 ClutterActor *tmp = self->priv->last_child;
10801 tmp->priv->next_sibling = child;
10803 /* insert the node at the end of the list */
10804 child->priv->prev_sibling = self->priv->last_child;
10805 child->priv->next_sibling = NULL;
10808 if (child->priv->prev_sibling == NULL)
10809 self->priv->first_child = child;
10811 if (child->priv->next_sibling == NULL)
10812 self->priv->last_child = child;
10816 insert_child_at_index (ClutterActor *self,
10817 ClutterActor *child,
10820 gint index_ = GPOINTER_TO_INT (data_);
10822 child->priv->parent = self;
10826 ClutterActor *tmp = self->priv->first_child;
10829 tmp->priv->prev_sibling = child;
10831 child->priv->prev_sibling = NULL;
10832 child->priv->next_sibling = tmp;
10834 else if (index_ < 0 || index_ >= self->priv->n_children)
10836 ClutterActor *tmp = self->priv->last_child;
10839 tmp->priv->next_sibling = child;
10841 child->priv->prev_sibling = tmp;
10842 child->priv->next_sibling = NULL;
10846 ClutterActor *iter;
10849 for (iter = self->priv->first_child, i = 0;
10851 iter = iter->priv->next_sibling, i += 1)
10855 ClutterActor *tmp = iter->priv->prev_sibling;
10857 child->priv->prev_sibling = tmp;
10858 child->priv->next_sibling = iter;
10860 iter->priv->prev_sibling = child;
10863 tmp->priv->next_sibling = child;
10870 if (child->priv->prev_sibling == NULL)
10871 self->priv->first_child = child;
10873 if (child->priv->next_sibling == NULL)
10874 self->priv->last_child = child;
10878 insert_child_above (ClutterActor *self,
10879 ClutterActor *child,
10882 ClutterActor *sibling = data;
10884 child->priv->parent = self;
10886 if (sibling == NULL)
10887 sibling = self->priv->last_child;
10889 child->priv->prev_sibling = sibling;
10891 if (sibling != NULL)
10893 ClutterActor *tmp = sibling->priv->next_sibling;
10895 child->priv->next_sibling = tmp;
10898 tmp->priv->prev_sibling = child;
10900 sibling->priv->next_sibling = child;
10903 child->priv->next_sibling = NULL;
10905 if (child->priv->prev_sibling == NULL)
10906 self->priv->first_child = child;
10908 if (child->priv->next_sibling == NULL)
10909 self->priv->last_child = child;
10913 insert_child_below (ClutterActor *self,
10914 ClutterActor *child,
10917 ClutterActor *sibling = data;
10919 child->priv->parent = self;
10921 if (sibling == NULL)
10922 sibling = self->priv->first_child;
10924 child->priv->next_sibling = sibling;
10926 if (sibling != NULL)
10928 ClutterActor *tmp = sibling->priv->prev_sibling;
10930 child->priv->prev_sibling = tmp;
10933 tmp->priv->next_sibling = child;
10935 sibling->priv->prev_sibling = child;
10938 child->priv->prev_sibling = NULL;
10940 if (child->priv->prev_sibling == NULL)
10941 self->priv->first_child = child;
10943 if (child->priv->next_sibling == NULL)
10944 self->priv->last_child = child;
10947 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10948 ClutterActor *child,
10952 ADD_CHILD_CREATE_META = 1 << 0,
10953 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10954 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10955 ADD_CHILD_CHECK_STATE = 1 << 3,
10956 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10958 /* default flags for public API */
10959 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10960 ADD_CHILD_EMIT_PARENT_SET |
10961 ADD_CHILD_EMIT_ACTOR_ADDED |
10962 ADD_CHILD_CHECK_STATE |
10963 ADD_CHILD_NOTIFY_FIRST_LAST,
10965 /* flags for legacy/deprecated API */
10966 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10967 ADD_CHILD_CHECK_STATE |
10968 ADD_CHILD_NOTIFY_FIRST_LAST
10969 } ClutterActorAddChildFlags;
10972 * clutter_actor_add_child_internal:
10973 * @self: a #ClutterActor
10974 * @child: a #ClutterActor
10975 * @flags: control flags for actions
10976 * @add_func: delegate function
10977 * @data: (closure): data to pass to @add_func
10979 * Adds @child to the list of children of @self.
10981 * The actual insertion inside the list is delegated to @add_func: this
10982 * function will just set up the state, perform basic checks, and emit
10985 * The @flags argument is used to perform additional operations.
10988 clutter_actor_add_child_internal (ClutterActor *self,
10989 ClutterActor *child,
10990 ClutterActorAddChildFlags flags,
10991 ClutterActorAddChildFunc add_func,
10994 ClutterTextDirection text_dir;
10995 gboolean create_meta;
10996 gboolean emit_parent_set, emit_actor_added;
10997 gboolean check_state;
10998 gboolean notify_first_last;
10999 ClutterActor *old_first_child, *old_last_child;
11001 if (child->priv->parent != NULL)
11003 g_warning ("The actor '%s' already has a parent, '%s'. You must "
11004 "use clutter_actor_remove_child() first.",
11005 _clutter_actor_get_debug_name (child),
11006 _clutter_actor_get_debug_name (child->priv->parent));
11010 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11012 g_warning ("The actor '%s' is a top-level actor, and cannot be "
11013 "a child of another actor.",
11014 _clutter_actor_get_debug_name (child));
11019 /* XXX - this check disallows calling methods that change the stacking
11020 * order within the destruction sequence, by triggering a critical
11021 * warning first, and leaving the actor in an undefined state, which
11022 * then ends up being caught by an assertion.
11024 * the reproducible sequence is:
11026 * - actor gets destroyed;
11027 * - another actor, linked to the first, will try to change the
11028 * stacking order of the first actor;
11029 * - changing the stacking order is a composite operation composed
11030 * by the following steps:
11031 * 1. ref() the child;
11032 * 2. remove_child_internal(), which removes the reference;
11033 * 3. add_child_internal(), which adds a reference;
11034 * - the state of the actor is not changed between (2) and (3), as
11035 * it could be an expensive recomputation;
11036 * - if (3) bails out, then the actor is in an undefined state, but
11038 * - the destruction sequence terminates, but the actor is unparented
11039 * while its state indicates being parented instead.
11040 * - assertion failure.
11042 * the obvious fix would be to decompose each set_child_*_sibling()
11043 * method into proper remove_child()/add_child(), with state validation;
11044 * this may cause excessive work, though, and trigger a cascade of other
11045 * bugs in code that assumes that a change in the stacking order is an
11046 * atomic operation.
11048 * another potential fix is to just remove this check here, and let
11049 * code doing stacking order changes inside the destruction sequence
11050 * of an actor continue doing the work.
11052 * the third fix is to silently bail out early from every
11053 * set_child_*_sibling() and set_child_at_index() method, and avoid
11056 * I have a preference for the second solution, since it involves the
11057 * least amount of work, and the least amount of code duplication.
11059 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11061 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11063 g_warning ("The actor '%s' is currently being destroyed, and "
11064 "cannot be added as a child of another actor.",
11065 _clutter_actor_get_debug_name (child));
11070 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11071 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11072 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11073 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11074 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11076 old_first_child = self->priv->first_child;
11077 old_last_child = self->priv->last_child;
11079 g_object_freeze_notify (G_OBJECT (self));
11082 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11084 g_object_ref_sink (child);
11085 child->priv->parent = NULL;
11086 child->priv->next_sibling = NULL;
11087 child->priv->prev_sibling = NULL;
11089 /* delegate the actual insertion */
11090 add_func (self, child, data);
11092 g_assert (child->priv->parent == self);
11094 self->priv->n_children += 1;
11096 self->priv->age += 1;
11098 /* if push_internal() has been called then we automatically set
11099 * the flag on the actor
11101 if (self->priv->internal_child)
11102 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11104 /* clutter_actor_reparent() will emit ::parent-set for us */
11105 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11106 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11110 /* If parent is mapped or realized, we need to also be mapped or
11111 * realized once we're inside the parent.
11113 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11115 /* propagate the parent's text direction to the child */
11116 text_dir = clutter_actor_get_text_direction (self);
11117 clutter_actor_set_text_direction (child, text_dir);
11120 if (child->priv->show_on_set_parent)
11121 clutter_actor_show (child);
11123 if (CLUTTER_ACTOR_IS_MAPPED (child))
11124 clutter_actor_queue_redraw (child);
11126 /* maintain the invariant that if an actor needs layout,
11127 * its parents do as well
11129 if (child->priv->needs_width_request ||
11130 child->priv->needs_height_request ||
11131 child->priv->needs_allocation)
11133 /* we work around the short-circuiting we do
11134 * in clutter_actor_queue_relayout() since we
11135 * want to force a relayout
11137 child->priv->needs_width_request = TRUE;
11138 child->priv->needs_height_request = TRUE;
11139 child->priv->needs_allocation = TRUE;
11141 clutter_actor_queue_relayout (child->priv->parent);
11144 if (emit_actor_added)
11145 g_signal_emit_by_name (self, "actor-added", child);
11147 if (notify_first_last)
11149 if (old_first_child != self->priv->first_child)
11150 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11152 if (old_last_child != self->priv->last_child)
11153 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11156 g_object_thaw_notify (G_OBJECT (self));
11160 * clutter_actor_add_child:
11161 * @self: a #ClutterActor
11162 * @child: a #ClutterActor
11164 * Adds @child to the children of @self.
11166 * This function will acquire a reference on @child that will only
11167 * be released when calling clutter_actor_remove_child().
11169 * This function will take into consideration the #ClutterActor:depth
11170 * of @child, and will keep the list of children sorted.
11172 * This function will emit the #ClutterContainer::actor-added signal
11178 clutter_actor_add_child (ClutterActor *self,
11179 ClutterActor *child)
11181 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11182 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11183 g_return_if_fail (self != child);
11184 g_return_if_fail (child->priv->parent == NULL);
11186 clutter_actor_add_child_internal (self, child,
11187 ADD_CHILD_DEFAULT_FLAGS,
11188 insert_child_at_depth,
11193 * clutter_actor_insert_child_at_index:
11194 * @self: a #ClutterActor
11195 * @child: a #ClutterActor
11196 * @index_: the index
11198 * Inserts @child into the list of children of @self, using the
11199 * given @index_. If @index_ is greater than the number of children
11200 * in @self, or is less than 0, then the new child is added at the end.
11202 * This function will acquire a reference on @child that will only
11203 * be released when calling clutter_actor_remove_child().
11205 * This function will not take into consideration the #ClutterActor:depth
11208 * This function will emit the #ClutterContainer::actor-added signal
11214 clutter_actor_insert_child_at_index (ClutterActor *self,
11215 ClutterActor *child,
11218 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11219 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11220 g_return_if_fail (self != child);
11221 g_return_if_fail (child->priv->parent == NULL);
11223 clutter_actor_add_child_internal (self, child,
11224 ADD_CHILD_DEFAULT_FLAGS,
11225 insert_child_at_index,
11226 GINT_TO_POINTER (index_));
11230 * clutter_actor_insert_child_above:
11231 * @self: a #ClutterActor
11232 * @child: a #ClutterActor
11233 * @sibling: (allow-none): a child of @self, or %NULL
11235 * Inserts @child into the list of children of @self, above another
11236 * child of @self or, if @sibling is %NULL, above all the children
11239 * This function will acquire a reference on @child that will only
11240 * be released when calling clutter_actor_remove_child().
11242 * This function will not take into consideration the #ClutterActor:depth
11245 * This function will emit the #ClutterContainer::actor-added signal
11251 clutter_actor_insert_child_above (ClutterActor *self,
11252 ClutterActor *child,
11253 ClutterActor *sibling)
11255 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11256 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11257 g_return_if_fail (self != child);
11258 g_return_if_fail (child != sibling);
11259 g_return_if_fail (child->priv->parent == NULL);
11260 g_return_if_fail (sibling == NULL ||
11261 (CLUTTER_IS_ACTOR (sibling) &&
11262 sibling->priv->parent == self));
11264 clutter_actor_add_child_internal (self, child,
11265 ADD_CHILD_DEFAULT_FLAGS,
11266 insert_child_above,
11271 * clutter_actor_insert_child_below:
11272 * @self: a #ClutterActor
11273 * @child: a #ClutterActor
11274 * @sibling: (allow-none): a child of @self, or %NULL
11276 * Inserts @child into the list of children of @self, below another
11277 * child of @self or, if @sibling is %NULL, below all the children
11280 * This function will acquire a reference on @child that will only
11281 * be released when calling clutter_actor_remove_child().
11283 * This function will not take into consideration the #ClutterActor:depth
11286 * This function will emit the #ClutterContainer::actor-added signal
11292 clutter_actor_insert_child_below (ClutterActor *self,
11293 ClutterActor *child,
11294 ClutterActor *sibling)
11296 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11297 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11298 g_return_if_fail (self != child);
11299 g_return_if_fail (child != sibling);
11300 g_return_if_fail (child->priv->parent == NULL);
11301 g_return_if_fail (sibling == NULL ||
11302 (CLUTTER_IS_ACTOR (sibling) &&
11303 sibling->priv->parent == self));
11305 clutter_actor_add_child_internal (self, child,
11306 ADD_CHILD_DEFAULT_FLAGS,
11307 insert_child_below,
11312 * clutter_actor_set_parent:
11313 * @self: A #ClutterActor
11314 * @parent: A new #ClutterActor parent
11316 * Sets the parent of @self to @parent.
11318 * This function will result in @parent acquiring a reference on @self,
11319 * eventually by sinking its floating reference first. The reference
11320 * will be released by clutter_actor_unparent().
11322 * This function should only be called by legacy #ClutterActor<!-- -->s
11323 * implementing the #ClutterContainer interface.
11325 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11328 clutter_actor_set_parent (ClutterActor *self,
11329 ClutterActor *parent)
11331 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11332 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11333 g_return_if_fail (self != parent);
11334 g_return_if_fail (self->priv->parent == NULL);
11336 /* as this function will be called inside ClutterContainer::add
11337 * implementations or when building up a composite actor, we have
11338 * to preserve the old behaviour, and not create child meta or
11339 * emit the ::actor-added signal, to avoid recursion or double
11342 clutter_actor_add_child_internal (parent, self,
11343 ADD_CHILD_LEGACY_FLAGS,
11344 insert_child_at_depth,
11349 * clutter_actor_get_parent:
11350 * @self: A #ClutterActor
11352 * Retrieves the parent of @self.
11354 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11355 * if no parent is set
11358 clutter_actor_get_parent (ClutterActor *self)
11360 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11362 return self->priv->parent;
11366 * clutter_actor_get_paint_visibility:
11367 * @self: A #ClutterActor
11369 * Retrieves the 'paint' visibility of an actor recursively checking for non
11372 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11374 * Return Value: %TRUE if the actor is visibile and will be painted.
11379 clutter_actor_get_paint_visibility (ClutterActor *actor)
11381 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11383 return CLUTTER_ACTOR_IS_MAPPED (actor);
11387 * clutter_actor_remove_child:
11388 * @self: a #ClutterActor
11389 * @child: a #ClutterActor
11391 * Removes @child from the children of @self.
11393 * This function will release the reference added by
11394 * clutter_actor_add_child(), so if you want to keep using @child
11395 * you will have to acquire a referenced on it before calling this
11398 * This function will emit the #ClutterContainer::actor-removed
11404 clutter_actor_remove_child (ClutterActor *self,
11405 ClutterActor *child)
11407 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11408 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11409 g_return_if_fail (self != child);
11410 g_return_if_fail (child->priv->parent != NULL);
11411 g_return_if_fail (child->priv->parent == self);
11413 clutter_actor_remove_child_internal (self, child,
11414 REMOVE_CHILD_DEFAULT_FLAGS);
11418 * clutter_actor_remove_all_children:
11419 * @self: a #ClutterActor
11421 * Removes all children of @self.
11423 * This function releases the reference added by inserting a child actor
11424 * in the list of children of @self.
11426 * If the reference count of a child drops to zero, the child will be
11427 * destroyed. If you want to ensure the destruction of all the children
11428 * of @self, use clutter_actor_destroy_all_children().
11433 clutter_actor_remove_all_children (ClutterActor *self)
11435 ClutterActorIter iter;
11437 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11439 if (self->priv->n_children == 0)
11442 g_object_freeze_notify (G_OBJECT (self));
11444 clutter_actor_iter_init (&iter, self);
11445 while (clutter_actor_iter_next (&iter, NULL))
11446 clutter_actor_iter_remove (&iter);
11448 g_object_thaw_notify (G_OBJECT (self));
11451 g_assert (self->priv->first_child == NULL);
11452 g_assert (self->priv->last_child == NULL);
11453 g_assert (self->priv->n_children == 0);
11457 * clutter_actor_destroy_all_children:
11458 * @self: a #ClutterActor
11460 * Destroys all children of @self.
11462 * This function releases the reference added by inserting a child
11463 * actor in the list of children of @self, and ensures that the
11464 * #ClutterActor::destroy signal is emitted on each child of the
11467 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11468 * when its reference count drops to 0; the default handler of the
11469 * #ClutterActor::destroy signal will destroy all the children of an
11470 * actor. This function ensures that all children are destroyed, instead
11471 * of just removed from @self, unlike clutter_actor_remove_all_children()
11472 * which will merely release the reference and remove each child.
11474 * Unless you acquired an additional reference on each child of @self
11475 * prior to calling clutter_actor_remove_all_children() and want to reuse
11476 * the actors, you should use clutter_actor_destroy_all_children() in
11477 * order to make sure that children are destroyed and signal handlers
11478 * are disconnected even in cases where circular references prevent this
11479 * from automatically happening through reference counting alone.
11484 clutter_actor_destroy_all_children (ClutterActor *self)
11486 ClutterActorIter iter;
11488 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11490 if (self->priv->n_children == 0)
11493 g_object_freeze_notify (G_OBJECT (self));
11495 clutter_actor_iter_init (&iter, self);
11496 while (clutter_actor_iter_next (&iter, NULL))
11497 clutter_actor_iter_destroy (&iter);
11499 g_object_thaw_notify (G_OBJECT (self));
11502 g_assert (self->priv->first_child == NULL);
11503 g_assert (self->priv->last_child == NULL);
11504 g_assert (self->priv->n_children == 0);
11507 typedef struct _InsertBetweenData {
11508 ClutterActor *prev_sibling;
11509 ClutterActor *next_sibling;
11510 } InsertBetweenData;
11513 insert_child_between (ClutterActor *self,
11514 ClutterActor *child,
11517 InsertBetweenData *data = data_;
11518 ClutterActor *prev_sibling = data->prev_sibling;
11519 ClutterActor *next_sibling = data->next_sibling;
11521 child->priv->parent = self;
11522 child->priv->prev_sibling = prev_sibling;
11523 child->priv->next_sibling = next_sibling;
11525 if (prev_sibling != NULL)
11526 prev_sibling->priv->next_sibling = child;
11528 if (next_sibling != NULL)
11529 next_sibling->priv->prev_sibling = child;
11531 if (child->priv->prev_sibling == NULL)
11532 self->priv->first_child = child;
11534 if (child->priv->next_sibling == NULL)
11535 self->priv->last_child = child;
11539 * clutter_actor_replace_child:
11540 * @self: a #ClutterActor
11541 * @old_child: the child of @self to replace
11542 * @new_child: the #ClutterActor to replace @old_child
11544 * Replaces @old_child with @new_child in the list of children of @self.
11549 clutter_actor_replace_child (ClutterActor *self,
11550 ClutterActor *old_child,
11551 ClutterActor *new_child)
11553 ClutterActor *prev_sibling, *next_sibling;
11554 InsertBetweenData clos;
11556 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11557 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11558 g_return_if_fail (old_child->priv->parent == self);
11559 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11560 g_return_if_fail (old_child != new_child);
11561 g_return_if_fail (new_child != self);
11562 g_return_if_fail (new_child->priv->parent == NULL);
11564 prev_sibling = old_child->priv->prev_sibling;
11565 next_sibling = old_child->priv->next_sibling;
11566 clutter_actor_remove_child_internal (self, old_child,
11567 REMOVE_CHILD_DEFAULT_FLAGS);
11569 clos.prev_sibling = prev_sibling;
11570 clos.next_sibling = next_sibling;
11571 clutter_actor_add_child_internal (self, new_child,
11572 ADD_CHILD_DEFAULT_FLAGS,
11573 insert_child_between,
11578 * clutter_actor_unparent:
11579 * @self: a #ClutterActor
11581 * Removes the parent of @self.
11583 * This will cause the parent of @self to release the reference
11584 * acquired when calling clutter_actor_set_parent(), so if you
11585 * want to keep @self you will have to acquire a reference of
11586 * your own, through g_object_ref().
11588 * This function should only be called by legacy #ClutterActor<!-- -->s
11589 * implementing the #ClutterContainer interface.
11593 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11596 clutter_actor_unparent (ClutterActor *self)
11598 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11600 if (self->priv->parent == NULL)
11603 clutter_actor_remove_child_internal (self->priv->parent, self,
11604 REMOVE_CHILD_LEGACY_FLAGS);
11608 * clutter_actor_reparent:
11609 * @self: a #ClutterActor
11610 * @new_parent: the new #ClutterActor parent
11612 * Resets the parent actor of @self.
11614 * This function is logically equivalent to calling clutter_actor_unparent()
11615 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11616 * ensures the child is not finalized when unparented, and emits the
11617 * #ClutterActor::parent-set signal only once.
11619 * In reality, calling this function is less useful than it sounds, as some
11620 * application code may rely on changes in the intermediate state between
11621 * removal and addition of the actor from its old parent to the @new_parent.
11622 * Thus, it is strongly encouraged to avoid using this function in application
11627 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11628 * clutter_actor_add_child() instead; remember to take a reference on
11629 * the actor being removed before calling clutter_actor_remove_child()
11630 * to avoid the reference count dropping to zero and the actor being
11634 clutter_actor_reparent (ClutterActor *self,
11635 ClutterActor *new_parent)
11637 ClutterActorPrivate *priv;
11639 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11640 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11641 g_return_if_fail (self != new_parent);
11643 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11645 g_warning ("Cannot set a parent on a toplevel actor");
11649 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11651 g_warning ("Cannot set a parent currently being destroyed");
11657 if (priv->parent != new_parent)
11659 ClutterActor *old_parent;
11661 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11663 old_parent = priv->parent;
11665 g_object_ref (self);
11667 if (old_parent != NULL)
11669 /* go through the Container implementation if this is a regular
11670 * child and not an internal one
11672 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11674 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11676 /* this will have to call unparent() */
11677 clutter_container_remove_actor (parent, self);
11680 clutter_actor_remove_child_internal (old_parent, self,
11681 REMOVE_CHILD_LEGACY_FLAGS);
11684 /* Note, will call set_parent() */
11685 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11686 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11688 clutter_actor_add_child_internal (new_parent, self,
11689 ADD_CHILD_LEGACY_FLAGS,
11690 insert_child_at_depth,
11693 /* we emit the ::parent-set signal once */
11694 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11696 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11698 /* the IN_REPARENT flag suspends state updates */
11699 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11701 g_object_unref (self);
11706 * clutter_actor_contains:
11707 * @self: A #ClutterActor
11708 * @descendant: A #ClutterActor, possibly contained in @self
11710 * Determines if @descendant is contained inside @self (either as an
11711 * immediate child, or as a deeper descendant). If @self and
11712 * @descendant point to the same actor then it will also return %TRUE.
11714 * Return value: whether @descendent is contained within @self
11719 clutter_actor_contains (ClutterActor *self,
11720 ClutterActor *descendant)
11722 ClutterActor *actor;
11724 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11725 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11727 for (actor = descendant; actor; actor = actor->priv->parent)
11735 * clutter_actor_set_child_above_sibling:
11736 * @self: a #ClutterActor
11737 * @child: a #ClutterActor child of @self
11738 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11740 * Sets @child to be above @sibling in the list of children of @self.
11742 * If @sibling is %NULL, @child will be the new last child of @self.
11744 * This function is logically equivalent to removing @child and using
11745 * clutter_actor_insert_child_above(), but it will not emit signals
11746 * or change state on @child.
11751 clutter_actor_set_child_above_sibling (ClutterActor *self,
11752 ClutterActor *child,
11753 ClutterActor *sibling)
11755 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11756 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11757 g_return_if_fail (child->priv->parent == self);
11758 g_return_if_fail (child != sibling);
11759 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11761 if (sibling != NULL)
11762 g_return_if_fail (sibling->priv->parent == self);
11764 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11765 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11766 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11769 /* we don't want to change the state of child, or emit signals, or
11770 * regenerate ChildMeta instances here, but we still want to follow
11771 * the correct sequence of steps encoded in remove_child() and
11772 * add_child(), so that correctness is ensured, and we only go
11773 * through one known code path.
11775 g_object_ref (child);
11776 clutter_actor_remove_child_internal (self, child, 0);
11777 clutter_actor_add_child_internal (self, child,
11778 ADD_CHILD_NOTIFY_FIRST_LAST,
11779 insert_child_above,
11782 clutter_actor_queue_relayout (self);
11786 * clutter_actor_set_child_below_sibling:
11787 * @self: a #ClutterActor
11788 * @child: a #ClutterActor child of @self
11789 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11791 * Sets @child to be below @sibling in the list of children of @self.
11793 * If @sibling is %NULL, @child will be the new first child of @self.
11795 * This function is logically equivalent to removing @self and using
11796 * clutter_actor_insert_child_below(), but it will not emit signals
11797 * or change state on @child.
11802 clutter_actor_set_child_below_sibling (ClutterActor *self,
11803 ClutterActor *child,
11804 ClutterActor *sibling)
11806 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11807 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11808 g_return_if_fail (child->priv->parent == self);
11809 g_return_if_fail (child != sibling);
11810 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11812 if (sibling != NULL)
11813 g_return_if_fail (sibling->priv->parent == self);
11815 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11816 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11817 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11820 /* see the comment in set_child_above_sibling() */
11821 g_object_ref (child);
11822 clutter_actor_remove_child_internal (self, child, 0);
11823 clutter_actor_add_child_internal (self, child,
11824 ADD_CHILD_NOTIFY_FIRST_LAST,
11825 insert_child_below,
11828 clutter_actor_queue_relayout (self);
11832 * clutter_actor_set_child_at_index:
11833 * @self: a #ClutterActor
11834 * @child: a #ClutterActor child of @self
11835 * @index_: the new index for @child
11837 * Changes the index of @child in the list of children of @self.
11839 * This function is logically equivalent to removing @child and
11840 * calling clutter_actor_insert_child_at_index(), but it will not
11841 * emit signals or change state on @child.
11846 clutter_actor_set_child_at_index (ClutterActor *self,
11847 ClutterActor *child,
11850 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11851 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11852 g_return_if_fail (child->priv->parent == self);
11853 g_return_if_fail (index_ <= self->priv->n_children);
11855 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11856 CLUTTER_ACTOR_IN_DESTRUCTION (child))
11859 g_object_ref (child);
11860 clutter_actor_remove_child_internal (self, child, 0);
11861 clutter_actor_add_child_internal (self, child,
11862 ADD_CHILD_NOTIFY_FIRST_LAST,
11863 insert_child_at_index,
11864 GINT_TO_POINTER (index_));
11866 clutter_actor_queue_relayout (self);
11870 * clutter_actor_raise:
11871 * @self: A #ClutterActor
11872 * @below: (allow-none): A #ClutterActor to raise above.
11874 * Puts @self above @below.
11876 * Both actors must have the same parent, and the parent must implement
11877 * the #ClutterContainer interface
11879 * This function calls clutter_container_raise_child() internally.
11881 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11884 clutter_actor_raise (ClutterActor *self,
11885 ClutterActor *below)
11887 ClutterActor *parent;
11889 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11891 parent = clutter_actor_get_parent (self);
11892 if (parent == NULL)
11894 g_warning ("%s: Actor '%s' is not inside a container",
11896 _clutter_actor_get_debug_name (self));
11902 if (parent != clutter_actor_get_parent (below))
11904 g_warning ("%s Actor '%s' is not in the same container as "
11907 _clutter_actor_get_debug_name (self),
11908 _clutter_actor_get_debug_name (below));
11913 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11917 * clutter_actor_lower:
11918 * @self: A #ClutterActor
11919 * @above: (allow-none): A #ClutterActor to lower below
11921 * Puts @self below @above.
11923 * Both actors must have the same parent, and the parent must implement
11924 * the #ClutterContainer interface.
11926 * This function calls clutter_container_lower_child() internally.
11928 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11931 clutter_actor_lower (ClutterActor *self,
11932 ClutterActor *above)
11934 ClutterActor *parent;
11936 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11938 parent = clutter_actor_get_parent (self);
11939 if (parent == NULL)
11941 g_warning ("%s: Actor of type %s is not inside a container",
11943 _clutter_actor_get_debug_name (self));
11949 if (parent != clutter_actor_get_parent (above))
11951 g_warning ("%s: Actor '%s' is not in the same container as "
11954 _clutter_actor_get_debug_name (self),
11955 _clutter_actor_get_debug_name (above));
11960 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11964 * clutter_actor_raise_top:
11965 * @self: A #ClutterActor
11967 * Raises @self to the top.
11969 * This function calls clutter_actor_raise() internally.
11971 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11972 * a %NULL sibling, instead.
11975 clutter_actor_raise_top (ClutterActor *self)
11977 clutter_actor_raise (self, NULL);
11981 * clutter_actor_lower_bottom:
11982 * @self: A #ClutterActor
11984 * Lowers @self to the bottom.
11986 * This function calls clutter_actor_lower() internally.
11988 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11989 * a %NULL sibling, instead.
11992 clutter_actor_lower_bottom (ClutterActor *self)
11994 clutter_actor_lower (self, NULL);
12002 * clutter_actor_event:
12003 * @actor: a #ClutterActor
12004 * @event: a #ClutterEvent
12005 * @capture: TRUE if event in in capture phase, FALSE otherwise.
12007 * This function is used to emit an event on the main stage.
12008 * You should rarely need to use this function, except for
12009 * synthetising events.
12011 * Return value: the return value from the signal emission: %TRUE
12012 * if the actor handled the event, or %FALSE if the event was
12018 clutter_actor_event (ClutterActor *actor,
12019 ClutterEvent *event,
12022 gboolean retval = FALSE;
12023 gint signal_num = -1;
12025 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12026 g_return_val_if_fail (event != NULL, FALSE);
12028 g_object_ref (actor);
12032 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12038 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12042 switch (event->type)
12044 case CLUTTER_NOTHING:
12046 case CLUTTER_BUTTON_PRESS:
12047 signal_num = BUTTON_PRESS_EVENT;
12049 case CLUTTER_BUTTON_RELEASE:
12050 signal_num = BUTTON_RELEASE_EVENT;
12052 case CLUTTER_SCROLL:
12053 signal_num = SCROLL_EVENT;
12055 case CLUTTER_KEY_PRESS:
12056 signal_num = KEY_PRESS_EVENT;
12058 case CLUTTER_KEY_RELEASE:
12059 signal_num = KEY_RELEASE_EVENT;
12061 case CLUTTER_MOTION:
12062 signal_num = MOTION_EVENT;
12064 case CLUTTER_ENTER:
12065 signal_num = ENTER_EVENT;
12067 case CLUTTER_LEAVE:
12068 signal_num = LEAVE_EVENT;
12070 case CLUTTER_DELETE:
12071 case CLUTTER_DESTROY_NOTIFY:
12072 case CLUTTER_CLIENT_MESSAGE:
12078 if (signal_num != -1)
12079 g_signal_emit (actor, actor_signals[signal_num], 0,
12084 g_object_unref (actor);
12090 * clutter_actor_set_reactive:
12091 * @actor: a #ClutterActor
12092 * @reactive: whether the actor should be reactive to events
12094 * Sets @actor as reactive. Reactive actors will receive events.
12099 clutter_actor_set_reactive (ClutterActor *actor,
12102 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12104 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12108 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12110 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12112 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12116 * clutter_actor_get_reactive:
12117 * @actor: a #ClutterActor
12119 * Checks whether @actor is marked as reactive.
12121 * Return value: %TRUE if the actor is reactive
12126 clutter_actor_get_reactive (ClutterActor *actor)
12128 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12130 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12134 * clutter_actor_get_anchor_point:
12135 * @self: a #ClutterActor
12136 * @anchor_x: (out): return location for the X coordinate of the anchor point
12137 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12139 * Gets the current anchor point of the @actor in pixels.
12144 clutter_actor_get_anchor_point (ClutterActor *self,
12148 const ClutterTransformInfo *info;
12150 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12152 info = _clutter_actor_get_transform_info_or_defaults (self);
12153 clutter_anchor_coord_get_units (self, &info->anchor,
12160 * clutter_actor_set_anchor_point:
12161 * @self: a #ClutterActor
12162 * @anchor_x: X coordinate of the anchor point
12163 * @anchor_y: Y coordinate of the anchor point
12165 * Sets an anchor point for @self. The anchor point is a point in the
12166 * coordinate space of an actor to which the actor position within its
12167 * parent is relative; the default is (0, 0), i.e. the top-left corner
12173 clutter_actor_set_anchor_point (ClutterActor *self,
12177 ClutterTransformInfo *info;
12178 ClutterActorPrivate *priv;
12179 gboolean changed = FALSE;
12180 gfloat old_anchor_x, old_anchor_y;
12183 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12185 obj = G_OBJECT (self);
12187 info = _clutter_actor_get_transform_info (self);
12189 g_object_freeze_notify (obj);
12191 clutter_anchor_coord_get_units (self, &info->anchor,
12196 if (info->anchor.is_fractional)
12197 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12199 if (old_anchor_x != anchor_x)
12201 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12205 if (old_anchor_y != anchor_y)
12207 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12211 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12215 priv->transform_valid = FALSE;
12216 clutter_actor_queue_redraw (self);
12219 g_object_thaw_notify (obj);
12223 * clutter_actor_get_anchor_point_gravity:
12224 * @self: a #ClutterActor
12226 * Retrieves the anchor position expressed as a #ClutterGravity. If
12227 * the anchor point was specified using pixels or units this will
12228 * return %CLUTTER_GRAVITY_NONE.
12230 * Return value: the #ClutterGravity used by the anchor point
12235 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12237 const ClutterTransformInfo *info;
12239 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12241 info = _clutter_actor_get_transform_info_or_defaults (self);
12243 return clutter_anchor_coord_get_gravity (&info->anchor);
12247 * clutter_actor_move_anchor_point:
12248 * @self: a #ClutterActor
12249 * @anchor_x: X coordinate of the anchor point
12250 * @anchor_y: Y coordinate of the anchor point
12252 * Sets an anchor point for the actor, and adjusts the actor postion so that
12253 * the relative position of the actor toward its parent remains the same.
12258 clutter_actor_move_anchor_point (ClutterActor *self,
12262 gfloat old_anchor_x, old_anchor_y;
12263 const ClutterTransformInfo *info;
12265 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12267 info = _clutter_actor_get_transform_info (self);
12268 clutter_anchor_coord_get_units (self, &info->anchor,
12273 g_object_freeze_notify (G_OBJECT (self));
12275 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12277 if (self->priv->position_set)
12278 clutter_actor_move_by (self,
12279 anchor_x - old_anchor_x,
12280 anchor_y - old_anchor_y);
12282 g_object_thaw_notify (G_OBJECT (self));
12286 * clutter_actor_move_anchor_point_from_gravity:
12287 * @self: a #ClutterActor
12288 * @gravity: #ClutterGravity.
12290 * Sets an anchor point on the actor based on the given gravity, adjusting the
12291 * actor postion so that its relative position within its parent remains
12294 * Since version 1.0 the anchor point will be stored as a gravity so
12295 * that if the actor changes size then the anchor point will move. For
12296 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12297 * and later double the size of the actor, the anchor point will move
12298 * to the bottom right.
12303 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12304 ClutterGravity gravity)
12306 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12307 const ClutterTransformInfo *info;
12308 ClutterActorPrivate *priv;
12310 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12313 info = _clutter_actor_get_transform_info (self);
12315 g_object_freeze_notify (G_OBJECT (self));
12317 clutter_anchor_coord_get_units (self, &info->anchor,
12321 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12322 clutter_anchor_coord_get_units (self, &info->anchor,
12327 if (priv->position_set)
12328 clutter_actor_move_by (self,
12329 new_anchor_x - old_anchor_x,
12330 new_anchor_y - old_anchor_y);
12332 g_object_thaw_notify (G_OBJECT (self));
12336 * clutter_actor_set_anchor_point_from_gravity:
12337 * @self: a #ClutterActor
12338 * @gravity: #ClutterGravity.
12340 * Sets an anchor point on the actor, based on the given gravity (this is a
12341 * convenience function wrapping clutter_actor_set_anchor_point()).
12343 * Since version 1.0 the anchor point will be stored as a gravity so
12344 * that if the actor changes size then the anchor point will move. For
12345 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12346 * and later double the size of the actor, the anchor point will move
12347 * to the bottom right.
12352 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12353 ClutterGravity gravity)
12355 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12357 if (gravity == CLUTTER_GRAVITY_NONE)
12358 clutter_actor_set_anchor_point (self, 0, 0);
12361 GObject *obj = G_OBJECT (self);
12362 ClutterTransformInfo *info;
12364 g_object_freeze_notify (obj);
12366 info = _clutter_actor_get_transform_info (self);
12367 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12369 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12370 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12371 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12373 self->priv->transform_valid = FALSE;
12375 clutter_actor_queue_redraw (self);
12377 g_object_thaw_notify (obj);
12382 clutter_container_iface_init (ClutterContainerIface *iface)
12384 /* we don't override anything, as ClutterContainer already has a default
12385 * implementation that we can use, and which calls into our own API.
12400 parse_units (ClutterActor *self,
12401 ParseDimension dimension,
12404 GValue value = G_VALUE_INIT;
12407 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12410 json_node_get_value (node, &value);
12412 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12414 retval = (gfloat) g_value_get_int64 (&value);
12416 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12418 retval = g_value_get_double (&value);
12420 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12422 ClutterUnits units;
12425 res = clutter_units_from_string (&units, g_value_get_string (&value));
12427 retval = clutter_units_to_pixels (&units);
12430 g_warning ("Invalid value '%s': integers, strings or floating point "
12431 "values can be used for the x, y, width and height "
12432 "properties. Valid modifiers for strings are 'px', 'mm', "
12434 g_value_get_string (&value));
12440 g_warning ("Invalid value of type '%s': integers, strings of floating "
12441 "point values can be used for the x, y, width, height "
12442 "anchor-x and anchor-y properties.",
12443 g_type_name (G_VALUE_TYPE (&value)));
12446 g_value_unset (&value);
12452 ClutterRotateAxis axis;
12461 static inline gboolean
12462 parse_rotation_array (ClutterActor *actor,
12464 RotationInfo *info)
12468 if (json_array_get_length (array) != 2)
12472 element = json_array_get_element (array, 0);
12473 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12474 info->angle = json_node_get_double (element);
12479 element = json_array_get_element (array, 1);
12480 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12482 JsonArray *center = json_node_get_array (element);
12484 if (json_array_get_length (center) != 2)
12487 switch (info->axis)
12489 case CLUTTER_X_AXIS:
12490 info->center_y = parse_units (actor, PARSE_Y,
12491 json_array_get_element (center, 0));
12492 info->center_z = parse_units (actor, PARSE_Y,
12493 json_array_get_element (center, 1));
12496 case CLUTTER_Y_AXIS:
12497 info->center_x = parse_units (actor, PARSE_X,
12498 json_array_get_element (center, 0));
12499 info->center_z = parse_units (actor, PARSE_X,
12500 json_array_get_element (center, 1));
12503 case CLUTTER_Z_AXIS:
12504 info->center_x = parse_units (actor, PARSE_X,
12505 json_array_get_element (center, 0));
12506 info->center_y = parse_units (actor, PARSE_Y,
12507 json_array_get_element (center, 1));
12516 parse_rotation (ClutterActor *actor,
12518 RotationInfo *info)
12522 gboolean retval = FALSE;
12524 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12526 g_warning ("Invalid node of type '%s' found, expecting an array",
12527 json_node_type_name (node));
12531 array = json_node_get_array (node);
12532 len = json_array_get_length (array);
12534 for (i = 0; i < len; i++)
12536 JsonNode *element = json_array_get_element (array, i);
12537 JsonObject *object;
12540 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12542 g_warning ("Invalid node of type '%s' found, expecting an object",
12543 json_node_type_name (element));
12547 object = json_node_get_object (element);
12549 if (json_object_has_member (object, "x-axis"))
12551 member = json_object_get_member (object, "x-axis");
12553 info->axis = CLUTTER_X_AXIS;
12555 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12557 info->angle = json_node_get_double (member);
12560 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12561 retval = parse_rotation_array (actor,
12562 json_node_get_array (member),
12567 else if (json_object_has_member (object, "y-axis"))
12569 member = json_object_get_member (object, "y-axis");
12571 info->axis = CLUTTER_Y_AXIS;
12573 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12575 info->angle = json_node_get_double (member);
12578 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12579 retval = parse_rotation_array (actor,
12580 json_node_get_array (member),
12585 else if (json_object_has_member (object, "z-axis"))
12587 member = json_object_get_member (object, "z-axis");
12589 info->axis = CLUTTER_Z_AXIS;
12591 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12593 info->angle = json_node_get_double (member);
12596 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12597 retval = parse_rotation_array (actor,
12598 json_node_get_array (member),
12609 parse_actor_metas (ClutterScript *script,
12610 ClutterActor *actor,
12613 GList *elements, *l;
12614 GSList *retval = NULL;
12616 if (!JSON_NODE_HOLDS_ARRAY (node))
12619 elements = json_array_get_elements (json_node_get_array (node));
12621 for (l = elements; l != NULL; l = l->next)
12623 JsonNode *element = l->data;
12624 const gchar *id_ = _clutter_script_get_id_from_node (element);
12627 if (id_ == NULL || *id_ == '\0')
12630 meta = clutter_script_get_object (script, id_);
12634 retval = g_slist_prepend (retval, meta);
12637 g_list_free (elements);
12639 return g_slist_reverse (retval);
12643 parse_behaviours (ClutterScript *script,
12644 ClutterActor *actor,
12647 GList *elements, *l;
12648 GSList *retval = NULL;
12650 if (!JSON_NODE_HOLDS_ARRAY (node))
12653 elements = json_array_get_elements (json_node_get_array (node));
12655 for (l = elements; l != NULL; l = l->next)
12657 JsonNode *element = l->data;
12658 const gchar *id_ = _clutter_script_get_id_from_node (element);
12659 GObject *behaviour;
12661 if (id_ == NULL || *id_ == '\0')
12664 behaviour = clutter_script_get_object (script, id_);
12665 if (behaviour == NULL)
12668 retval = g_slist_prepend (retval, behaviour);
12671 g_list_free (elements);
12673 return g_slist_reverse (retval);
12677 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12678 ClutterScript *script,
12683 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12684 gboolean retval = FALSE;
12686 if ((name[0] == 'x' && name[1] == '\0') ||
12687 (name[0] == 'y' && name[1] == '\0') ||
12688 (strcmp (name, "width") == 0) ||
12689 (strcmp (name, "height") == 0) ||
12690 (strcmp (name, "anchor_x") == 0) ||
12691 (strcmp (name, "anchor_y") == 0))
12693 ParseDimension dimension;
12696 if (name[0] == 'x')
12697 dimension = PARSE_X;
12698 else if (name[0] == 'y')
12699 dimension = PARSE_Y;
12700 else if (name[0] == 'w')
12701 dimension = PARSE_WIDTH;
12702 else if (name[0] == 'h')
12703 dimension = PARSE_HEIGHT;
12704 else if (name[0] == 'a' && name[7] == 'x')
12705 dimension = PARSE_ANCHOR_X;
12706 else if (name[0] == 'a' && name[7] == 'y')
12707 dimension = PARSE_ANCHOR_Y;
12711 units = parse_units (actor, dimension, node);
12713 /* convert back to pixels: all properties are pixel-based */
12714 g_value_init (value, G_TYPE_FLOAT);
12715 g_value_set_float (value, units);
12719 else if (strcmp (name, "rotation") == 0)
12721 RotationInfo *info;
12723 info = g_slice_new0 (RotationInfo);
12724 retval = parse_rotation (actor, node, info);
12728 g_value_init (value, G_TYPE_POINTER);
12729 g_value_set_pointer (value, info);
12732 g_slice_free (RotationInfo, info);
12734 else if (strcmp (name, "behaviours") == 0)
12738 #ifdef CLUTTER_ENABLE_DEBUG
12739 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12740 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12741 "and it should not be used in newly "
12742 "written ClutterScript definitions.");
12745 l = parse_behaviours (script, actor, node);
12747 g_value_init (value, G_TYPE_POINTER);
12748 g_value_set_pointer (value, l);
12752 else if (strcmp (name, "actions") == 0 ||
12753 strcmp (name, "constraints") == 0 ||
12754 strcmp (name, "effects") == 0)
12758 l = parse_actor_metas (script, actor, node);
12760 g_value_init (value, G_TYPE_POINTER);
12761 g_value_set_pointer (value, l);
12770 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12771 ClutterScript *script,
12773 const GValue *value)
12775 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12777 #ifdef CLUTTER_ENABLE_DEBUG
12778 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12780 gchar *tmp = g_strdup_value_contents (value);
12782 CLUTTER_NOTE (SCRIPT,
12783 "in ClutterActor::set_custom_property('%s') = %s",
12789 #endif /* CLUTTER_ENABLE_DEBUG */
12791 if (strcmp (name, "rotation") == 0)
12793 RotationInfo *info;
12795 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12798 info = g_value_get_pointer (value);
12800 clutter_actor_set_rotation (actor,
12801 info->axis, info->angle,
12806 g_slice_free (RotationInfo, info);
12811 if (strcmp (name, "behaviours") == 0)
12813 GSList *behaviours, *l;
12815 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12818 behaviours = g_value_get_pointer (value);
12819 for (l = behaviours; l != NULL; l = l->next)
12821 ClutterBehaviour *behaviour = l->data;
12823 clutter_behaviour_apply (behaviour, actor);
12826 g_slist_free (behaviours);
12831 if (strcmp (name, "actions") == 0 ||
12832 strcmp (name, "constraints") == 0 ||
12833 strcmp (name, "effects") == 0)
12837 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12840 metas = g_value_get_pointer (value);
12841 for (l = metas; l != NULL; l = l->next)
12843 if (name[0] == 'a')
12844 clutter_actor_add_action (actor, l->data);
12846 if (name[0] == 'c')
12847 clutter_actor_add_constraint (actor, l->data);
12849 if (name[0] == 'e')
12850 clutter_actor_add_effect (actor, l->data);
12853 g_slist_free (metas);
12858 g_object_set_property (G_OBJECT (scriptable), name, value);
12862 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12864 iface->parse_custom_node = clutter_actor_parse_custom_node;
12865 iface->set_custom_property = clutter_actor_set_custom_property;
12868 static ClutterActorMeta *
12869 get_meta_from_animation_property (ClutterActor *actor,
12873 ClutterActorPrivate *priv = actor->priv;
12874 ClutterActorMeta *meta = NULL;
12877 /* if this is not a special property, fall through */
12878 if (name[0] != '@')
12881 /* detect the properties named using the following spec:
12883 * @<section>.<meta-name>.<property-name>
12885 * where <section> can be one of the following:
12891 * and <meta-name> is the name set on a specific ActorMeta
12894 tokens = g_strsplit (name + 1, ".", -1);
12895 if (tokens == NULL || g_strv_length (tokens) != 3)
12897 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12899 g_strfreev (tokens);
12903 if (strcmp (tokens[0], "actions") == 0)
12904 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12906 if (strcmp (tokens[0], "constraints") == 0)
12907 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12909 if (strcmp (tokens[0], "effects") == 0)
12910 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12912 if (name_p != NULL)
12913 *name_p = g_strdup (tokens[2]);
12915 CLUTTER_NOTE (ANIMATION,
12916 "Looking for property '%s' of object '%s' in section '%s'",
12921 g_strfreev (tokens);
12926 static GParamSpec *
12927 clutter_actor_find_property (ClutterAnimatable *animatable,
12928 const gchar *property_name)
12930 ClutterActorMeta *meta = NULL;
12931 GObjectClass *klass = NULL;
12932 GParamSpec *pspec = NULL;
12933 gchar *p_name = NULL;
12935 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12941 klass = G_OBJECT_GET_CLASS (meta);
12943 pspec = g_object_class_find_property (klass, p_name);
12947 klass = G_OBJECT_GET_CLASS (animatable);
12949 pspec = g_object_class_find_property (klass, property_name);
12958 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12959 const gchar *property_name,
12962 ClutterActorMeta *meta = NULL;
12963 gchar *p_name = NULL;
12965 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12970 g_object_get_property (G_OBJECT (meta), p_name, initial);
12972 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12978 * clutter_actor_set_animatable_property:
12979 * @actor: a #ClutterActor
12980 * @prop_id: the paramspec id
12981 * @value: the value to set
12982 * @pspec: the paramspec
12984 * Sets values of animatable properties.
12986 * This is a variant of clutter_actor_set_property() that gets called
12987 * by the #ClutterAnimatable implementation of #ClutterActor for the
12988 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12991 * Unlike the implementation of #GObjectClass.set_property(), this
12992 * function will not update the interval if a transition involving an
12993 * animatable property is in progress - this avoids cycles with the
12994 * transition API calling the public API.
12997 clutter_actor_set_animatable_property (ClutterActor *actor,
12999 const GValue *value,
13005 clutter_actor_set_x_internal (actor, g_value_get_float (value));
13009 clutter_actor_set_y_internal (actor, g_value_get_float (value));
13013 clutter_actor_set_width_internal (actor, g_value_get_float (value));
13017 clutter_actor_set_height_internal (actor, g_value_get_float (value));
13021 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13025 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13028 case PROP_BACKGROUND_COLOR:
13029 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13033 clutter_actor_set_scale_factor_internal (actor,
13034 g_value_get_double (value),
13039 clutter_actor_set_scale_factor_internal (actor,
13040 g_value_get_double (value),
13044 case PROP_ROTATION_ANGLE_X:
13045 clutter_actor_set_rotation_angle_internal (actor,
13047 g_value_get_double (value));
13050 case PROP_ROTATION_ANGLE_Y:
13051 clutter_actor_set_rotation_angle_internal (actor,
13053 g_value_get_double (value));
13056 case PROP_ROTATION_ANGLE_Z:
13057 clutter_actor_set_rotation_angle_internal (actor,
13059 g_value_get_double (value));
13063 g_object_set_property (G_OBJECT (actor), pspec->name, value);
13069 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13070 const gchar *property_name,
13071 const GValue *final)
13073 ClutterActor *actor = CLUTTER_ACTOR (animatable);
13074 ClutterActorMeta *meta = NULL;
13075 gchar *p_name = NULL;
13077 meta = get_meta_from_animation_property (actor,
13081 g_object_set_property (G_OBJECT (meta), p_name, final);
13084 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13087 pspec = g_object_class_find_property (obj_class, property_name);
13089 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13091 /* XXX - I'm going to the special hell for this */
13092 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13095 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13102 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13104 iface->find_property = clutter_actor_find_property;
13105 iface->get_initial_state = clutter_actor_get_initial_state;
13106 iface->set_final_state = clutter_actor_set_final_state;
13110 * clutter_actor_transform_stage_point:
13111 * @self: A #ClutterActor
13112 * @x: (in): x screen coordinate of the point to unproject
13113 * @y: (in): y screen coordinate of the point to unproject
13114 * @x_out: (out): return location for the unprojected x coordinance
13115 * @y_out: (out): return location for the unprojected y coordinance
13117 * This function translates screen coordinates (@x, @y) to
13118 * coordinates relative to the actor. For example, it can be used to translate
13119 * screen events from global screen coordinates into actor-local coordinates.
13121 * The conversion can fail, notably if the transform stack results in the
13122 * actor being projected on the screen as a mere line.
13124 * The conversion should not be expected to be pixel-perfect due to the
13125 * nature of the operation. In general the error grows when the skewing
13126 * of the actor rectangle on screen increases.
13128 * <note><para>This function can be computationally intensive.</para></note>
13130 * <note><para>This function only works when the allocation is up-to-date,
13131 * i.e. inside of paint().</para></note>
13133 * Return value: %TRUE if conversion was successful.
13138 clutter_actor_transform_stage_point (ClutterActor *self,
13144 ClutterVertex v[4];
13147 int du, dv, xi, yi;
13149 float xf, yf, wf, det;
13150 ClutterActorPrivate *priv;
13152 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13156 /* This implementation is based on the quad -> quad projection algorithm
13157 * described by Paul Heckbert in:
13159 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13161 * and the sample implementation at:
13163 * http://www.cs.cmu.edu/~ph/src/texfund/
13165 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13166 * quad to rectangle only, which significantly simplifies things; the
13167 * function calls have been unrolled, and most of the math is done in fixed
13171 clutter_actor_get_abs_allocation_vertices (self, v);
13173 /* Keeping these as ints simplifies the multiplication (no significant
13174 * loss of precision here).
13176 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13177 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13182 #define UX2FP(x) (x)
13183 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13185 /* First, find mapping from unit uv square to xy quadrilateral; this
13186 * equivalent to the pmap_square_quad() functions in the sample
13187 * implementation, which we can simplify, since our target is always
13190 px = v[0].x - v[1].x + v[3].x - v[2].x;
13191 py = v[0].y - v[1].y + v[3].y - v[2].y;
13195 /* affine transform */
13196 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13197 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13198 RQ[2][0] = UX2FP (v[0].x);
13199 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13200 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13201 RQ[2][1] = UX2FP (v[0].y);
13208 /* projective transform */
13209 double dx1, dx2, dy1, dy2, del;
13211 dx1 = UX2FP (v[1].x - v[3].x);
13212 dx2 = UX2FP (v[2].x - v[3].x);
13213 dy1 = UX2FP (v[1].y - v[3].y);
13214 dy2 = UX2FP (v[2].y - v[3].y);
13216 del = DET2FP (dx1, dx2, dy1, dy2);
13221 * The division here needs to be done in floating point for
13222 * precisions reasons.
13224 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13225 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13226 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13228 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13229 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13230 RQ[2][0] = UX2FP (v[0].x);
13231 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13232 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13233 RQ[2][1] = UX2FP (v[0].y);
13237 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13238 * square. Since our rectangle is based at 0,0 we only need to scale.
13248 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13251 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13252 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13253 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13254 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13255 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13256 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13257 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13258 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13259 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13262 * Check the resulting matrix is OK.
13264 det = (RQ[0][0] * ST[0][0])
13265 + (RQ[0][1] * ST[0][1])
13266 + (RQ[0][2] * ST[0][2]);
13271 * Now transform our point with the ST matrix; the notional w
13272 * coordinate is 1, hence the last part is simply added.
13277 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13278 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13279 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13297 static ClutterGeometry*
13298 clutter_geometry_copy (const ClutterGeometry *geometry)
13300 return g_slice_dup (ClutterGeometry, geometry);
13304 clutter_geometry_free (ClutterGeometry *geometry)
13306 if (G_LIKELY (geometry != NULL))
13307 g_slice_free (ClutterGeometry, geometry);
13311 * clutter_geometry_union:
13312 * @geometry_a: a #ClutterGeometry
13313 * @geometry_b: another #ClutterGeometry
13314 * @result: (out): location to store the result
13316 * Find the union of two rectangles represented as #ClutterGeometry.
13321 clutter_geometry_union (const ClutterGeometry *geometry_a,
13322 const ClutterGeometry *geometry_b,
13323 ClutterGeometry *result)
13325 /* We don't try to handle rectangles that can't be represented
13326 * as a signed integer box */
13327 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13328 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13329 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13330 geometry_b->x + (gint)geometry_b->width);
13331 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13332 geometry_b->y + (gint)geometry_b->height);
13335 result->width = x_2 - x_1;
13336 result->height = y_2 - y_1;
13340 * clutter_geometry_intersects:
13341 * @geometry0: The first geometry to test
13342 * @geometry1: The second geometry to test
13344 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13345 * they do else %FALSE.
13347 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13353 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13354 const ClutterGeometry *geometry1)
13356 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13357 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13358 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13359 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13366 clutter_geometry_progress (const GValue *a,
13371 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13372 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13373 ClutterGeometry res = { 0, };
13374 gint a_width = a_geom->width;
13375 gint b_width = b_geom->width;
13376 gint a_height = a_geom->height;
13377 gint b_height = b_geom->height;
13379 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13380 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13382 res.width = a_width + (b_width - a_width) * progress;
13383 res.height = a_height + (b_height - a_height) * progress;
13385 g_value_set_boxed (retval, &res);
13390 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13391 clutter_geometry_copy,
13392 clutter_geometry_free,
13393 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13400 * clutter_vertex_new:
13405 * Creates a new #ClutterVertex for the point in 3D space
13406 * identified by the 3 coordinates @x, @y, @z
13408 * Return value: the newly allocate #ClutterVertex. Use
13409 * clutter_vertex_free() to free the resources
13414 clutter_vertex_new (gfloat x,
13418 ClutterVertex *vertex;
13420 vertex = g_slice_new (ClutterVertex);
13421 clutter_vertex_init (vertex, x, y, z);
13427 * clutter_vertex_init:
13428 * @vertex: a #ClutterVertex
13433 * Initializes @vertex with the given coordinates.
13438 clutter_vertex_init (ClutterVertex *vertex,
13443 g_return_if_fail (vertex != NULL);
13451 * clutter_vertex_copy:
13452 * @vertex: a #ClutterVertex
13456 * Return value: a newly allocated copy of #ClutterVertex. Use
13457 * clutter_vertex_free() to free the allocated resources
13462 clutter_vertex_copy (const ClutterVertex *vertex)
13464 if (G_LIKELY (vertex != NULL))
13465 return g_slice_dup (ClutterVertex, vertex);
13471 * clutter_vertex_free:
13472 * @vertex: a #ClutterVertex
13474 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13479 clutter_vertex_free (ClutterVertex *vertex)
13481 if (G_UNLIKELY (vertex != NULL))
13482 g_slice_free (ClutterVertex, vertex);
13486 * clutter_vertex_equal:
13487 * @vertex_a: a #ClutterVertex
13488 * @vertex_b: a #ClutterVertex
13490 * Compares @vertex_a and @vertex_b for equality
13492 * Return value: %TRUE if the passed #ClutterVertex are equal
13497 clutter_vertex_equal (const ClutterVertex *vertex_a,
13498 const ClutterVertex *vertex_b)
13500 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13502 if (vertex_a == vertex_b)
13505 return vertex_a->x == vertex_b->x &&
13506 vertex_a->y == vertex_b->y &&
13507 vertex_a->z == vertex_b->z;
13511 clutter_vertex_progress (const GValue *a,
13516 const ClutterVertex *av = g_value_get_boxed (a);
13517 const ClutterVertex *bv = g_value_get_boxed (b);
13518 ClutterVertex res = { 0, };
13520 res.x = av->x + (bv->x - av->x) * progress;
13521 res.y = av->y + (bv->y - av->y) * progress;
13522 res.z = av->z + (bv->z - av->z) * progress;
13524 g_value_set_boxed (retval, &res);
13529 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13530 clutter_vertex_copy,
13531 clutter_vertex_free,
13532 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13535 * clutter_actor_is_rotated:
13536 * @self: a #ClutterActor
13538 * Checks whether any rotation is applied to the actor.
13540 * Return value: %TRUE if the actor is rotated.
13545 clutter_actor_is_rotated (ClutterActor *self)
13547 const ClutterTransformInfo *info;
13549 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13551 info = _clutter_actor_get_transform_info_or_defaults (self);
13553 if (info->rx_angle || info->ry_angle || info->rz_angle)
13560 * clutter_actor_is_scaled:
13561 * @self: a #ClutterActor
13563 * Checks whether the actor is scaled in either dimension.
13565 * Return value: %TRUE if the actor is scaled.
13570 clutter_actor_is_scaled (ClutterActor *self)
13572 const ClutterTransformInfo *info;
13574 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13576 info = _clutter_actor_get_transform_info_or_defaults (self);
13578 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13585 _clutter_actor_get_stage_internal (ClutterActor *actor)
13587 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13588 actor = actor->priv->parent;
13594 * clutter_actor_get_stage:
13595 * @actor: a #ClutterActor
13597 * Retrieves the #ClutterStage where @actor is contained.
13599 * Return value: (transfer none) (type Clutter.Stage): the stage
13600 * containing the actor, or %NULL
13605 clutter_actor_get_stage (ClutterActor *actor)
13607 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13609 return _clutter_actor_get_stage_internal (actor);
13613 * clutter_actor_allocate_available_size:
13614 * @self: a #ClutterActor
13615 * @x: the actor's X coordinate
13616 * @y: the actor's Y coordinate
13617 * @available_width: the maximum available width, or -1 to use the
13618 * actor's natural width
13619 * @available_height: the maximum available height, or -1 to use the
13620 * actor's natural height
13621 * @flags: flags controlling the allocation
13623 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13624 * preferred size, but limiting it to the maximum available width
13625 * and height provided.
13627 * This function will do the right thing when dealing with the
13628 * actor's request mode.
13630 * The implementation of this function is equivalent to:
13633 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13635 * clutter_actor_get_preferred_width (self, available_height,
13637 * &natural_width);
13638 * width = CLAMP (natural_width, min_width, available_width);
13640 * clutter_actor_get_preferred_height (self, width,
13642 * &natural_height);
13643 * height = CLAMP (natural_height, min_height, available_height);
13647 * clutter_actor_get_preferred_height (self, available_width,
13649 * &natural_height);
13650 * height = CLAMP (natural_height, min_height, available_height);
13652 * clutter_actor_get_preferred_width (self, height,
13654 * &natural_width);
13655 * width = CLAMP (natural_width, min_width, available_width);
13658 * box.x1 = x; box.y1 = y;
13659 * box.x2 = box.x1 + available_width;
13660 * box.y2 = box.y1 + available_height;
13661 * clutter_actor_allocate (self, &box, flags);
13664 * This function can be used by fluid layout managers to allocate
13665 * an actor's preferred size without making it bigger than the area
13666 * available for the container.
13671 clutter_actor_allocate_available_size (ClutterActor *self,
13674 gfloat available_width,
13675 gfloat available_height,
13676 ClutterAllocationFlags flags)
13678 ClutterActorPrivate *priv;
13679 gfloat width, height;
13680 gfloat min_width, min_height;
13681 gfloat natural_width, natural_height;
13682 ClutterActorBox box;
13684 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13688 width = height = 0.0;
13690 switch (priv->request_mode)
13692 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13693 clutter_actor_get_preferred_width (self, available_height,
13696 width = CLAMP (natural_width, min_width, available_width);
13698 clutter_actor_get_preferred_height (self, width,
13701 height = CLAMP (natural_height, min_height, available_height);
13704 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13705 clutter_actor_get_preferred_height (self, available_width,
13708 height = CLAMP (natural_height, min_height, available_height);
13710 clutter_actor_get_preferred_width (self, height,
13713 width = CLAMP (natural_width, min_width, available_width);
13720 box.x2 = box.x1 + width;
13721 box.y2 = box.y1 + height;
13722 clutter_actor_allocate (self, &box, flags);
13726 * clutter_actor_allocate_preferred_size:
13727 * @self: a #ClutterActor
13728 * @flags: flags controlling the allocation
13730 * Allocates the natural size of @self.
13732 * This function is a utility call for #ClutterActor implementations
13733 * that allocates the actor's preferred natural size. It can be used
13734 * by fixed layout managers (like #ClutterGroup or so called
13735 * 'composite actors') inside the ClutterActor::allocate
13736 * implementation to give each child exactly how much space it
13739 * This function is not meant to be used by applications. It is also
13740 * not meant to be used outside the implementation of the
13741 * ClutterActor::allocate virtual function.
13746 clutter_actor_allocate_preferred_size (ClutterActor *self,
13747 ClutterAllocationFlags flags)
13749 gfloat actor_x, actor_y;
13750 gfloat natural_width, natural_height;
13751 ClutterActorBox actor_box;
13753 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13755 actor_x = clutter_actor_get_x (self);
13756 actor_y = clutter_actor_get_y (self);
13758 clutter_actor_get_preferred_size (self,
13763 actor_box.x1 = actor_x;
13764 actor_box.y1 = actor_y;
13765 actor_box.x2 = actor_box.x1 + natural_width;
13766 actor_box.y2 = actor_box.y1 + natural_height;
13768 clutter_actor_allocate (self, &actor_box, flags);
13772 * clutter_actor_allocate_align_fill:
13773 * @self: a #ClutterActor
13774 * @box: a #ClutterActorBox, containing the available width and height
13775 * @x_align: the horizontal alignment, between 0 and 1
13776 * @y_align: the vertical alignment, between 0 and 1
13777 * @x_fill: whether the actor should fill horizontally
13778 * @y_fill: whether the actor should fill vertically
13779 * @flags: allocation flags to be passed to clutter_actor_allocate()
13781 * Allocates @self by taking into consideration the available allocation
13782 * area; an alignment factor on either axis; and whether the actor should
13783 * fill the allocation on either axis.
13785 * The @box should contain the available allocation width and height;
13786 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13787 * allocation will be offset by their value.
13789 * This function takes into consideration the geometry request specified by
13790 * the #ClutterActor:request-mode property, and the text direction.
13792 * This function is useful for fluid layout managers, like #ClutterBinLayout
13793 * or #ClutterTableLayout
13798 clutter_actor_allocate_align_fill (ClutterActor *self,
13799 const ClutterActorBox *box,
13804 ClutterAllocationFlags flags)
13806 ClutterActorPrivate *priv;
13807 ClutterActorBox allocation = { 0, };
13808 gfloat x_offset, y_offset;
13809 gfloat available_width, available_height;
13810 gfloat child_width, child_height;
13812 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13813 g_return_if_fail (box != NULL);
13814 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13815 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13819 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13820 clutter_actor_box_get_size (box, &available_width, &available_height);
13822 if (available_width < 0)
13823 available_width = 0;
13825 if (available_height < 0)
13826 available_height = 0;
13830 allocation.x1 = x_offset;
13831 allocation.x2 = allocation.x1 + available_width;
13836 allocation.y1 = y_offset;
13837 allocation.y2 = allocation.y1 + available_height;
13840 /* if we are filling horizontally and vertically then we're done */
13841 if (x_fill && y_fill)
13844 child_width = child_height = 0.0f;
13846 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13848 gfloat min_width, natural_width;
13849 gfloat min_height, natural_height;
13851 clutter_actor_get_preferred_width (self, available_height,
13855 child_width = CLAMP (natural_width, min_width, available_width);
13859 clutter_actor_get_preferred_height (self, child_width,
13863 child_height = CLAMP (natural_height, min_height, available_height);
13868 gfloat min_width, natural_width;
13869 gfloat min_height, natural_height;
13871 clutter_actor_get_preferred_height (self, available_width,
13875 child_height = CLAMP (natural_height, min_height, available_height);
13879 clutter_actor_get_preferred_width (self, child_height,
13883 child_width = CLAMP (natural_width, min_width, available_width);
13887 /* invert the horizontal alignment for RTL languages */
13888 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13889 x_align = 1.0 - x_align;
13893 allocation.x1 = x_offset
13894 + ((available_width - child_width) * x_align);
13895 allocation.x2 = allocation.x1 + child_width;
13900 allocation.y1 = y_offset
13901 + ((available_height - child_height) * y_align);
13902 allocation.y2 = allocation.y1 + child_height;
13906 clutter_actor_box_clamp_to_pixel (&allocation);
13907 clutter_actor_allocate (self, &allocation, flags);
13911 * clutter_actor_grab_key_focus:
13912 * @self: a #ClutterActor
13914 * Sets the key focus of the #ClutterStage including @self
13915 * to this #ClutterActor.
13920 clutter_actor_grab_key_focus (ClutterActor *self)
13922 ClutterActor *stage;
13924 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13926 stage = _clutter_actor_get_stage_internal (self);
13928 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13932 * clutter_actor_get_pango_context:
13933 * @self: a #ClutterActor
13935 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13936 * is already configured using the appropriate font map, resolution
13937 * and font options.
13939 * Unlike clutter_actor_create_pango_context(), this context is owend
13940 * by the #ClutterActor and it will be updated each time the options
13941 * stored by the #ClutterBackend change.
13943 * You can use the returned #PangoContext to create a #PangoLayout
13944 * and render text using cogl_pango_render_layout() to reuse the
13945 * glyphs cache also used by Clutter.
13947 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13948 * The returned #PangoContext is owned by the actor and should not be
13949 * unreferenced by the application code
13954 clutter_actor_get_pango_context (ClutterActor *self)
13956 ClutterActorPrivate *priv;
13958 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13962 if (priv->pango_context != NULL)
13963 return priv->pango_context;
13965 priv->pango_context = _clutter_context_get_pango_context ();
13966 g_object_ref (priv->pango_context);
13968 return priv->pango_context;
13972 * clutter_actor_create_pango_context:
13973 * @self: a #ClutterActor
13975 * Creates a #PangoContext for the given actor. The #PangoContext
13976 * is already configured using the appropriate font map, resolution
13977 * and font options.
13979 * See also clutter_actor_get_pango_context().
13981 * Return value: (transfer full): the newly created #PangoContext.
13982 * Use g_object_unref() on the returned value to deallocate its
13988 clutter_actor_create_pango_context (ClutterActor *self)
13990 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13992 return _clutter_context_create_pango_context ();
13996 * clutter_actor_create_pango_layout:
13997 * @self: a #ClutterActor
13998 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14000 * Creates a new #PangoLayout from the same #PangoContext used
14001 * by the #ClutterActor. The #PangoLayout is already configured
14002 * with the font map, resolution and font options, and the
14005 * If you want to keep around a #PangoLayout created by this
14006 * function you will have to connect to the #ClutterBackend::font-changed
14007 * and #ClutterBackend::resolution-changed signals, and call
14008 * pango_layout_context_changed() in response to them.
14010 * Return value: (transfer full): the newly created #PangoLayout.
14011 * Use g_object_unref() when done
14016 clutter_actor_create_pango_layout (ClutterActor *self,
14019 PangoContext *context;
14020 PangoLayout *layout;
14022 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14024 context = clutter_actor_get_pango_context (self);
14025 layout = pango_layout_new (context);
14028 pango_layout_set_text (layout, text, -1);
14033 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14034 * ClutterOffscreenEffect.
14037 _clutter_actor_set_opacity_override (ClutterActor *self,
14040 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14042 self->priv->opacity_override = opacity;
14046 _clutter_actor_get_opacity_override (ClutterActor *self)
14048 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14050 return self->priv->opacity_override;
14053 /* Allows you to disable applying the actors model view transform during
14054 * a paint. Used by ClutterClone. */
14056 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14059 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14061 self->priv->enable_model_view_transform = enable;
14065 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14068 ClutterActorPrivate *priv;
14070 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14074 priv->enable_paint_unmapped = enable;
14076 if (priv->enable_paint_unmapped)
14078 /* Make sure that the parents of the widget are realized first;
14079 * otherwise checks in clutter_actor_update_map_state() will
14082 clutter_actor_realize (self);
14084 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14088 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14093 clutter_anchor_coord_get_units (ClutterActor *self,
14094 const AnchorCoord *coord,
14099 if (coord->is_fractional)
14101 gfloat actor_width, actor_height;
14103 clutter_actor_get_size (self, &actor_width, &actor_height);
14106 *x = actor_width * coord->v.fraction.x;
14109 *y = actor_height * coord->v.fraction.y;
14117 *x = coord->v.units.x;
14120 *y = coord->v.units.y;
14123 *z = coord->v.units.z;
14128 clutter_anchor_coord_set_units (AnchorCoord *coord,
14133 coord->is_fractional = FALSE;
14134 coord->v.units.x = x;
14135 coord->v.units.y = y;
14136 coord->v.units.z = z;
14139 static ClutterGravity
14140 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14142 if (coord->is_fractional)
14144 if (coord->v.fraction.x == 0.0)
14146 if (coord->v.fraction.y == 0.0)
14147 return CLUTTER_GRAVITY_NORTH_WEST;
14148 else if (coord->v.fraction.y == 0.5)
14149 return CLUTTER_GRAVITY_WEST;
14150 else if (coord->v.fraction.y == 1.0)
14151 return CLUTTER_GRAVITY_SOUTH_WEST;
14153 return CLUTTER_GRAVITY_NONE;
14155 else if (coord->v.fraction.x == 0.5)
14157 if (coord->v.fraction.y == 0.0)
14158 return CLUTTER_GRAVITY_NORTH;
14159 else if (coord->v.fraction.y == 0.5)
14160 return CLUTTER_GRAVITY_CENTER;
14161 else if (coord->v.fraction.y == 1.0)
14162 return CLUTTER_GRAVITY_SOUTH;
14164 return CLUTTER_GRAVITY_NONE;
14166 else if (coord->v.fraction.x == 1.0)
14168 if (coord->v.fraction.y == 0.0)
14169 return CLUTTER_GRAVITY_NORTH_EAST;
14170 else if (coord->v.fraction.y == 0.5)
14171 return CLUTTER_GRAVITY_EAST;
14172 else if (coord->v.fraction.y == 1.0)
14173 return CLUTTER_GRAVITY_SOUTH_EAST;
14175 return CLUTTER_GRAVITY_NONE;
14178 return CLUTTER_GRAVITY_NONE;
14181 return CLUTTER_GRAVITY_NONE;
14185 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14186 ClutterGravity gravity)
14190 case CLUTTER_GRAVITY_NORTH:
14191 coord->v.fraction.x = 0.5;
14192 coord->v.fraction.y = 0.0;
14195 case CLUTTER_GRAVITY_NORTH_EAST:
14196 coord->v.fraction.x = 1.0;
14197 coord->v.fraction.y = 0.0;
14200 case CLUTTER_GRAVITY_EAST:
14201 coord->v.fraction.x = 1.0;
14202 coord->v.fraction.y = 0.5;
14205 case CLUTTER_GRAVITY_SOUTH_EAST:
14206 coord->v.fraction.x = 1.0;
14207 coord->v.fraction.y = 1.0;
14210 case CLUTTER_GRAVITY_SOUTH:
14211 coord->v.fraction.x = 0.5;
14212 coord->v.fraction.y = 1.0;
14215 case CLUTTER_GRAVITY_SOUTH_WEST:
14216 coord->v.fraction.x = 0.0;
14217 coord->v.fraction.y = 1.0;
14220 case CLUTTER_GRAVITY_WEST:
14221 coord->v.fraction.x = 0.0;
14222 coord->v.fraction.y = 0.5;
14225 case CLUTTER_GRAVITY_NORTH_WEST:
14226 coord->v.fraction.x = 0.0;
14227 coord->v.fraction.y = 0.0;
14230 case CLUTTER_GRAVITY_CENTER:
14231 coord->v.fraction.x = 0.5;
14232 coord->v.fraction.y = 0.5;
14236 coord->v.fraction.x = 0.0;
14237 coord->v.fraction.y = 0.0;
14241 coord->is_fractional = TRUE;
14245 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14247 if (coord->is_fractional)
14248 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14250 return (coord->v.units.x == 0.0
14251 && coord->v.units.y == 0.0
14252 && coord->v.units.z == 0.0);
14256 * clutter_actor_get_flags:
14257 * @self: a #ClutterActor
14259 * Retrieves the flags set on @self
14261 * Return value: a bitwise or of #ClutterActorFlags or 0
14266 clutter_actor_get_flags (ClutterActor *self)
14268 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14270 return self->flags;
14274 * clutter_actor_set_flags:
14275 * @self: a #ClutterActor
14276 * @flags: the flags to set
14278 * Sets @flags on @self
14280 * This function will emit notifications for the changed properties
14285 clutter_actor_set_flags (ClutterActor *self,
14286 ClutterActorFlags flags)
14288 ClutterActorFlags old_flags;
14290 gboolean was_reactive_set, reactive_set;
14291 gboolean was_realized_set, realized_set;
14292 gboolean was_mapped_set, mapped_set;
14293 gboolean was_visible_set, visible_set;
14295 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14297 if (self->flags == flags)
14300 obj = G_OBJECT (self);
14301 g_object_ref (obj);
14302 g_object_freeze_notify (obj);
14304 old_flags = self->flags;
14306 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14307 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14308 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14309 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14311 self->flags |= flags;
14313 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14314 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14315 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14316 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14318 if (reactive_set != was_reactive_set)
14319 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14321 if (realized_set != was_realized_set)
14322 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14324 if (mapped_set != was_mapped_set)
14325 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14327 if (visible_set != was_visible_set)
14328 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14330 g_object_thaw_notify (obj);
14331 g_object_unref (obj);
14335 * clutter_actor_unset_flags:
14336 * @self: a #ClutterActor
14337 * @flags: the flags to unset
14339 * Unsets @flags on @self
14341 * This function will emit notifications for the changed properties
14346 clutter_actor_unset_flags (ClutterActor *self,
14347 ClutterActorFlags flags)
14349 ClutterActorFlags old_flags;
14351 gboolean was_reactive_set, reactive_set;
14352 gboolean was_realized_set, realized_set;
14353 gboolean was_mapped_set, mapped_set;
14354 gboolean was_visible_set, visible_set;
14356 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14358 obj = G_OBJECT (self);
14359 g_object_freeze_notify (obj);
14361 old_flags = self->flags;
14363 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14364 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14365 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14366 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14368 self->flags &= ~flags;
14370 if (self->flags == old_flags)
14373 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14374 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14375 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14376 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14378 if (reactive_set != was_reactive_set)
14379 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14381 if (realized_set != was_realized_set)
14382 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14384 if (mapped_set != was_mapped_set)
14385 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14387 if (visible_set != was_visible_set)
14388 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14390 g_object_thaw_notify (obj);
14394 * clutter_actor_get_transformation_matrix:
14395 * @self: a #ClutterActor
14396 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14398 * Retrieves the transformations applied to @self relative to its
14404 clutter_actor_get_transformation_matrix (ClutterActor *self,
14405 CoglMatrix *matrix)
14407 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14409 cogl_matrix_init_identity (matrix);
14411 _clutter_actor_apply_modelview_transform (self, matrix);
14415 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14416 gboolean is_in_clone_paint)
14418 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14419 self->priv->in_clone_paint = is_in_clone_paint;
14423 * clutter_actor_is_in_clone_paint:
14424 * @self: a #ClutterActor
14426 * Checks whether @self is being currently painted by a #ClutterClone
14428 * This function is useful only inside the ::paint virtual function
14429 * implementations or within handlers for the #ClutterActor::paint
14432 * This function should not be used by applications
14434 * Return value: %TRUE if the #ClutterActor is currently being painted
14435 * by a #ClutterClone, and %FALSE otherwise
14440 clutter_actor_is_in_clone_paint (ClutterActor *self)
14442 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14444 return self->priv->in_clone_paint;
14448 set_direction_recursive (ClutterActor *actor,
14449 gpointer user_data)
14451 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14453 clutter_actor_set_text_direction (actor, text_dir);
14459 * clutter_actor_set_text_direction:
14460 * @self: a #ClutterActor
14461 * @text_dir: the text direction for @self
14463 * Sets the #ClutterTextDirection for an actor
14465 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14467 * If @self implements #ClutterContainer then this function will recurse
14468 * inside all the children of @self (including the internal ones).
14470 * Composite actors not implementing #ClutterContainer, or actors requiring
14471 * special handling when the text direction changes, should connect to
14472 * the #GObject::notify signal for the #ClutterActor:text-direction property
14477 clutter_actor_set_text_direction (ClutterActor *self,
14478 ClutterTextDirection text_dir)
14480 ClutterActorPrivate *priv;
14482 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14483 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14487 if (priv->text_direction != text_dir)
14489 priv->text_direction = text_dir;
14491 /* we need to emit the notify::text-direction first, so that
14492 * the sub-classes can catch that and do specific handling of
14493 * the text direction; see clutter_text_direction_changed_cb()
14494 * inside clutter-text.c
14496 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14498 _clutter_actor_foreach_child (self, set_direction_recursive,
14499 GINT_TO_POINTER (text_dir));
14501 clutter_actor_queue_relayout (self);
14506 _clutter_actor_set_has_pointer (ClutterActor *self,
14507 gboolean has_pointer)
14509 ClutterActorPrivate *priv = self->priv;
14511 if (priv->has_pointer != has_pointer)
14513 priv->has_pointer = has_pointer;
14515 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14520 * clutter_actor_get_text_direction:
14521 * @self: a #ClutterActor
14523 * Retrieves the value set using clutter_actor_set_text_direction()
14525 * If no text direction has been previously set, the default text
14526 * direction, as returned by clutter_get_default_text_direction(), will
14527 * be returned instead
14529 * Return value: the #ClutterTextDirection for the actor
14533 ClutterTextDirection
14534 clutter_actor_get_text_direction (ClutterActor *self)
14536 ClutterActorPrivate *priv;
14538 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14539 CLUTTER_TEXT_DIRECTION_LTR);
14543 /* if no direction has been set yet use the default */
14544 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14545 priv->text_direction = clutter_get_default_text_direction ();
14547 return priv->text_direction;
14551 * clutter_actor_push_internal:
14552 * @self: a #ClutterActor
14554 * Should be used by actors implementing the #ClutterContainer and with
14555 * internal children added through clutter_actor_set_parent(), for instance:
14559 * my_actor_init (MyActor *self)
14561 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14563 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14565 * /* calling clutter_actor_set_parent() now will result in
14566 * * the internal flag being set on a child of MyActor
14569 * /* internal child - a background texture */
14570 * self->priv->background_tex = clutter_texture_new ();
14571 * clutter_actor_set_parent (self->priv->background_tex,
14572 * CLUTTER_ACTOR (self));
14574 * /* internal child - a label */
14575 * self->priv->label = clutter_text_new ();
14576 * clutter_actor_set_parent (self->priv->label,
14577 * CLUTTER_ACTOR (self));
14579 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14581 * /* calling clutter_actor_set_parent() now will not result in
14582 * * the internal flag being set on a child of MyActor
14587 * This function will be used by Clutter to toggle an "internal child"
14588 * flag whenever clutter_actor_set_parent() is called; internal children
14589 * are handled differently by Clutter, specifically when destroying their
14592 * Call clutter_actor_pop_internal() when you finished adding internal
14595 * Nested calls to clutter_actor_push_internal() are allowed, but each
14596 * one must by followed by a clutter_actor_pop_internal() call.
14600 * Deprecated: 1.10: All children of an actor are accessible through
14601 * the #ClutterActor API, and #ClutterActor implements the
14602 * #ClutterContainer interface, so this function is only useful
14603 * for legacy containers overriding the default implementation.
14606 clutter_actor_push_internal (ClutterActor *self)
14608 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14610 self->priv->internal_child += 1;
14614 * clutter_actor_pop_internal:
14615 * @self: a #ClutterActor
14617 * Disables the effects of clutter_actor_push_internal().
14621 * Deprecated: 1.10: All children of an actor are accessible through
14622 * the #ClutterActor API. This function is only useful for legacy
14623 * containers overriding the default implementation of the
14624 * #ClutterContainer interface.
14627 clutter_actor_pop_internal (ClutterActor *self)
14629 ClutterActorPrivate *priv;
14631 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14635 if (priv->internal_child == 0)
14637 g_warning ("Mismatched %s: you need to call "
14638 "clutter_actor_push_composite() at least once before "
14639 "calling this function", G_STRFUNC);
14643 priv->internal_child -= 1;
14647 * clutter_actor_has_pointer:
14648 * @self: a #ClutterActor
14650 * Checks whether an actor contains the pointer of a
14651 * #ClutterInputDevice
14653 * Return value: %TRUE if the actor contains the pointer, and
14659 clutter_actor_has_pointer (ClutterActor *self)
14661 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14663 return self->priv->has_pointer;
14666 /* XXX: This is a workaround for not being able to break the ABI of
14667 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14668 * clutter_actor_queue_clipped_redraw() for details.
14670 ClutterPaintVolume *
14671 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14673 return g_object_get_data (G_OBJECT (self),
14674 "-clutter-actor-queue-redraw-clip");
14678 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14679 ClutterPaintVolume *clip)
14681 g_object_set_data (G_OBJECT (self),
14682 "-clutter-actor-queue-redraw-clip",
14687 * clutter_actor_has_allocation:
14688 * @self: a #ClutterActor
14690 * Checks if the actor has an up-to-date allocation assigned to
14691 * it. This means that the actor should have an allocation: it's
14692 * visible and has a parent. It also means that there is no
14693 * outstanding relayout request in progress for the actor or its
14694 * children (There might be other outstanding layout requests in
14695 * progress that will cause the actor to get a new allocation
14696 * when the stage is laid out, however).
14698 * If this function returns %FALSE, then the actor will normally
14699 * be allocated before it is next drawn on the screen.
14701 * Return value: %TRUE if the actor has an up-to-date allocation
14706 clutter_actor_has_allocation (ClutterActor *self)
14708 ClutterActorPrivate *priv;
14710 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14714 return priv->parent != NULL &&
14715 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14716 !priv->needs_allocation;
14720 * clutter_actor_add_action:
14721 * @self: a #ClutterActor
14722 * @action: a #ClutterAction
14724 * Adds @action to the list of actions applied to @self
14726 * A #ClutterAction can only belong to one actor at a time
14728 * The #ClutterActor will hold a reference on @action until either
14729 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14735 clutter_actor_add_action (ClutterActor *self,
14736 ClutterAction *action)
14738 ClutterActorPrivate *priv;
14740 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14741 g_return_if_fail (CLUTTER_IS_ACTION (action));
14745 if (priv->actions == NULL)
14747 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14748 priv->actions->actor = self;
14751 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14753 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14757 * clutter_actor_add_action_with_name:
14758 * @self: a #ClutterActor
14759 * @name: the name to set on the action
14760 * @action: a #ClutterAction
14762 * A convenience function for setting the name of a #ClutterAction
14763 * while adding it to the list of actions applied to @self
14765 * This function is the logical equivalent of:
14768 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14769 * clutter_actor_add_action (self, action);
14775 clutter_actor_add_action_with_name (ClutterActor *self,
14777 ClutterAction *action)
14779 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14780 g_return_if_fail (name != NULL);
14781 g_return_if_fail (CLUTTER_IS_ACTION (action));
14783 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14784 clutter_actor_add_action (self, action);
14788 * clutter_actor_remove_action:
14789 * @self: a #ClutterActor
14790 * @action: a #ClutterAction
14792 * Removes @action from the list of actions applied to @self
14794 * The reference held by @self on the #ClutterAction will be released
14799 clutter_actor_remove_action (ClutterActor *self,
14800 ClutterAction *action)
14802 ClutterActorPrivate *priv;
14804 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14805 g_return_if_fail (CLUTTER_IS_ACTION (action));
14809 if (priv->actions == NULL)
14812 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14814 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14818 * clutter_actor_remove_action_by_name:
14819 * @self: a #ClutterActor
14820 * @name: the name of the action to remove
14822 * Removes the #ClutterAction with the given name from the list
14823 * of actions applied to @self
14828 clutter_actor_remove_action_by_name (ClutterActor *self,
14831 ClutterActorPrivate *priv;
14832 ClutterActorMeta *meta;
14834 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14835 g_return_if_fail (name != NULL);
14839 if (priv->actions == NULL)
14842 meta = _clutter_meta_group_get_meta (priv->actions, name);
14846 _clutter_meta_group_remove_meta (priv->actions, meta);
14848 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14852 * clutter_actor_get_actions:
14853 * @self: a #ClutterActor
14855 * Retrieves the list of actions applied to @self
14857 * Return value: (transfer container) (element-type Clutter.Action): a copy
14858 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14859 * owned by the #ClutterActor. Use g_list_free() to free the resources
14860 * allocated by the returned #GList
14865 clutter_actor_get_actions (ClutterActor *self)
14867 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14869 if (self->priv->actions == NULL)
14872 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14876 * clutter_actor_get_action:
14877 * @self: a #ClutterActor
14878 * @name: the name of the action to retrieve
14880 * Retrieves the #ClutterAction with the given name in the list
14881 * of actions applied to @self
14883 * Return value: (transfer none): a #ClutterAction for the given
14884 * name, or %NULL. The returned #ClutterAction is owned by the
14885 * actor and it should not be unreferenced directly
14890 clutter_actor_get_action (ClutterActor *self,
14893 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14894 g_return_val_if_fail (name != NULL, NULL);
14896 if (self->priv->actions == NULL)
14899 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14903 * clutter_actor_clear_actions:
14904 * @self: a #ClutterActor
14906 * Clears the list of actions applied to @self
14911 clutter_actor_clear_actions (ClutterActor *self)
14913 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14915 if (self->priv->actions == NULL)
14918 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14922 * clutter_actor_add_constraint:
14923 * @self: a #ClutterActor
14924 * @constraint: a #ClutterConstraint
14926 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14929 * The #ClutterActor will hold a reference on the @constraint until
14930 * either clutter_actor_remove_constraint() or
14931 * clutter_actor_clear_constraints() is called.
14936 clutter_actor_add_constraint (ClutterActor *self,
14937 ClutterConstraint *constraint)
14939 ClutterActorPrivate *priv;
14941 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14942 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14946 if (priv->constraints == NULL)
14948 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14949 priv->constraints->actor = self;
14952 _clutter_meta_group_add_meta (priv->constraints,
14953 CLUTTER_ACTOR_META (constraint));
14954 clutter_actor_queue_relayout (self);
14956 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14960 * clutter_actor_add_constraint_with_name:
14961 * @self: a #ClutterActor
14962 * @name: the name to set on the constraint
14963 * @constraint: a #ClutterConstraint
14965 * A convenience function for setting the name of a #ClutterConstraint
14966 * while adding it to the list of constraints applied to @self
14968 * This function is the logical equivalent of:
14971 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14972 * clutter_actor_add_constraint (self, constraint);
14978 clutter_actor_add_constraint_with_name (ClutterActor *self,
14980 ClutterConstraint *constraint)
14982 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14983 g_return_if_fail (name != NULL);
14984 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14986 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14987 clutter_actor_add_constraint (self, constraint);
14991 * clutter_actor_remove_constraint:
14992 * @self: a #ClutterActor
14993 * @constraint: a #ClutterConstraint
14995 * Removes @constraint from the list of constraints applied to @self
14997 * The reference held by @self on the #ClutterConstraint will be released
15002 clutter_actor_remove_constraint (ClutterActor *self,
15003 ClutterConstraint *constraint)
15005 ClutterActorPrivate *priv;
15007 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15008 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15012 if (priv->constraints == NULL)
15015 _clutter_meta_group_remove_meta (priv->constraints,
15016 CLUTTER_ACTOR_META (constraint));
15017 clutter_actor_queue_relayout (self);
15019 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15023 * clutter_actor_remove_constraint_by_name:
15024 * @self: a #ClutterActor
15025 * @name: the name of the constraint to remove
15027 * Removes the #ClutterConstraint with the given name from the list
15028 * of constraints applied to @self
15033 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15036 ClutterActorPrivate *priv;
15037 ClutterActorMeta *meta;
15039 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15040 g_return_if_fail (name != NULL);
15044 if (priv->constraints == NULL)
15047 meta = _clutter_meta_group_get_meta (priv->constraints, name);
15051 _clutter_meta_group_remove_meta (priv->constraints, meta);
15052 clutter_actor_queue_relayout (self);
15056 * clutter_actor_get_constraints:
15057 * @self: a #ClutterActor
15059 * Retrieves the list of constraints applied to @self
15061 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15062 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15063 * owned by the #ClutterActor. Use g_list_free() to free the resources
15064 * allocated by the returned #GList
15069 clutter_actor_get_constraints (ClutterActor *self)
15071 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15073 if (self->priv->constraints == NULL)
15076 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15080 * clutter_actor_get_constraint:
15081 * @self: a #ClutterActor
15082 * @name: the name of the constraint to retrieve
15084 * Retrieves the #ClutterConstraint with the given name in the list
15085 * of constraints applied to @self
15087 * Return value: (transfer none): a #ClutterConstraint for the given
15088 * name, or %NULL. The returned #ClutterConstraint is owned by the
15089 * actor and it should not be unreferenced directly
15093 ClutterConstraint *
15094 clutter_actor_get_constraint (ClutterActor *self,
15097 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15098 g_return_val_if_fail (name != NULL, NULL);
15100 if (self->priv->constraints == NULL)
15103 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15107 * clutter_actor_clear_constraints:
15108 * @self: a #ClutterActor
15110 * Clears the list of constraints applied to @self
15115 clutter_actor_clear_constraints (ClutterActor *self)
15117 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15119 if (self->priv->constraints == NULL)
15122 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15124 clutter_actor_queue_relayout (self);
15128 * clutter_actor_set_clip_to_allocation:
15129 * @self: a #ClutterActor
15130 * @clip_set: %TRUE to apply a clip tracking the allocation
15132 * Sets whether @self should be clipped to the same size as its
15138 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15141 ClutterActorPrivate *priv;
15143 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15145 clip_set = !!clip_set;
15149 if (priv->clip_to_allocation != clip_set)
15151 priv->clip_to_allocation = clip_set;
15153 clutter_actor_queue_redraw (self);
15155 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15160 * clutter_actor_get_clip_to_allocation:
15161 * @self: a #ClutterActor
15163 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15165 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15170 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15172 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15174 return self->priv->clip_to_allocation;
15178 * clutter_actor_add_effect:
15179 * @self: a #ClutterActor
15180 * @effect: a #ClutterEffect
15182 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15184 * The #ClutterActor will hold a reference on the @effect until either
15185 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15191 clutter_actor_add_effect (ClutterActor *self,
15192 ClutterEffect *effect)
15194 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15195 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15197 _clutter_actor_add_effect_internal (self, effect);
15199 clutter_actor_queue_redraw (self);
15201 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15205 * clutter_actor_add_effect_with_name:
15206 * @self: a #ClutterActor
15207 * @name: the name to set on the effect
15208 * @effect: a #ClutterEffect
15210 * A convenience function for setting the name of a #ClutterEffect
15211 * while adding it to the list of effectss applied to @self
15213 * This function is the logical equivalent of:
15216 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15217 * clutter_actor_add_effect (self, effect);
15223 clutter_actor_add_effect_with_name (ClutterActor *self,
15225 ClutterEffect *effect)
15227 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15228 g_return_if_fail (name != NULL);
15229 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15231 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15232 clutter_actor_add_effect (self, effect);
15236 * clutter_actor_remove_effect:
15237 * @self: a #ClutterActor
15238 * @effect: a #ClutterEffect
15240 * Removes @effect from the list of effects applied to @self
15242 * The reference held by @self on the #ClutterEffect will be released
15247 clutter_actor_remove_effect (ClutterActor *self,
15248 ClutterEffect *effect)
15250 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15251 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15253 _clutter_actor_remove_effect_internal (self, effect);
15255 clutter_actor_queue_redraw (self);
15257 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15261 * clutter_actor_remove_effect_by_name:
15262 * @self: a #ClutterActor
15263 * @name: the name of the effect to remove
15265 * Removes the #ClutterEffect with the given name from the list
15266 * of effects applied to @self
15271 clutter_actor_remove_effect_by_name (ClutterActor *self,
15274 ClutterActorPrivate *priv;
15275 ClutterActorMeta *meta;
15277 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15278 g_return_if_fail (name != NULL);
15282 if (priv->effects == NULL)
15285 meta = _clutter_meta_group_get_meta (priv->effects, name);
15289 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15293 * clutter_actor_get_effects:
15294 * @self: a #ClutterActor
15296 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15298 * Return value: (transfer container) (element-type Clutter.Effect): a list
15299 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15300 * list are owned by Clutter and they should not be freed. You should
15301 * free the returned list using g_list_free() when done
15306 clutter_actor_get_effects (ClutterActor *self)
15308 ClutterActorPrivate *priv;
15310 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15314 if (priv->effects == NULL)
15317 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15321 * clutter_actor_get_effect:
15322 * @self: a #ClutterActor
15323 * @name: the name of the effect to retrieve
15325 * Retrieves the #ClutterEffect with the given name in the list
15326 * of effects applied to @self
15328 * Return value: (transfer none): a #ClutterEffect for the given
15329 * name, or %NULL. The returned #ClutterEffect is owned by the
15330 * actor and it should not be unreferenced directly
15335 clutter_actor_get_effect (ClutterActor *self,
15338 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15339 g_return_val_if_fail (name != NULL, NULL);
15341 if (self->priv->effects == NULL)
15344 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15348 * clutter_actor_clear_effects:
15349 * @self: a #ClutterActor
15351 * Clears the list of effects applied to @self
15356 clutter_actor_clear_effects (ClutterActor *self)
15358 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15360 if (self->priv->effects == NULL)
15363 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15365 clutter_actor_queue_redraw (self);
15369 * clutter_actor_has_key_focus:
15370 * @self: a #ClutterActor
15372 * Checks whether @self is the #ClutterActor that has key focus
15374 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15379 clutter_actor_has_key_focus (ClutterActor *self)
15381 ClutterActor *stage;
15383 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15385 stage = _clutter_actor_get_stage_internal (self);
15389 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15393 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15394 ClutterPaintVolume *pv)
15396 ClutterActorPrivate *priv = self->priv;
15398 /* Actors are only expected to report a valid paint volume
15399 * while they have a valid allocation. */
15400 if (G_UNLIKELY (priv->needs_allocation))
15402 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15403 "Actor needs allocation",
15404 _clutter_actor_get_debug_name (self));
15408 /* Check if there are any handlers connected to the paint
15409 * signal. If there are then all bets are off for what the paint
15410 * volume for this actor might possibly be!
15412 * XXX: It's expected that this is going to end up being quite a
15413 * costly check to have to do here, but we haven't come up with
15414 * another solution that can reliably catch paint signal handlers at
15415 * the right time to either avoid artefacts due to invalid stage
15416 * clipping or due to incorrect culling.
15418 * Previously we checked in clutter_actor_paint(), but at that time
15419 * we may already be using a stage clip that could be derived from
15420 * an invalid paint-volume. We used to try and handle that by
15421 * queuing a follow up, unclipped, redraw but still the previous
15422 * checking wasn't enough to catch invalid volumes involved in
15423 * culling (considering that containers may derive their volume from
15424 * children that haven't yet been painted)
15426 * Longer term, improved solutions could be:
15427 * - Disallow painting in the paint signal, only allow using it
15428 * for tracking when paints happen. We can add another API that
15429 * allows monkey patching the paint of arbitrary actors but in a
15430 * more controlled way and that also supports modifying the
15432 * - If we could be notified somehow when signal handlers are
15433 * connected we wouldn't have to poll for handlers like this.
15435 if (g_signal_has_handler_pending (self,
15436 actor_signals[PAINT],
15440 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15441 "Actor has \"paint\" signal handlers",
15442 _clutter_actor_get_debug_name (self));
15446 _clutter_paint_volume_init_static (pv, self);
15448 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15450 clutter_paint_volume_free (pv);
15451 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15452 "Actor failed to report a volume",
15453 _clutter_actor_get_debug_name (self));
15457 /* since effects can modify the paint volume, we allow them to actually
15458 * do this by making get_paint_volume() "context sensitive"
15460 if (priv->effects != NULL)
15462 if (priv->current_effect != NULL)
15464 const GList *effects, *l;
15466 /* if we are being called from within the paint sequence of
15467 * an actor, get the paint volume up to the current effect
15469 effects = _clutter_meta_group_peek_metas (priv->effects);
15471 l != NULL || (l != NULL && l->data != priv->current_effect);
15474 if (!_clutter_effect_get_paint_volume (l->data, pv))
15476 clutter_paint_volume_free (pv);
15477 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15478 "Effect (%s) failed to report a volume",
15479 _clutter_actor_get_debug_name (self),
15480 _clutter_actor_meta_get_debug_name (l->data));
15487 const GList *effects, *l;
15489 /* otherwise, get the cumulative volume */
15490 effects = _clutter_meta_group_peek_metas (priv->effects);
15491 for (l = effects; l != NULL; l = l->next)
15492 if (!_clutter_effect_get_paint_volume (l->data, pv))
15494 clutter_paint_volume_free (pv);
15495 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15496 "Effect (%s) failed to report a volume",
15497 _clutter_actor_get_debug_name (self),
15498 _clutter_actor_meta_get_debug_name (l->data));
15507 /* The public clutter_actor_get_paint_volume API returns a const
15508 * pointer since we return a pointer directly to the cached
15509 * PaintVolume associated with the actor and don't want the user to
15510 * inadvertently modify it, but for internal uses we sometimes need
15511 * access to the same PaintVolume but need to apply some book-keeping
15512 * modifications to it so we don't want a const pointer.
15514 static ClutterPaintVolume *
15515 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15517 ClutterActorPrivate *priv;
15521 if (priv->paint_volume_valid)
15522 clutter_paint_volume_free (&priv->paint_volume);
15524 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15526 priv->paint_volume_valid = TRUE;
15527 return &priv->paint_volume;
15531 priv->paint_volume_valid = FALSE;
15537 * clutter_actor_get_paint_volume:
15538 * @self: a #ClutterActor
15540 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15541 * when a paint volume can't be determined.
15543 * The paint volume is defined as the 3D space occupied by an actor
15544 * when being painted.
15546 * This function will call the <function>get_paint_volume()</function>
15547 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15548 * should not usually care about overriding the default implementation,
15549 * unless they are, for instance: painting outside their allocation, or
15550 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15553 * <note>2D actors overriding <function>get_paint_volume()</function>
15554 * ensure their volume has a depth of 0. (This will be true so long as
15555 * you don't call clutter_paint_volume_set_depth().)</note>
15557 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15558 * or %NULL if no volume could be determined. The returned pointer
15559 * is not guaranteed to be valid across multiple frames; if you want
15560 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15564 const ClutterPaintVolume *
15565 clutter_actor_get_paint_volume (ClutterActor *self)
15567 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15569 return _clutter_actor_get_paint_volume_mutable (self);
15573 * clutter_actor_get_transformed_paint_volume:
15574 * @self: a #ClutterActor
15575 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15576 * (or %NULL for the stage)
15578 * Retrieves the 3D paint volume of an actor like
15579 * clutter_actor_get_paint_volume() does (Please refer to the
15580 * documentation of clutter_actor_get_paint_volume() for more
15581 * details.) and it additionally transforms the paint volume into the
15582 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15583 * is passed for @relative_to_ancestor)
15585 * This can be used by containers that base their paint volume on
15586 * the volume of their children. Such containers can query the
15587 * transformed paint volume of all of its children and union them
15588 * together using clutter_paint_volume_union().
15590 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15591 * or %NULL if no volume could be determined. The returned pointer is
15592 * not guaranteed to be valid across multiple frames; if you wish to
15593 * keep it, you will have to copy it using clutter_paint_volume_copy().
15597 const ClutterPaintVolume *
15598 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15599 ClutterActor *relative_to_ancestor)
15601 const ClutterPaintVolume *volume;
15602 ClutterActor *stage;
15603 ClutterPaintVolume *transformed_volume;
15605 stage = _clutter_actor_get_stage_internal (self);
15606 if (G_UNLIKELY (stage == NULL))
15609 if (relative_to_ancestor == NULL)
15610 relative_to_ancestor = stage;
15612 volume = clutter_actor_get_paint_volume (self);
15613 if (volume == NULL)
15616 transformed_volume =
15617 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15619 _clutter_paint_volume_copy_static (volume, transformed_volume);
15621 _clutter_paint_volume_transform_relative (transformed_volume,
15622 relative_to_ancestor);
15624 return transformed_volume;
15628 * clutter_actor_get_paint_box:
15629 * @self: a #ClutterActor
15630 * @box: (out): return location for a #ClutterActorBox
15632 * Retrieves the paint volume of the passed #ClutterActor, and
15633 * transforms it into a 2D bounding box in stage coordinates.
15635 * This function is useful to determine the on screen area occupied by
15636 * the actor. The box is only an approximation and may often be
15637 * considerably larger due to the optimizations used to calculate the
15638 * box. The box is never smaller though, so it can reliably be used
15641 * There are times when a 2D paint box can't be determined, e.g.
15642 * because the actor isn't yet parented under a stage or because
15643 * the actor is unable to determine a paint volume.
15645 * Return value: %TRUE if a 2D paint box could be determined, else
15651 clutter_actor_get_paint_box (ClutterActor *self,
15652 ClutterActorBox *box)
15654 ClutterActor *stage;
15655 ClutterPaintVolume *pv;
15657 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15658 g_return_val_if_fail (box != NULL, FALSE);
15660 stage = _clutter_actor_get_stage_internal (self);
15661 if (G_UNLIKELY (!stage))
15664 pv = _clutter_actor_get_paint_volume_mutable (self);
15665 if (G_UNLIKELY (!pv))
15668 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15674 * clutter_actor_has_overlaps:
15675 * @self: A #ClutterActor
15677 * Asks the actor's implementation whether it may contain overlapping
15680 * For example; Clutter may use this to determine whether the painting
15681 * should be redirected to an offscreen buffer to correctly implement
15682 * the opacity property.
15684 * Custom actors can override the default response by implementing the
15685 * #ClutterActor <function>has_overlaps</function> virtual function. See
15686 * clutter_actor_set_offscreen_redirect() for more information.
15688 * Return value: %TRUE if the actor may have overlapping primitives, and
15694 clutter_actor_has_overlaps (ClutterActor *self)
15696 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15698 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15702 * clutter_actor_has_effects:
15703 * @self: A #ClutterActor
15705 * Returns whether the actor has any effects applied.
15707 * Return value: %TRUE if the actor has any effects,
15713 clutter_actor_has_effects (ClutterActor *self)
15715 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15717 if (self->priv->effects == NULL)
15720 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15724 * clutter_actor_has_constraints:
15725 * @self: A #ClutterActor
15727 * Returns whether the actor has any constraints applied.
15729 * Return value: %TRUE if the actor has any constraints,
15735 clutter_actor_has_constraints (ClutterActor *self)
15737 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15739 return self->priv->constraints != NULL;
15743 * clutter_actor_has_actions:
15744 * @self: A #ClutterActor
15746 * Returns whether the actor has any actions applied.
15748 * Return value: %TRUE if the actor has any actions,
15754 clutter_actor_has_actions (ClutterActor *self)
15756 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15758 return self->priv->actions != NULL;
15762 * clutter_actor_get_n_children:
15763 * @self: a #ClutterActor
15765 * Retrieves the number of children of @self.
15767 * Return value: the number of children of an actor
15772 clutter_actor_get_n_children (ClutterActor *self)
15774 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15776 return self->priv->n_children;
15780 * clutter_actor_get_child_at_index:
15781 * @self: a #ClutterActor
15782 * @index_: the position in the list of children
15784 * Retrieves the actor at the given @index_ inside the list of
15785 * children of @self.
15787 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15792 clutter_actor_get_child_at_index (ClutterActor *self,
15795 ClutterActor *iter;
15798 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15799 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15801 for (iter = self->priv->first_child, i = 0;
15802 iter != NULL && i < index_;
15803 iter = iter->priv->next_sibling, i += 1)
15810 * _clutter_actor_foreach_child:
15811 * @actor: The actor whos children you want to iterate
15812 * @callback: The function to call for each child
15813 * @user_data: Private data to pass to @callback
15815 * Calls a given @callback once for each child of the specified @actor and
15816 * passing the @user_data pointer each time.
15818 * Return value: returns %TRUE if all children were iterated, else
15819 * %FALSE if a callback broke out of iteration early.
15822 _clutter_actor_foreach_child (ClutterActor *self,
15823 ClutterForeachCallback callback,
15824 gpointer user_data)
15826 ClutterActorPrivate *priv = self->priv;
15827 ClutterActor *iter;
15830 for (cont = TRUE, iter = priv->first_child;
15831 cont && iter != NULL;
15832 iter = iter->priv->next_sibling)
15834 cont = callback (iter, user_data);
15841 /* For debugging purposes this gives us a simple way to print out
15842 * the scenegraph e.g in gdb using:
15844 * _clutter_actor_traverse (stage,
15846 * clutter_debug_print_actor_cb,
15851 static ClutterActorTraverseVisitFlags
15852 clutter_debug_print_actor_cb (ClutterActor *actor,
15856 g_print ("%*s%s:%p\n",
15858 _clutter_actor_get_debug_name (actor),
15861 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15866 _clutter_actor_traverse_breadth (ClutterActor *actor,
15867 ClutterTraverseCallback callback,
15868 gpointer user_data)
15870 GQueue *queue = g_queue_new ();
15871 ClutterActor dummy;
15872 int current_depth = 0;
15874 g_queue_push_tail (queue, actor);
15875 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15877 while ((actor = g_queue_pop_head (queue)))
15879 ClutterActorTraverseVisitFlags flags;
15881 if (actor == &dummy)
15884 g_queue_push_tail (queue, &dummy);
15888 flags = callback (actor, current_depth, user_data);
15889 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15891 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15893 ClutterActor *iter;
15895 for (iter = actor->priv->first_child;
15897 iter = iter->priv->next_sibling)
15899 g_queue_push_tail (queue, iter);
15904 g_queue_free (queue);
15907 static ClutterActorTraverseVisitFlags
15908 _clutter_actor_traverse_depth (ClutterActor *actor,
15909 ClutterTraverseCallback before_children_callback,
15910 ClutterTraverseCallback after_children_callback,
15912 gpointer user_data)
15914 ClutterActorTraverseVisitFlags flags;
15916 flags = before_children_callback (actor, current_depth, user_data);
15917 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15918 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15920 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15922 ClutterActor *iter;
15924 for (iter = actor->priv->first_child;
15926 iter = iter->priv->next_sibling)
15928 flags = _clutter_actor_traverse_depth (iter,
15929 before_children_callback,
15930 after_children_callback,
15934 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15935 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15939 if (after_children_callback)
15940 return after_children_callback (actor, current_depth, user_data);
15942 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15945 /* _clutter_actor_traverse:
15946 * @actor: The actor to start traversing the graph from
15947 * @flags: These flags may affect how the traversal is done
15948 * @before_children_callback: A function to call before visiting the
15949 * children of the current actor.
15950 * @after_children_callback: A function to call after visiting the
15951 * children of the current actor. (Ignored if
15952 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15953 * @user_data: The private data to pass to the callbacks
15955 * Traverses the scenegraph starting at the specified @actor and
15956 * descending through all its children and its children's children.
15957 * For each actor traversed @before_children_callback and
15958 * @after_children_callback are called with the specified
15959 * @user_data, before and after visiting that actor's children.
15961 * The callbacks can return flags that affect the ongoing traversal
15962 * such as by skipping over an actors children or bailing out of
15963 * any further traversing.
15966 _clutter_actor_traverse (ClutterActor *actor,
15967 ClutterActorTraverseFlags flags,
15968 ClutterTraverseCallback before_children_callback,
15969 ClutterTraverseCallback after_children_callback,
15970 gpointer user_data)
15972 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15973 _clutter_actor_traverse_breadth (actor,
15974 before_children_callback,
15976 else /* DEPTH_FIRST */
15977 _clutter_actor_traverse_depth (actor,
15978 before_children_callback,
15979 after_children_callback,
15980 0, /* start depth */
15985 on_layout_manager_changed (ClutterLayoutManager *manager,
15986 ClutterActor *self)
15988 clutter_actor_queue_relayout (self);
15992 * clutter_actor_set_layout_manager:
15993 * @self: a #ClutterActor
15994 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15996 * Sets the #ClutterLayoutManager delegate object that will be used to
15997 * lay out the children of @self.
15999 * The #ClutterActor will take a reference on the passed @manager which
16000 * will be released either when the layout manager is removed, or when
16001 * the actor is destroyed.
16006 clutter_actor_set_layout_manager (ClutterActor *self,
16007 ClutterLayoutManager *manager)
16009 ClutterActorPrivate *priv;
16011 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16012 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16016 if (priv->layout_manager != NULL)
16018 g_signal_handlers_disconnect_by_func (priv->layout_manager,
16019 G_CALLBACK (on_layout_manager_changed),
16021 clutter_layout_manager_set_container (priv->layout_manager, NULL);
16022 g_clear_object (&priv->layout_manager);
16025 priv->layout_manager = manager;
16027 if (priv->layout_manager != NULL)
16029 g_object_ref_sink (priv->layout_manager);
16030 clutter_layout_manager_set_container (priv->layout_manager,
16031 CLUTTER_CONTAINER (self));
16032 g_signal_connect (priv->layout_manager, "layout-changed",
16033 G_CALLBACK (on_layout_manager_changed),
16037 clutter_actor_queue_relayout (self);
16039 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16043 * clutter_actor_get_layout_manager:
16044 * @self: a #ClutterActor
16046 * Retrieves the #ClutterLayoutManager used by @self.
16048 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16053 ClutterLayoutManager *
16054 clutter_actor_get_layout_manager (ClutterActor *self)
16056 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16058 return self->priv->layout_manager;
16061 static const ClutterLayoutInfo default_layout_info = {
16064 { 0, 0, 0, 0 }, /* margin */
16065 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
16066 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
16067 0.f, 0.f, /* min_width, natural_width */
16068 0.f, 0.f, /* natual_width, natural_height */
16072 layout_info_free (gpointer data)
16074 if (G_LIKELY (data != NULL))
16075 g_slice_free (ClutterLayoutInfo, data);
16079 * _clutter_actor_get_layout_info:
16080 * @self: a #ClutterActor
16082 * Retrieves a pointer to the ClutterLayoutInfo structure.
16084 * If the actor does not have a ClutterLayoutInfo associated to it, one
16085 * will be created and initialized to the default values.
16087 * This function should be used for setters.
16089 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16092 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16094 ClutterLayoutInfo *
16095 _clutter_actor_get_layout_info (ClutterActor *self)
16097 ClutterLayoutInfo *retval;
16099 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16100 if (retval == NULL)
16102 retval = g_slice_new (ClutterLayoutInfo);
16104 *retval = default_layout_info;
16106 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16115 * _clutter_actor_get_layout_info_or_defaults:
16116 * @self: a #ClutterActor
16118 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16120 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16121 * then the default structure will be returned.
16123 * This function should only be used for getters.
16125 * Return value: a const pointer to the ClutterLayoutInfo structure
16127 const ClutterLayoutInfo *
16128 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16130 const ClutterLayoutInfo *info;
16132 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16134 return &default_layout_info;
16140 * clutter_actor_set_x_align:
16141 * @self: a #ClutterActor
16142 * @x_align: the horizontal alignment policy
16144 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16145 * actor received extra horizontal space.
16147 * See also the #ClutterActor:x-align property.
16152 clutter_actor_set_x_align (ClutterActor *self,
16153 ClutterActorAlign x_align)
16155 ClutterLayoutInfo *info;
16157 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16159 info = _clutter_actor_get_layout_info (self);
16161 if (info->x_align != x_align)
16163 info->x_align = x_align;
16165 clutter_actor_queue_relayout (self);
16167 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16172 * clutter_actor_get_x_align:
16173 * @self: a #ClutterActor
16175 * Retrieves the horizontal alignment policy set using
16176 * clutter_actor_set_x_align().
16178 * Return value: the horizontal alignment policy.
16183 clutter_actor_get_x_align (ClutterActor *self)
16185 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16187 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16191 * clutter_actor_set_y_align:
16192 * @self: a #ClutterActor
16193 * @y_align: the vertical alignment policy
16195 * Sets the vertical alignment policy of a #ClutterActor, in case the
16196 * actor received extra vertical space.
16198 * See also the #ClutterActor:y-align property.
16203 clutter_actor_set_y_align (ClutterActor *self,
16204 ClutterActorAlign y_align)
16206 ClutterLayoutInfo *info;
16208 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16210 info = _clutter_actor_get_layout_info (self);
16212 if (info->y_align != y_align)
16214 info->y_align = y_align;
16216 clutter_actor_queue_relayout (self);
16218 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16223 * clutter_actor_get_y_align:
16224 * @self: a #ClutterActor
16226 * Retrieves the vertical alignment policy set using
16227 * clutter_actor_set_y_align().
16229 * Return value: the vertical alignment policy.
16234 clutter_actor_get_y_align (ClutterActor *self)
16236 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16238 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16243 * clutter_margin_new:
16245 * Creates a new #ClutterMargin.
16247 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16248 * clutter_margin_free() to free the resources associated with it when
16254 clutter_margin_new (void)
16256 return g_slice_new0 (ClutterMargin);
16260 * clutter_margin_copy:
16261 * @margin_: a #ClutterMargin
16263 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16264 * the newly created structure.
16266 * Return value: (transfer full): a copy of the #ClutterMargin.
16271 clutter_margin_copy (const ClutterMargin *margin_)
16273 if (G_LIKELY (margin_ != NULL))
16274 return g_slice_dup (ClutterMargin, margin_);
16280 * clutter_margin_free:
16281 * @margin_: a #ClutterMargin
16283 * Frees the resources allocated by clutter_margin_new() and
16284 * clutter_margin_copy().
16289 clutter_margin_free (ClutterMargin *margin_)
16291 if (G_LIKELY (margin_ != NULL))
16292 g_slice_free (ClutterMargin, margin_);
16295 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16296 clutter_margin_copy,
16297 clutter_margin_free)
16300 * clutter_actor_set_margin:
16301 * @self: a #ClutterActor
16302 * @margin: a #ClutterMargin
16304 * Sets all the components of the margin of a #ClutterActor.
16309 clutter_actor_set_margin (ClutterActor *self,
16310 const ClutterMargin *margin)
16312 ClutterLayoutInfo *info;
16316 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16317 g_return_if_fail (margin != NULL);
16319 obj = G_OBJECT (self);
16322 g_object_freeze_notify (obj);
16324 info = _clutter_actor_get_layout_info (self);
16326 if (info->margin.top != margin->top)
16328 info->margin.top = margin->top;
16329 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16333 if (info->margin.right != margin->right)
16335 info->margin.right = margin->right;
16336 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16340 if (info->margin.bottom != margin->bottom)
16342 info->margin.bottom = margin->bottom;
16343 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16347 if (info->margin.left != margin->left)
16349 info->margin.left = margin->left;
16350 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16355 clutter_actor_queue_relayout (self);
16357 g_object_thaw_notify (obj);
16361 * clutter_actor_get_margin:
16362 * @self: a #ClutterActor
16363 * @margin: (out caller-allocates): return location for a #ClutterMargin
16365 * Retrieves all the components of the margin of a #ClutterActor.
16370 clutter_actor_get_margin (ClutterActor *self,
16371 ClutterMargin *margin)
16373 const ClutterLayoutInfo *info;
16375 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16376 g_return_if_fail (margin != NULL);
16378 info = _clutter_actor_get_layout_info_or_defaults (self);
16380 *margin = info->margin;
16384 * clutter_actor_set_margin_top:
16385 * @self: a #ClutterActor
16386 * @margin: the top margin
16388 * Sets the margin from the top of a #ClutterActor.
16393 clutter_actor_set_margin_top (ClutterActor *self,
16396 ClutterLayoutInfo *info;
16398 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16399 g_return_if_fail (margin >= 0.f);
16401 info = _clutter_actor_get_layout_info (self);
16403 if (info->margin.top == margin)
16406 info->margin.top = margin;
16408 clutter_actor_queue_relayout (self);
16410 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16414 * clutter_actor_get_margin_top:
16415 * @self: a #ClutterActor
16417 * Retrieves the top margin of a #ClutterActor.
16419 * Return value: the top margin
16424 clutter_actor_get_margin_top (ClutterActor *self)
16426 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16428 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16432 * clutter_actor_set_margin_bottom:
16433 * @self: a #ClutterActor
16434 * @margin: the bottom margin
16436 * Sets the margin from the bottom of a #ClutterActor.
16441 clutter_actor_set_margin_bottom (ClutterActor *self,
16444 ClutterLayoutInfo *info;
16446 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16447 g_return_if_fail (margin >= 0.f);
16449 info = _clutter_actor_get_layout_info (self);
16451 if (info->margin.bottom == margin)
16454 info->margin.bottom = margin;
16456 clutter_actor_queue_relayout (self);
16458 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16462 * clutter_actor_get_margin_bottom:
16463 * @self: a #ClutterActor
16465 * Retrieves the bottom margin of a #ClutterActor.
16467 * Return value: the bottom margin
16472 clutter_actor_get_margin_bottom (ClutterActor *self)
16474 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16476 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16480 * clutter_actor_set_margin_left:
16481 * @self: a #ClutterActor
16482 * @margin: the left margin
16484 * Sets the margin from the left of a #ClutterActor.
16489 clutter_actor_set_margin_left (ClutterActor *self,
16492 ClutterLayoutInfo *info;
16494 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16495 g_return_if_fail (margin >= 0.f);
16497 info = _clutter_actor_get_layout_info (self);
16499 if (info->margin.left == margin)
16502 info->margin.left = margin;
16504 clutter_actor_queue_relayout (self);
16506 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16510 * clutter_actor_get_margin_left:
16511 * @self: a #ClutterActor
16513 * Retrieves the left margin of a #ClutterActor.
16515 * Return value: the left margin
16520 clutter_actor_get_margin_left (ClutterActor *self)
16522 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16524 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16528 * clutter_actor_set_margin_right:
16529 * @self: a #ClutterActor
16530 * @margin: the right margin
16532 * Sets the margin from the right of a #ClutterActor.
16537 clutter_actor_set_margin_right (ClutterActor *self,
16540 ClutterLayoutInfo *info;
16542 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16543 g_return_if_fail (margin >= 0.f);
16545 info = _clutter_actor_get_layout_info (self);
16547 if (info->margin.right == margin)
16550 info->margin.right = margin;
16552 clutter_actor_queue_relayout (self);
16554 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16558 * clutter_actor_get_margin_right:
16559 * @self: a #ClutterActor
16561 * Retrieves the right margin of a #ClutterActor.
16563 * Return value: the right margin
16568 clutter_actor_get_margin_right (ClutterActor *self)
16570 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16572 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16576 clutter_actor_set_background_color_internal (ClutterActor *self,
16577 const ClutterColor *color)
16579 ClutterActorPrivate *priv = self->priv;
16582 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16585 obj = G_OBJECT (self);
16587 priv->bg_color = *color;
16588 priv->bg_color_set = TRUE;
16590 clutter_actor_queue_redraw (self);
16592 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16593 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16597 * clutter_actor_set_background_color:
16598 * @self: a #ClutterActor
16599 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16602 * Sets the background color of a #ClutterActor.
16604 * The background color will be used to cover the whole allocation of the
16605 * actor. The default background color of an actor is transparent.
16607 * To check whether an actor has a background color, you can use the
16608 * #ClutterActor:background-color-set actor property.
16610 * The #ClutterActor:background-color property is animatable.
16615 clutter_actor_set_background_color (ClutterActor *self,
16616 const ClutterColor *color)
16618 ClutterActorPrivate *priv;
16620 GParamSpec *bg_color_pspec;
16622 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16624 obj = G_OBJECT (self);
16630 priv->bg_color_set = FALSE;
16631 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16632 clutter_actor_queue_redraw (self);
16636 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16637 if (clutter_actor_get_easing_duration (self) != 0)
16639 ClutterTransition *transition;
16641 transition = _clutter_actor_get_transition (self, bg_color_pspec);
16642 if (transition == NULL)
16644 transition = _clutter_actor_create_transition (self, bg_color_pspec,
16649 _clutter_actor_update_transition (self, bg_color_pspec, color);
16651 clutter_actor_queue_redraw (self);
16654 clutter_actor_set_background_color_internal (self, color);
16658 * clutter_actor_get_background_color:
16659 * @self: a #ClutterActor
16660 * @color: (out caller-allocates): return location for a #ClutterColor
16662 * Retrieves the color set using clutter_actor_set_background_color().
16667 clutter_actor_get_background_color (ClutterActor *self,
16668 ClutterColor *color)
16670 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16671 g_return_if_fail (color != NULL);
16673 *color = self->priv->bg_color;
16677 * clutter_actor_get_previous_sibling:
16678 * @self: a #ClutterActor
16680 * Retrieves the sibling of @self that comes before it in the list
16681 * of children of @self's parent.
16683 * The returned pointer is only valid until the scene graph changes; it
16684 * is not safe to modify the list of children of @self while iterating
16687 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16692 clutter_actor_get_previous_sibling (ClutterActor *self)
16694 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16696 return self->priv->prev_sibling;
16700 * clutter_actor_get_next_sibling:
16701 * @self: a #ClutterActor
16703 * Retrieves the sibling of @self that comes after it in the list
16704 * of children of @self's parent.
16706 * The returned pointer is only valid until the scene graph changes; it
16707 * is not safe to modify the list of children of @self while iterating
16710 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16715 clutter_actor_get_next_sibling (ClutterActor *self)
16717 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16719 return self->priv->next_sibling;
16723 * clutter_actor_get_first_child:
16724 * @self: a #ClutterActor
16726 * Retrieves the first child of @self.
16728 * The returned pointer is only valid until the scene graph changes; it
16729 * is not safe to modify the list of children of @self while iterating
16732 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16737 clutter_actor_get_first_child (ClutterActor *self)
16739 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16741 return self->priv->first_child;
16745 * clutter_actor_get_last_child:
16746 * @self: a #ClutterActor
16748 * Retrieves the last child of @self.
16750 * The returned pointer is only valid until the scene graph changes; it
16751 * is not safe to modify the list of children of @self while iterating
16754 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16759 clutter_actor_get_last_child (ClutterActor *self)
16761 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16763 return self->priv->last_child;
16766 /* easy way to have properly named fields instead of the dummy ones
16767 * we use in the public structure
16769 typedef struct _RealActorIter
16771 ClutterActor *root; /* dummy1 */
16772 ClutterActor *current; /* dummy2 */
16773 gpointer padding_1; /* dummy3 */
16774 gint age; /* dummy4 */
16775 gpointer padding_2; /* dummy5 */
16779 * clutter_actor_iter_init:
16780 * @iter: a #ClutterActorIter
16781 * @root: a #ClutterActor
16783 * Initializes a #ClutterActorIter, which can then be used to iterate
16784 * efficiently over a section of the scene graph, and associates it
16787 * Modifying the scene graph section that contains @root will invalidate
16791 * ClutterActorIter iter;
16792 * ClutterActor *child;
16794 * clutter_actor_iter_init (&iter, container);
16795 * while (clutter_actor_iter_next (&iter, &child))
16797 * /* do something with child */
16804 clutter_actor_iter_init (ClutterActorIter *iter,
16805 ClutterActor *root)
16807 RealActorIter *ri = (RealActorIter *) iter;
16809 g_return_if_fail (iter != NULL);
16810 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16813 ri->current = NULL;
16814 ri->age = root->priv->age;
16818 * clutter_actor_iter_next:
16819 * @iter: a #ClutterActorIter
16820 * @child: (out): return location for a #ClutterActor
16822 * Advances the @iter and retrieves the next child of the root #ClutterActor
16823 * that was used to initialize the #ClutterActorIterator.
16825 * If the iterator can advance, this function returns %TRUE and sets the
16828 * If the iterator cannot advance, this function returns %FALSE, and
16829 * the contents of @child are undefined.
16831 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16836 clutter_actor_iter_next (ClutterActorIter *iter,
16837 ClutterActor **child)
16839 RealActorIter *ri = (RealActorIter *) iter;
16841 g_return_val_if_fail (iter != NULL, FALSE);
16842 g_return_val_if_fail (ri->root != NULL, FALSE);
16843 #ifndef G_DISABLE_ASSERT
16844 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16847 if (ri->current == NULL)
16848 ri->current = ri->root->priv->first_child;
16850 ri->current = ri->current->priv->next_sibling;
16853 *child = ri->current;
16855 return ri->current != NULL;
16859 * clutter_actor_iter_prev:
16860 * @iter: a #ClutterActorIter
16861 * @child: (out): return location for a #ClutterActor
16863 * Advances the @iter and retrieves the previous child of the root
16864 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16866 * If the iterator can advance, this function returns %TRUE and sets the
16869 * If the iterator cannot advance, this function returns %FALSE, and
16870 * the contents of @child are undefined.
16872 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16877 clutter_actor_iter_prev (ClutterActorIter *iter,
16878 ClutterActor **child)
16880 RealActorIter *ri = (RealActorIter *) iter;
16882 g_return_val_if_fail (iter != NULL, FALSE);
16883 g_return_val_if_fail (ri->root != NULL, FALSE);
16884 #ifndef G_DISABLE_ASSERT
16885 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16888 if (ri->current == NULL)
16889 ri->current = ri->root->priv->last_child;
16891 ri->current = ri->current->priv->prev_sibling;
16894 *child = ri->current;
16896 return ri->current != NULL;
16900 * clutter_actor_iter_remove:
16901 * @iter: a #ClutterActorIter
16903 * Safely removes the #ClutterActor currently pointer to by the iterator
16906 * This function can only be called after clutter_actor_iter_next() or
16907 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16908 * than once for the same actor.
16910 * This function will call clutter_actor_remove_child() internally.
16915 clutter_actor_iter_remove (ClutterActorIter *iter)
16917 RealActorIter *ri = (RealActorIter *) iter;
16920 g_return_if_fail (iter != NULL);
16921 g_return_if_fail (ri->root != NULL);
16922 #ifndef G_DISABLE_ASSERT
16923 g_return_if_fail (ri->age == ri->root->priv->age);
16925 g_return_if_fail (ri->current != NULL);
16931 ri->current = cur->priv->prev_sibling;
16933 clutter_actor_remove_child_internal (ri->root, cur,
16934 REMOVE_CHILD_DEFAULT_FLAGS);
16941 * clutter_actor_iter_destroy:
16942 * @iter: a #ClutterActorIter
16944 * Safely destroys the #ClutterActor currently pointer to by the iterator
16947 * This function can only be called after clutter_actor_iter_next() or
16948 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16949 * than once for the same actor.
16951 * This function will call clutter_actor_destroy() internally.
16956 clutter_actor_iter_destroy (ClutterActorIter *iter)
16958 RealActorIter *ri = (RealActorIter *) iter;
16961 g_return_if_fail (iter != NULL);
16962 g_return_if_fail (ri->root != NULL);
16963 #ifndef G_DISABLE_ASSERT
16964 g_return_if_fail (ri->age == ri->root->priv->age);
16966 g_return_if_fail (ri->current != NULL);
16972 ri->current = cur->priv->prev_sibling;
16974 clutter_actor_destroy (cur);
16980 static const ClutterAnimationInfo default_animation_info = {
16981 NULL, /* transitions */
16983 NULL, /* cur_state */
16987 clutter_animation_info_free (gpointer data)
16991 ClutterAnimationInfo *info = data;
16993 if (info->transitions != NULL)
16994 g_hash_table_unref (info->transitions);
16996 if (info->states != NULL)
16997 g_array_unref (info->states);
16999 g_slice_free (ClutterAnimationInfo, info);
17003 const ClutterAnimationInfo *
17004 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17006 const ClutterAnimationInfo *res;
17007 GObject *obj = G_OBJECT (self);
17009 res = g_object_get_qdata (obj, quark_actor_animation_info);
17013 return &default_animation_info;
17016 ClutterAnimationInfo *
17017 _clutter_actor_get_animation_info (ClutterActor *self)
17019 GObject *obj = G_OBJECT (self);
17020 ClutterAnimationInfo *res;
17022 res = g_object_get_qdata (obj, quark_actor_animation_info);
17025 res = g_slice_new (ClutterAnimationInfo);
17027 *res = default_animation_info;
17029 g_object_set_qdata_full (obj, quark_actor_animation_info,
17031 clutter_animation_info_free);
17037 ClutterTransition *
17038 _clutter_actor_get_transition (ClutterActor *actor,
17041 const ClutterAnimationInfo *info;
17043 info = _clutter_actor_get_animation_info_or_defaults (actor);
17045 if (info->transitions == NULL)
17048 return g_hash_table_lookup (info->transitions, pspec->name);
17051 typedef struct _TransitionClosure
17053 ClutterActor *actor;
17054 ClutterTransition *transition;
17056 gulong completed_id;
17057 } TransitionClosure;
17060 transition_closure_free (gpointer data)
17062 if (G_LIKELY (data != NULL))
17064 TransitionClosure *clos = data;
17066 if (clutter_timeline_is_playing (CLUTTER_TIMELINE (clos->transition)))
17067 clutter_timeline_stop (CLUTTER_TIMELINE (clos->transition));
17069 g_signal_handler_disconnect (clos->transition, clos->completed_id);
17071 g_object_unref (clos->transition);
17072 g_free (clos->name);
17074 g_slice_free (TransitionClosure, clos);
17079 on_transition_completed (ClutterTransition *transition,
17080 TransitionClosure *clos)
17082 ClutterActor *actor = clos->actor;
17083 ClutterAnimationInfo *info;
17085 info = _clutter_actor_get_animation_info (actor);
17087 /* this will take care of cleaning clos for us */
17088 if (clutter_transition_get_remove_on_complete (transition))
17090 /* we take a reference here because removing the closure
17091 * will release the reference on the transition, and we
17092 * want the transition to survive the signal emission;
17093 * the master clock will release the laste reference at
17094 * the end of the frame processing.
17096 g_object_ref (transition);
17097 g_hash_table_remove (info->transitions, clos->name);
17100 /* if it's the last transition then we clean up */
17101 if (g_hash_table_size (info->transitions) == 0)
17103 g_hash_table_unref (info->transitions);
17104 info->transitions = NULL;
17106 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17107 _clutter_actor_get_debug_name (actor));
17109 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17114 _clutter_actor_update_transition (ClutterActor *actor,
17118 TransitionClosure *clos;
17119 ClutterInterval *interval;
17120 const ClutterAnimationInfo *info;
17123 GValue initial = G_VALUE_INIT;
17124 GValue final = G_VALUE_INIT;
17125 char *error = NULL;
17127 info = _clutter_actor_get_animation_info_or_defaults (actor);
17129 if (info->transitions == NULL)
17132 clos = g_hash_table_lookup (info->transitions, pspec->name);
17136 va_start (var_args, pspec);
17138 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17140 g_value_init (&initial, ptype);
17141 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17145 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17148 g_critical ("%s: %s", G_STRLOC, error);
17153 interval = clutter_transition_get_interval (clos->transition);
17154 clutter_interval_set_initial_value (interval, &initial);
17155 clutter_interval_set_final_value (interval, &final);
17157 clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
17160 g_value_unset (&initial);
17161 g_value_unset (&final);
17167 * _clutter_actor_create_transition:
17168 * @actor: a #ClutterActor
17169 * @pspec: the property used for the transition
17170 * @...: initial and final state
17172 * Creates a #ClutterTransition for the property represented by @pspec.
17174 * Return value: a #ClutterTransition
17176 ClutterTransition *
17177 _clutter_actor_create_transition (ClutterActor *actor,
17181 ClutterAnimationInfo *info;
17182 ClutterTransition *res = NULL;
17183 gboolean call_restore = FALSE;
17184 TransitionClosure *clos;
17187 info = _clutter_actor_get_animation_info (actor);
17189 if (info->states == NULL)
17191 clutter_actor_save_easing_state (actor);
17192 call_restore = TRUE;
17195 if (info->transitions == NULL)
17196 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17198 transition_closure_free);
17200 va_start (var_args, pspec);
17202 clos = g_hash_table_lookup (info->transitions, pspec->name);
17205 ClutterInterval *interval;
17206 GValue initial = G_VALUE_INIT;
17207 GValue final = G_VALUE_INIT;
17211 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17213 G_VALUE_COLLECT_INIT (&initial, ptype,
17218 g_critical ("%s: %s", G_STRLOC, error);
17223 G_VALUE_COLLECT_INIT (&final, ptype,
17229 g_critical ("%s: %s", G_STRLOC, error);
17230 g_value_unset (&initial);
17235 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17237 g_value_unset (&initial);
17238 g_value_unset (&final);
17240 res = clutter_property_transition_new (pspec->name);
17242 clutter_transition_set_interval (res, interval);
17243 clutter_transition_set_remove_on_complete (res, TRUE);
17245 /* this will start the transition as well */
17246 clutter_actor_add_transition (actor, pspec->name, res);
17248 /* the actor now owns the transition */
17249 g_object_unref (res);
17252 res = clos->transition;
17256 clutter_actor_restore_easing_state (actor);
17264 * clutter_actor_add_transition:
17265 * @self: a #ClutterActor
17266 * @name: the name of the transition to add
17267 * @transition: the #ClutterTransition to add
17269 * Adds a @transition to the #ClutterActor's list of animations.
17271 * The @name string is a per-actor unique identifier of the @transition: only
17272 * one #ClutterTransition can be associated to the specified @name.
17274 * The @transition will be given the easing duration, mode, and delay
17275 * associated to the actor's current easing state; it is possible to modify
17276 * these values after calling clutter_actor_add_transition().
17278 * The @transition will be started once added.
17280 * This function will take a reference on the @transition.
17282 * This function is usually called implicitly when modifying an animatable
17288 clutter_actor_add_transition (ClutterActor *self,
17290 ClutterTransition *transition)
17292 ClutterTimeline *timeline;
17293 TransitionClosure *clos;
17294 ClutterAnimationInfo *info;
17296 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17297 g_return_if_fail (name != NULL);
17298 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17300 info = _clutter_actor_get_animation_info (self);
17302 if (info->cur_state == NULL)
17304 g_warning ("No easing state is defined for the actor '%s'; you "
17305 "must call clutter_actor_save_easing_state() before "
17306 "calling clutter_actor_add_transition().",
17307 _clutter_actor_get_debug_name (self));
17311 if (info->transitions == NULL)
17312 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17314 transition_closure_free);
17316 if (g_hash_table_lookup (info->transitions, name) != NULL)
17318 g_warning ("A transition with name '%s' already exists for "
17321 _clutter_actor_get_debug_name (self));
17325 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17327 timeline = CLUTTER_TIMELINE (transition);
17329 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17330 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17331 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17333 clos = g_slice_new (TransitionClosure);
17334 clos->actor = self;
17335 clos->transition = g_object_ref (transition);
17336 clos->name = g_strdup (name);
17337 clos->completed_id = g_signal_connect (timeline, "completed",
17338 G_CALLBACK (on_transition_completed),
17341 g_hash_table_insert (info->transitions, clos->name, clos);
17342 clutter_timeline_start (timeline);
17346 * clutter_actor_remove_transition:
17347 * @self: a #ClutterActor
17348 * @name: the name of the transition to remove
17350 * Removes the transition stored inside a #ClutterActor using @name
17353 * If the transition is currently in progress, it will be stopped.
17355 * This function releases the reference acquired when the transition
17356 * was added to the #ClutterActor.
17361 clutter_actor_remove_transition (ClutterActor *self,
17364 const ClutterAnimationInfo *info;
17366 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17367 g_return_if_fail (name != NULL);
17369 info = _clutter_actor_get_animation_info_or_defaults (self);
17371 if (info->transitions == NULL)
17374 g_hash_table_remove (info->transitions, name);
17378 * clutter_actor_remove_all_transitions:
17379 * @self: a #ClutterActor
17381 * Removes all transitions associated to @self.
17386 clutter_actor_remove_all_transitions (ClutterActor *self)
17388 const ClutterAnimationInfo *info;
17390 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17392 info = _clutter_actor_get_animation_info_or_defaults (self);
17393 if (info->transitions == NULL)
17396 g_hash_table_remove_all (info->transitions);
17400 * clutter_actor_set_easing_duration:
17401 * @self: a #ClutterActor
17402 * @msecs: the duration of the easing, or %NULL
17404 * Sets the duration of the tweening for animatable properties
17405 * of @self for the current easing state.
17410 clutter_actor_set_easing_duration (ClutterActor *self,
17413 ClutterAnimationInfo *info;
17415 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17417 info = _clutter_actor_get_animation_info (self);
17419 if (info->cur_state == NULL)
17421 g_warning ("You must call clutter_actor_save_easing_state() prior "
17422 "to calling clutter_actor_set_easing_duration().");
17426 if (info->cur_state->easing_duration != msecs)
17427 info->cur_state->easing_duration = msecs;
17431 * clutter_actor_get_easing_duration:
17432 * @self: a #ClutterActor
17434 * Retrieves the duration of the tweening for animatable
17435 * properties of @self for the current easing state.
17437 * Return value: the duration of the tweening, in milliseconds
17442 clutter_actor_get_easing_duration (ClutterActor *self)
17444 const ClutterAnimationInfo *info;
17446 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17448 info = _clutter_actor_get_animation_info_or_defaults (self);
17450 if (info->cur_state != NULL)
17451 return info->cur_state->easing_duration;
17457 * clutter_actor_set_easing_mode:
17458 * @self: a #ClutterActor
17459 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17461 * Sets the easing mode for the tweening of animatable properties
17467 clutter_actor_set_easing_mode (ClutterActor *self,
17468 ClutterAnimationMode mode)
17470 ClutterAnimationInfo *info;
17472 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17473 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17474 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17476 info = _clutter_actor_get_animation_info (self);
17478 if (info->cur_state == NULL)
17480 g_warning ("You must call clutter_actor_save_easing_state() prior "
17481 "to calling clutter_actor_set_easing_mode().");
17485 if (info->cur_state->easing_mode != mode)
17486 info->cur_state->easing_mode = mode;
17490 * clutter_actor_get_easing_mode:
17491 * @self: a #ClutterActor
17493 * Retrieves the easing mode for the tweening of animatable properties
17494 * of @self for the current easing state.
17496 * Return value: an easing mode
17500 ClutterAnimationMode
17501 clutter_actor_get_easing_mode (ClutterActor *self)
17503 const ClutterAnimationInfo *info;
17505 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17507 info = _clutter_actor_get_animation_info_or_defaults (self);
17509 if (info->cur_state != NULL)
17510 return info->cur_state->easing_mode;
17512 return CLUTTER_EASE_OUT_CUBIC;
17516 * clutter_actor_set_easing_delay:
17517 * @self: a #ClutterActor
17518 * @msecs: the delay before the start of the tweening, in milliseconds
17520 * Sets the delay that should be applied before tweening animatable
17526 clutter_actor_set_easing_delay (ClutterActor *self,
17529 ClutterAnimationInfo *info;
17531 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17533 info = _clutter_actor_get_animation_info (self);
17535 if (info->cur_state == NULL)
17537 g_warning ("You must call clutter_actor_save_easing_state() prior "
17538 "to calling clutter_actor_set_easing_delay().");
17542 if (info->cur_state->easing_delay != msecs)
17543 info->cur_state->easing_delay = msecs;
17547 * clutter_actor_get_easing_delay:
17548 * @self: a #ClutterActor
17550 * Retrieves the delay that should be applied when tweening animatable
17553 * Return value: a delay, in milliseconds
17558 clutter_actor_get_easing_delay (ClutterActor *self)
17560 const ClutterAnimationInfo *info;
17562 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17564 info = _clutter_actor_get_animation_info_or_defaults (self);
17566 if (info->cur_state != NULL)
17567 return info->cur_state->easing_delay;
17573 * clutter_actor_get_transition:
17574 * @self: a #ClutterActor
17575 * @name: the name of the transition
17577 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17578 * transition @name.
17580 * Transitions created for animatable properties use the name of the
17581 * property itself, for instance the code below:
17584 * clutter_actor_set_easing_duration (actor, 1000);
17585 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17587 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17588 * g_signal_connect (transition, "completed",
17589 * G_CALLBACK (on_transition_complete),
17593 * will call the <function>on_transition_complete</function> callback when
17594 * the transition is complete.
17596 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17597 * was found to match the passed name; the returned instance is owned
17598 * by Clutter and it should not be freed
17602 ClutterTransition *
17603 clutter_actor_get_transition (ClutterActor *self,
17606 TransitionClosure *clos;
17607 const ClutterAnimationInfo *info;
17609 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17610 g_return_val_if_fail (name != NULL, NULL);
17612 info = _clutter_actor_get_animation_info_or_defaults (self);
17614 if (info->transitions == NULL)
17617 clos = g_hash_table_lookup (info->transitions, name);
17621 return clos->transition;
17625 * clutter_actor_save_easing_state:
17626 * @self: a #ClutterActor
17628 * Saves the current easing state for animatable properties, and creates
17629 * a new state with the default values for easing mode and duration.
17634 clutter_actor_save_easing_state (ClutterActor *self)
17636 ClutterAnimationInfo *info;
17639 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17641 info = _clutter_actor_get_animation_info (self);
17643 if (info->states == NULL)
17644 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17646 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17647 new_state.easing_duration = 250;
17648 new_state.easing_delay = 0;
17650 g_array_append_val (info->states, new_state);
17652 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17656 * clutter_actor_restore_easing_state:
17657 * @self: a #ClutterActor
17659 * Restores the easing state as it was prior to a call to
17660 * clutter_actor_save_easing_state().
17665 clutter_actor_restore_easing_state (ClutterActor *self)
17667 ClutterAnimationInfo *info;
17669 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17671 info = _clutter_actor_get_animation_info (self);
17673 if (info->states == NULL)
17675 g_critical ("The function clutter_actor_restore_easing_state() has "
17676 "called without a previous call to "
17677 "clutter_actor_save_easing_state().");
17681 g_array_remove_index (info->states, info->states->len - 1);
17683 if (info->states->len > 0)
17684 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17687 g_array_unref (info->states);
17688 info->states = NULL;
17693 * clutter_actor_set_content:
17694 * @self: a #ClutterActor
17695 * @content: (allow-none): a #ClutterContent, or %NULL
17697 * Sets the contents of a #ClutterActor.
17702 clutter_actor_set_content (ClutterActor *self,
17703 ClutterContent *content)
17705 ClutterActorPrivate *priv;
17707 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17708 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17712 if (priv->content != NULL)
17714 _clutter_content_detached (priv->content, self);
17715 g_clear_object (&priv->content);
17718 priv->content = content;
17720 if (priv->content != NULL)
17722 g_object_ref (priv->content);
17723 _clutter_content_attached (priv->content, self);
17726 /* given that the content is always painted within the allocation,
17727 * we only need to queue a redraw here
17729 clutter_actor_queue_redraw (self);
17731 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17733 /* if the content gravity is not resize-fill, and the new content has a
17734 * different preferred size than the previous one, then the content box
17735 * may have been changed. since we compute that lazily, we just notify
17736 * here, and let whomever watches :content-box do whatever they need to
17739 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17740 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17744 * clutter_actor_get_content:
17745 * @self: a #ClutterActor
17747 * Retrieves the contents of @self.
17749 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17750 * or %NULL if none was set
17755 clutter_actor_get_content (ClutterActor *self)
17757 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17759 return self->priv->content;
17763 * clutter_actor_set_content_gravity:
17764 * @self: a #ClutterActor
17765 * @gravity: the #ClutterContentGravity
17767 * Sets the gravity of the #ClutterContent used by @self.
17769 * See the description of the #ClutterActor:content-gravity property for
17770 * more information.
17775 clutter_actor_set_content_gravity (ClutterActor *self,
17776 ClutterContentGravity gravity)
17778 ClutterActorPrivate *priv;
17780 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17784 if (priv->content_gravity == gravity)
17787 priv->content_gravity = gravity;
17789 clutter_actor_queue_redraw (self);
17791 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17792 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17796 * clutter_actor_get_content_gravity:
17797 * @self: a #ClutterActor
17799 * Retrieves the content gravity as set using
17800 * clutter_actor_get_content_gravity().
17802 * Return value: the content gravity
17806 ClutterContentGravity
17807 clutter_actor_get_content_gravity (ClutterActor *self)
17809 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17810 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17812 return self->priv->content_gravity;
17816 * clutter_actor_get_content_box:
17817 * @self: a #ClutterActor
17818 * @box: (out caller-allocates): the return location for the bounding
17819 * box for the #ClutterContent
17821 * Retrieves the bounding box for the #ClutterContent of @self.
17823 * The bounding box is relative to the actor's allocation.
17825 * If no #ClutterContent is set for @self, or if @self has not been
17826 * allocated yet, then the result is undefined.
17828 * The content box is guaranteed to be, at most, as big as the allocation
17829 * of the #ClutterActor.
17831 * If the #ClutterContent used by the actor has a preferred size, then
17832 * it is possible to modify the content box by using the
17833 * #ClutterActor:content-gravity property.
17838 clutter_actor_get_content_box (ClutterActor *self,
17839 ClutterActorBox *box)
17841 ClutterActorPrivate *priv;
17842 gfloat content_w, content_h;
17843 gfloat alloc_w, alloc_h;
17845 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17846 g_return_if_fail (box != NULL);
17852 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17853 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17855 if (priv->content == NULL)
17858 /* no need to do any more work */
17859 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17862 /* if the content does not have a preferred size then there is
17863 * no point in computing the content box
17865 if (!clutter_content_get_preferred_size (priv->content,
17873 switch (priv->content_gravity)
17875 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17876 box->x2 = box->x1 + MIN (content_w, alloc_w);
17877 box->y2 = box->y1 + MIN (content_h, alloc_h);
17880 case CLUTTER_CONTENT_GRAVITY_TOP:
17881 if (alloc_w > content_w)
17883 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17884 box->x2 = box->x1 + content_w;
17886 box->y2 = box->y1 + MIN (content_h, alloc_h);
17889 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17890 if (alloc_w > content_w)
17892 box->x1 += (alloc_w - content_w);
17893 box->x2 = box->x1 + content_w;
17895 box->y2 = box->y1 + MIN (content_h, alloc_h);
17898 case CLUTTER_CONTENT_GRAVITY_LEFT:
17899 box->x2 = box->x1 + MIN (content_w, alloc_w);
17900 if (alloc_h > content_h)
17902 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17903 box->y2 = box->y1 + content_h;
17907 case CLUTTER_CONTENT_GRAVITY_CENTER:
17908 if (alloc_w > content_w)
17910 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17911 box->x2 = box->x1 + content_w;
17913 if (alloc_h > content_h)
17915 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17916 box->y2 = box->y1 + content_h;
17920 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17921 if (alloc_w > content_w)
17923 box->x1 += (alloc_w - content_w);
17924 box->x2 = box->x1 + content_w;
17926 if (alloc_h > content_h)
17928 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17929 box->y2 = box->y1 + content_h;
17933 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17934 box->x2 = box->x1 + MIN (content_w, alloc_w);
17935 if (alloc_h > content_h)
17937 box->y1 += (alloc_h - content_h);
17938 box->y2 = box->y1 + content_h;
17942 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17943 if (alloc_w > content_w)
17945 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17946 box->x2 = box->x1 + content_w;
17948 if (alloc_h > content_h)
17950 box->y1 += (alloc_h - content_h);
17951 box->y2 = box->y1 + content_h;
17955 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17956 if (alloc_w > content_w)
17958 box->x1 += (alloc_w - content_w);
17959 box->x2 = box->x1 + content_w;
17961 if (alloc_h > content_h)
17963 box->y1 += (alloc_h - content_h);
17964 box->y2 = box->y1 + content_h;
17968 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17969 g_assert_not_reached ();
17972 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17974 double r_c = content_w / content_h;
17975 double r_a = alloc_w / alloc_h;
17984 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17985 box->y2 = box->y1 + (alloc_w * r_c);
17992 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17993 box->x2 = box->x1 + (alloc_h * r_c);
18003 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18004 box->x2 = box->x1 + (alloc_h * r_c);
18011 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18012 box->y2 = box->y1 + (alloc_w * r_c);
18021 * clutter_actor_set_content_scaling_filters:
18022 * @self: a #ClutterActor
18023 * @min_filter: the minification filter for the content
18024 * @mag_filter: the magnification filter for the content
18026 * Sets the minification and magnification filter to be applied when
18027 * scaling the #ClutterActor:content of a #ClutterActor.
18029 * The #ClutterActor:minification-filter will be used when reducing
18030 * the size of the content; the #ClutterActor:magnification-filter
18031 * will be used when increasing the size of the content.
18036 clutter_actor_set_content_scaling_filters (ClutterActor *self,
18037 ClutterScalingFilter min_filter,
18038 ClutterScalingFilter mag_filter)
18040 ClutterActorPrivate *priv;
18044 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18047 obj = G_OBJECT (self);
18049 g_object_freeze_notify (obj);
18053 if (priv->min_filter != min_filter)
18055 priv->min_filter = min_filter;
18058 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18061 if (priv->mag_filter != mag_filter)
18063 priv->mag_filter = mag_filter;
18066 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18070 clutter_actor_queue_redraw (self);
18072 g_object_thaw_notify (obj);
18076 * clutter_actor_get_content_scaling_filters:
18077 * @self: a #ClutterActor
18078 * @min_filter: (out) (allow-none): return location for the minification
18080 * @mag_filter: (out) (allow-none): return location for the magnification
18083 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18088 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18089 ClutterScalingFilter *min_filter,
18090 ClutterScalingFilter *mag_filter)
18092 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18094 if (min_filter != NULL)
18095 *min_filter = self->priv->min_filter;
18097 if (mag_filter != NULL)
18098 *mag_filter = self->priv->mag_filter;