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>
261 * <para>It is important to note that if you modify the state on an
262 * animatable property while a transition is in flight, the transition's
263 * final value will be updated, as well as its duration and progress
264 * mode by using the current easing state; for instance, in the following
266 * <informalexample><programlisting>
267 * clutter_actor_save_easing_state (actor);
268 * clutter_actor_set_x (actor, 200);
269 * clutter_actor_restore_easing_state (actor);
271 * clutter_actor_save_easing_state (actor);
272 * clutter_actor_set_x (actor, 100);
273 * clutter_actor_restore_easing_state (actor);
274 * </programlisting></informalexample>
275 * <para>the first call to clutter_actor_set_x() will begin a transition
276 * of the #ClutterActor:x property to the value of 200; the second call
277 * to clutter_actor_set_x() will change the transition's final value to
279 * <para>It is possible to retrieve the #ClutterTransition used by the
280 * animatable properties by using clutter_actor_get_transition() and using
281 * the property name as the transition name.</para>
284 * <title>Explicit animations</title>
285 * <para>The explicit animation model supported by Clutter requires that
286 * you create a #ClutterTransition object, and set the initial and
287 * final values. The transition will not start unless you add it to the
288 * #ClutterActor.</para>
289 * <informalexample><programlisting>
290 * ClutterTransition *transition;
292 * transition = clutter_property_transition_new ("opacity");
293 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
294 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
295 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
296 * clutter_transition_set_interval (transition, clutter_interval_new (G_TYPE_UINT, 255, 0));
298 * clutter_actor_add_transition (actor, "animate-opacity", transition);
299 * </programlisting></informalexample>
300 * <para>The example above will animate the #ClutterActor:opacity property
301 * of an actor between fully opaque and fully transparent, and back, over
302 * a span of 3 seconds. The animation does not begin until it is added to
304 * <para>The explicit animation API should also be used when using custom
305 * animatable properties for #ClutterAction, #ClutterConstraint, and
306 * #ClutterEffect instances associated to an actor; see the section on
307 * <ulink linkend="ClutterActor-custom-animatable-properties">custom
308 * animatable properties below</ulink> for an example.</para>
309 * <para>Finally, explicit animations are useful for creating animations
310 * that run continuously, for instance:</para>
311 * <informalexample><programlisting>
312 * /* this animation will pulse the actor's opacity continuously */
313 * ClutterTransition *transition;
314 * ClutterInterval *interval;
316 * transition = clutter_property_transition_new ("opacity");
318 * /* we want to animate the opacity between 0 and 255 */
319 * internal = clutter_interval_new (G_TYPE_UINT, 0, 255);
320 * clutter_transition_set_interval (transition, interval);
322 * /* over a one second duration, running an infinite amount of times */
323 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
324 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
326 * /* we want to fade in and out, so we need to auto-reverse the transition */
327 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
329 * /* and we want to use an easing function that eases both in and out */
330 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
331 * CLUTTER_EASE_IN_OUT_CUBIC);
333 * /* add the transition to the desired actor; this will
334 * * start the animation.
336 * clutter_actor_add_transition (actor, "opacityAnimation", transition);
337 * </programlisting></informalexample>
341 * <refsect2 id="ClutterActor-subclassing">
342 * <title>Implementing an actor</title>
343 * <para>Careful consideration should be given when deciding to implement
344 * a #ClutterActor sub-class. It is generally recommended to implement a
345 * sub-class of #ClutterActor only for actors that should be used as leaf
346 * nodes of a scene graph.</para>
347 * <para>If your actor should be painted in a custom way, you should
348 * override the #ClutterActor::paint signal class handler. You can either
349 * opt to chain up to the parent class implementation or decide to fully
350 * override the default paint implementation; Clutter will set up the
351 * transformations and clip regions prior to emitting the #ClutterActor::paint
353 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
354 * #ClutterActorClass.get_preferred_height() virtual functions it is
355 * possible to change or provide the preferred size of an actor; similarly,
356 * by overriding the #ClutterActorClass.allocate() virtual function it is
357 * possible to control the layout of the children of an actor. Make sure to
358 * always chain up to the parent implementation of the
359 * #ClutterActorClass.allocate() virtual function.</para>
360 * <para>In general, it is strongly encouraged to use delegation and
361 * composition instead of direct subclassing.</para>
364 * <refsect2 id="ClutterActor-script">
365 * <title>ClutterActor custom properties for #ClutterScript</title>
366 * <para>#ClutterActor defines a custom "rotation" property which
367 * allows a short-hand description of the rotations to be applied
368 * to an actor.</para>
369 * <para>The syntax of the "rotation" property is the following:</para>
373 * { "<axis>" : [ <angle>, [ <center> ] ] }
377 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
378 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
379 * floating point value representing the rotation angle on the given axis,
381 * <para>The <emphasis>center</emphasis> array is optional, and if present
382 * it must contain the center of rotation as described by two coordinates:
383 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
385 * <para>#ClutterActor will also parse every positional and dimensional
386 * property defined as a string through clutter_units_from_string(); you
387 * should read the documentation for the #ClutterUnits parser format for
388 * the valid units and syntax.</para>
391 * <refsect2 id="ClutterActor-custom-animatable-properties">
392 * <title>Custom animatable properties</title>
393 * <para>#ClutterActor allows accessing properties of #ClutterAction,
394 * #ClutterEffect, and #ClutterConstraint instances associated to an actor
395 * instance for animation purposes.</para>
396 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
397 * property it is necessary to set the #ClutterActorMeta:name property on the
398 * given action or constraint.</para>
399 * <para>The property can be accessed using the following syntax:</para>
402 * @<section>.<meta-name>.<property-name>
405 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
406 * <para>The <emphasis>section</emphasis> fragment can be one between
407 * "actions", "constraints" and "effects".</para>
408 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
409 * action or constraint, as specified by the #ClutterActorMeta:name
411 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
412 * action or constraint property to be animated.</para>
413 * <para>The example below animates a #ClutterBindConstraint applied to an
414 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
415 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
416 * its initial state is overlapping the actor to which is bound to.</para>
417 * <informalexample><programlisting>
418 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
419 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
420 * clutter_actor_add_constraint (rect, constraint);
422 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
423 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
424 * clutter_actor_add_constraint (rect, constraint);
426 * clutter_actor_set_reactive (origin, TRUE);
428 * g_signal_connect (origin, "button-press-event",
429 * G_CALLBACK (on_button_press),
431 * </programlisting></informalexample>
432 * <para>On button press, the rectangle "slides" from behind the actor to
433 * which is bound to, using the #ClutterBindConstraint:offset property to
434 * achieve the effect:</para>
435 * <informalexample><programlisting>
437 * on_button_press (ClutterActor *origin,
438 * ClutterEvent *event,
439 * ClutterActor *rect)
441 * ClutterTransition *transition;
442 * ClutterInterval *interval;
444 * /* the offset that we want to apply; this will make the actor
445 * * slide in from behind the origin and rest at the right of
446 * * the origin, plus a padding value.
448 * float new_offset = clutter_actor_get_width (origin) + h_padding;
450 * /* the property we wish to animate; the "@constraints" section
451 * * tells Clutter to check inside the constraints associated
452 * * with the actor; the "bind-x" section is the name of the
453 * * constraint; and the "offset" is the name of the property
454 * * on the constraint.
456 * const char *prop = "@constraints.bind-x.offset";
458 * /* create a new transition for the given property */
459 * transition = clutter_property_transition_new (prop);
461 * /* set the easing mode and duration */
462 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
463 * CLUTTER_EASE_OUT_CUBIC);
464 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
466 * /* create the interval with the initial and final values */
467 * interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
468 * clutter_transition_set_interval (transition, interval);
470 * /* add the transition to the actor; this causes the animation
471 * * to start. the name "offsetAnimation" can be used to retrieve
472 * * the transition later.
474 * clutter_actor_add_transition (rect, "offsetAnimation", transition);
476 * /* we handled the event */
477 * return CLUTTER_EVENT_STOP;
479 * </programlisting></informalexample>
484 * CLUTTER_ACTOR_IS_MAPPED:
485 * @a: a #ClutterActor
487 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
489 * The mapped state is set when the actor is visible and all its parents up
490 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
492 * This check can be used to see if an actor is going to be painted, as only
493 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
495 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
496 * not be checked directly; instead, the recommended usage is to connect a
497 * handler on the #GObject::notify signal for the #ClutterActor:mapped
498 * property of #ClutterActor, and check the presence of
499 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
501 * It is also important to note that Clutter may delay the changes of
502 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
503 * limitations, or during the reparenting of an actor, to optimize
504 * unnecessary (and potentially expensive) state changes.
510 * CLUTTER_ACTOR_IS_REALIZED:
511 * @a: a #ClutterActor
513 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
515 * The realized state has an actor-dependant interpretation. If an
516 * actor wants to delay allocating resources until it is attached to a
517 * stage, it may use the realize state to do so. However it is
518 * perfectly acceptable for an actor to allocate Cogl resources before
519 * being realized because there is only one drawing context used by Clutter
520 * so any resources will work on any stage. If an actor is mapped it
521 * must also be realized, but an actor can be realized and unmapped
522 * (this is so hiding an actor temporarily doesn't do an expensive
523 * unrealize/realize).
525 * To be realized an actor must be inside a stage, and all its parents
532 * CLUTTER_ACTOR_IS_VISIBLE:
533 * @a: a #ClutterActor
535 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
536 * Equivalent to the ClutterActor::visible object property.
538 * Note that an actor is only painted onscreen if it's mapped, which
539 * means it's visible, and all its parents are visible, and one of the
540 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
546 * CLUTTER_ACTOR_IS_REACTIVE:
547 * @a: a #ClutterActor
549 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
551 * Only reactive actors will receive event-related signals.
562 #include <gobject/gvaluecollector.h>
564 #include <cogl/cogl.h>
566 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
567 #define CLUTTER_ENABLE_EXPERIMENTAL_API
569 #include "clutter-actor-private.h"
571 #include "clutter-action.h"
572 #include "clutter-actor-meta-private.h"
573 #include "clutter-animatable.h"
574 #include "clutter-color-static.h"
575 #include "clutter-color.h"
576 #include "clutter-constraint.h"
577 #include "clutter-container.h"
578 #include "clutter-content-private.h"
579 #include "clutter-debug.h"
580 #include "clutter-effect-private.h"
581 #include "clutter-enum-types.h"
582 #include "clutter-fixed-layout.h"
583 #include "clutter-flatten-effect.h"
584 #include "clutter-interval.h"
585 #include "clutter-main.h"
586 #include "clutter-marshal.h"
587 #include "clutter-paint-nodes.h"
588 #include "clutter-paint-node-private.h"
589 #include "clutter-paint-volume-private.h"
590 #include "clutter-private.h"
591 #include "clutter-profile.h"
592 #include "clutter-property-transition.h"
593 #include "clutter-scriptable.h"
594 #include "clutter-script-private.h"
595 #include "clutter-stage-private.h"
596 #include "clutter-timeline.h"
597 #include "clutter-transition.h"
598 #include "clutter-units.h"
600 #include "deprecated/clutter-actor.h"
601 #include "deprecated/clutter-behaviour.h"
602 #include "deprecated/clutter-container.h"
604 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
605 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
607 /* Internal enum used to control mapped state update. This is a hint
608 * which indicates when to do something other than just enforce
612 MAP_STATE_CHECK, /* just enforce invariants. */
613 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
614 * used when about to unparent.
616 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
617 * used to set mapped on toplevels.
619 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
620 * used just before unmapping parent.
624 /* 3 entries should be a good compromise, few layout managers
625 * will ask for 3 different preferred size in each allocation cycle */
626 #define N_CACHED_SIZE_REQUESTS 3
628 struct _ClutterActorPrivate
631 ClutterRequestMode request_mode;
633 /* our cached size requests for different width / height */
634 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
635 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
637 /* An age of 0 means the entry is not set */
638 guint cached_height_age;
639 guint cached_width_age;
641 /* the bounding box of the actor, relative to the parent's
644 ClutterActorBox allocation;
645 ClutterAllocationFlags allocation_flags;
647 /* clip, in actor coordinates */
648 cairo_rectangle_t clip;
650 /* the cached transformation matrix; see apply_transform() */
651 CoglMatrix transform;
654 gint opacity_override;
656 ClutterOffscreenRedirect offscreen_redirect;
658 /* This is an internal effect used to implement the
659 offscreen-redirect property */
660 ClutterEffect *flatten_effect;
663 ClutterActor *parent;
664 ClutterActor *prev_sibling;
665 ClutterActor *next_sibling;
666 ClutterActor *first_child;
667 ClutterActor *last_child;
671 /* tracks whenever the children of an actor are changed; the
672 * age is incremented by 1 whenever an actor is added or
673 * removed. the age is not incremented when the first or the
674 * last child pointers are changed, or when grandchildren of
675 * an actor are changed.
679 gchar *name; /* a non-unique name, used for debugging */
680 guint32 id; /* unique id, used for backward compatibility */
682 gint32 pick_id; /* per-stage unique id, used for picking */
684 /* a back-pointer to the Pango context that we can use
685 * to create pre-configured PangoLayout
687 PangoContext *pango_context;
689 /* the text direction configured for this child - either by
690 * application code, or by the actor's parent
692 ClutterTextDirection text_direction;
694 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
698 ClutterMetaGroup *actions;
699 ClutterMetaGroup *constraints;
700 ClutterMetaGroup *effects;
702 /* delegate object used to allocate the children of this actor */
703 ClutterLayoutManager *layout_manager;
705 /* delegate object used to paint the contents of this actor */
706 ClutterContent *content;
708 ClutterActorBox content_box;
709 ClutterContentGravity content_gravity;
710 ClutterScalingFilter min_filter;
711 ClutterScalingFilter mag_filter;
713 /* used when painting, to update the paint volume */
714 ClutterEffect *current_effect;
716 /* This is used to store an effect which needs to be redrawn. A
717 redraw can be queued to start from a particular effect. This is
718 used by parametrised effects that can cache an image of the
719 actor. If a parameter of the effect changes then it only needs to
720 redraw the cached image, not the actual actor. The pointer is
721 only valid if is_dirty == TRUE. If the pointer is NULL then the
722 whole actor is dirty. */
723 ClutterEffect *effect_to_redraw;
725 /* This is used when painting effects to implement the
726 clutter_actor_continue_paint() function. It points to the node in
727 the list of effects that is next in the chain */
728 const GList *next_effect_to_paint;
730 ClutterPaintVolume paint_volume;
732 /* NB: This volume isn't relative to this actor, it is in eye
733 * coordinates so that it can remain valid after the actor changes.
735 ClutterPaintVolume last_paint_volume;
737 ClutterStageQueueRedrawEntry *queue_redraw_entry;
739 ClutterColor bg_color;
743 /* fixed position and sizes */
744 guint position_set : 1;
745 guint min_width_set : 1;
746 guint min_height_set : 1;
747 guint natural_width_set : 1;
748 guint natural_height_set : 1;
749 /* cached request is invalid (implies allocation is too) */
750 guint needs_width_request : 1;
751 /* cached request is invalid (implies allocation is too) */
752 guint needs_height_request : 1;
753 /* cached allocation is invalid (request has changed, probably) */
754 guint needs_allocation : 1;
755 guint show_on_set_parent : 1;
757 guint clip_to_allocation : 1;
758 guint enable_model_view_transform : 1;
759 guint enable_paint_unmapped : 1;
760 guint has_pointer : 1;
761 guint propagated_one_redraw : 1;
762 guint paint_volume_valid : 1;
763 guint last_paint_volume_valid : 1;
764 guint in_clone_paint : 1;
765 guint transform_valid : 1;
766 /* This is TRUE if anything has queued a redraw since we were last
767 painted. In this case effect_to_redraw will point to an effect
768 the redraw was queued from or it will be NULL if the redraw was
769 queued without an effect. */
771 guint bg_color_set : 1;
772 guint content_box_valid : 1;
781 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
782 * when set they force a size request, when gotten they
783 * get the allocation if the allocation is valid, and the
791 /* Then the rest of these size-related properties are the "actual"
792 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
797 PROP_FIXED_POSITION_SET,
806 PROP_NATURAL_WIDTH_SET,
809 PROP_NATURAL_HEIGHT_SET,
813 /* Allocation properties are read-only */
820 PROP_CLIP_TO_ALLOCATION,
824 PROP_OFFSCREEN_REDIRECT,
837 PROP_ROTATION_ANGLE_X,
838 PROP_ROTATION_ANGLE_Y,
839 PROP_ROTATION_ANGLE_Z,
840 PROP_ROTATION_CENTER_X,
841 PROP_ROTATION_CENTER_Y,
842 PROP_ROTATION_CENTER_Z,
843 /* This property only makes sense for the z rotation because the
844 others would depend on the actor having a size along the
846 PROP_ROTATION_CENTER_Z_GRAVITY,
852 PROP_SHOW_ON_SET_PARENT,
870 PROP_BACKGROUND_COLOR,
871 PROP_BACKGROUND_COLOR_SET,
877 PROP_CONTENT_GRAVITY,
879 PROP_MINIFICATION_FILTER,
880 PROP_MAGNIFICATION_FILTER,
885 static GParamSpec *obj_props[PROP_LAST];
904 BUTTON_RELEASE_EVENT,
912 TRANSITIONS_COMPLETED,
917 static guint actor_signals[LAST_SIGNAL] = { 0, };
919 static void clutter_container_iface_init (ClutterContainerIface *iface);
920 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
921 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
922 static void atk_implementor_iface_init (AtkImplementorIface *iface);
924 /* These setters are all static for now, maybe they should be in the
925 * public API, but they are perhaps obscure enough to leave only as
928 static void clutter_actor_set_min_width (ClutterActor *self,
930 static void clutter_actor_set_min_height (ClutterActor *self,
932 static void clutter_actor_set_natural_width (ClutterActor *self,
933 gfloat natural_width);
934 static void clutter_actor_set_natural_height (ClutterActor *self,
935 gfloat natural_height);
936 static void clutter_actor_set_min_width_set (ClutterActor *self,
937 gboolean use_min_width);
938 static void clutter_actor_set_min_height_set (ClutterActor *self,
939 gboolean use_min_height);
940 static void clutter_actor_set_natural_width_set (ClutterActor *self,
941 gboolean use_natural_width);
942 static void clutter_actor_set_natural_height_set (ClutterActor *self,
943 gboolean use_natural_height);
944 static void clutter_actor_update_map_state (ClutterActor *self,
945 MapStateChange change);
946 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
948 /* Helper routines for managing anchor coords */
949 static void clutter_anchor_coord_get_units (ClutterActor *self,
950 const AnchorCoord *coord,
954 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
959 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
960 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
961 ClutterGravity gravity);
963 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
965 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
967 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
968 ClutterActor *ancestor,
971 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
973 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
975 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
976 const ClutterColor *color);
978 static void on_layout_manager_changed (ClutterLayoutManager *manager,
981 /* Helper macro which translates by the anchor coord, applies the
982 given transformation and then translates back */
983 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
984 gfloat _tx, _ty, _tz; \
985 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
986 cogl_matrix_translate ((m), _tx, _ty, _tz); \
988 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
990 static GQuark quark_shader_data = 0;
991 static GQuark quark_actor_layout_info = 0;
992 static GQuark quark_actor_transform_info = 0;
993 static GQuark quark_actor_animation_info = 0;
995 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
997 G_TYPE_INITIALLY_UNOWNED,
998 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
999 clutter_container_iface_init)
1000 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1001 clutter_scriptable_iface_init)
1002 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1003 clutter_animatable_iface_init)
1004 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1005 atk_implementor_iface_init));
1008 * clutter_actor_get_debug_name:
1009 * @actor: a #ClutterActor
1011 * Retrieves a printable name of @actor for debugging messages
1013 * Return value: a string with a printable name
1016 _clutter_actor_get_debug_name (ClutterActor *actor)
1018 return actor->priv->name != NULL ? actor->priv->name
1019 : G_OBJECT_TYPE_NAME (actor);
1022 #ifdef CLUTTER_ENABLE_DEBUG
1023 /* XXX - this is for debugging only, remove once working (or leave
1024 * in only in some debug mode). Should leave it for a little while
1025 * until we're confident in the new map/realize/visible handling.
1028 clutter_actor_verify_map_state (ClutterActor *self)
1030 ClutterActorPrivate *priv = self->priv;
1032 if (CLUTTER_ACTOR_IS_REALIZED (self))
1034 /* all bets are off during reparent when we're potentially realized,
1035 * but should not be according to invariants
1037 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1039 if (priv->parent == NULL)
1041 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1045 g_warning ("Realized non-toplevel actor '%s' should "
1047 _clutter_actor_get_debug_name (self));
1049 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1051 g_warning ("Realized actor %s has an unrealized parent %s",
1052 _clutter_actor_get_debug_name (self),
1053 _clutter_actor_get_debug_name (priv->parent));
1058 if (CLUTTER_ACTOR_IS_MAPPED (self))
1060 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1061 g_warning ("Actor '%s' is mapped but not realized",
1062 _clutter_actor_get_debug_name (self));
1064 /* remaining bets are off during reparent when we're potentially
1065 * mapped, but should not be according to invariants
1067 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1069 if (priv->parent == NULL)
1071 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1073 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1074 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1076 g_warning ("Toplevel actor '%s' is mapped "
1078 _clutter_actor_get_debug_name (self));
1083 g_warning ("Mapped actor '%s' should have a parent",
1084 _clutter_actor_get_debug_name (self));
1089 ClutterActor *iter = self;
1091 /* check for the enable_paint_unmapped flag on the actor
1092 * and parents; if the flag is enabled at any point of this
1093 * branch of the scene graph then all the later checks
1096 while (iter != NULL)
1098 if (iter->priv->enable_paint_unmapped)
1101 iter = iter->priv->parent;
1104 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1106 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1108 _clutter_actor_get_debug_name (self),
1109 _clutter_actor_get_debug_name (priv->parent));
1112 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1114 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1116 _clutter_actor_get_debug_name (self),
1117 _clutter_actor_get_debug_name (priv->parent));
1120 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1122 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1123 g_warning ("Actor '%s' is mapped but its non-toplevel "
1124 "parent '%s' is not mapped",
1125 _clutter_actor_get_debug_name (self),
1126 _clutter_actor_get_debug_name (priv->parent));
1133 #endif /* CLUTTER_ENABLE_DEBUG */
1136 clutter_actor_set_mapped (ClutterActor *self,
1139 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1144 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1145 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1149 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1150 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1154 /* this function updates the mapped and realized states according to
1155 * invariants, in the appropriate order.
1158 clutter_actor_update_map_state (ClutterActor *self,
1159 MapStateChange change)
1161 gboolean was_mapped;
1163 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1165 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1167 /* the mapped flag on top-level actors must be set by the
1168 * per-backend implementation because it might be asynchronous.
1170 * That is, the MAPPED flag on toplevels currently tracks the X
1171 * server mapped-ness of the window, while the expected behavior
1172 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1173 * This creates some weird complexity by breaking the invariant
1174 * that if we're visible and all ancestors shown then we are
1175 * also mapped - instead, we are mapped if all ancestors
1176 * _possibly excepting_ the stage are mapped. The stage
1177 * will map/unmap for example when it is minimized or
1178 * moved to another workspace.
1180 * So, the only invariant on the stage is that if visible it
1181 * should be realized, and that it has to be visible to be
1184 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1185 clutter_actor_realize (self);
1189 case MAP_STATE_CHECK:
1192 case MAP_STATE_MAKE_MAPPED:
1193 g_assert (!was_mapped);
1194 clutter_actor_set_mapped (self, TRUE);
1197 case MAP_STATE_MAKE_UNMAPPED:
1198 g_assert (was_mapped);
1199 clutter_actor_set_mapped (self, FALSE);
1202 case MAP_STATE_MAKE_UNREALIZED:
1203 /* we only use MAKE_UNREALIZED in unparent,
1204 * and unparenting a stage isn't possible.
1205 * If someone wants to just unrealize a stage
1206 * then clutter_actor_unrealize() doesn't
1207 * go through this codepath.
1209 g_warning ("Trying to force unrealize stage is not allowed");
1213 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1214 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1215 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1217 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1218 "it is somehow still mapped",
1219 _clutter_actor_get_debug_name (self));
1224 ClutterActorPrivate *priv = self->priv;
1225 ClutterActor *parent = priv->parent;
1226 gboolean should_be_mapped;
1227 gboolean may_be_realized;
1228 gboolean must_be_realized;
1230 should_be_mapped = FALSE;
1231 may_be_realized = TRUE;
1232 must_be_realized = FALSE;
1234 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1236 may_be_realized = FALSE;
1240 /* Maintain invariant that if parent is mapped, and we are
1241 * visible, then we are mapped ... unless parent is a
1242 * stage, in which case we map regardless of parent's map
1243 * state but do require stage to be visible and realized.
1245 * If parent is realized, that does not force us to be
1246 * realized; but if parent is unrealized, that does force
1247 * us to be unrealized.
1249 * The reason we don't force children to realize with
1250 * parents is _clutter_actor_rerealize(); if we require that
1251 * a realized parent means children are realized, then to
1252 * unrealize an actor we would have to unrealize its
1253 * parents, which would end up meaning unrealizing and
1254 * hiding the entire stage. So we allow unrealizing a
1255 * child (as long as that child is not mapped) while that
1256 * child still has a realized parent.
1258 * Also, if we unrealize from leaf nodes to root, and
1259 * realize from root to leaf, the invariants are never
1260 * violated if we allow children to be unrealized
1261 * while parents are realized.
1263 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1264 * to force us to unmap, even though parent is still
1265 * mapped. This is because we're unmapping from leaf nodes
1268 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1269 change != MAP_STATE_MAKE_UNMAPPED)
1271 gboolean parent_is_visible_realized_toplevel;
1273 parent_is_visible_realized_toplevel =
1274 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1275 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1276 CLUTTER_ACTOR_IS_REALIZED (parent));
1278 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1279 parent_is_visible_realized_toplevel)
1281 must_be_realized = TRUE;
1282 should_be_mapped = TRUE;
1286 /* if the actor has been set to be painted even if unmapped
1287 * then we should map it and check for realization as well;
1288 * this is an override for the branch of the scene graph
1289 * which begins with this node
1291 if (priv->enable_paint_unmapped)
1293 if (priv->parent == NULL)
1294 g_warning ("Attempting to map an unparented actor '%s'",
1295 _clutter_actor_get_debug_name (self));
1297 should_be_mapped = TRUE;
1298 must_be_realized = TRUE;
1301 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1302 may_be_realized = FALSE;
1305 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1308 g_warning ("Attempting to map a child that does not "
1309 "meet the necessary invariants: the actor '%s' "
1311 _clutter_actor_get_debug_name (self));
1313 g_warning ("Attempting to map a child that does not "
1314 "meet the necessary invariants: the actor '%s' "
1315 "is parented to an unmapped actor '%s'",
1316 _clutter_actor_get_debug_name (self),
1317 _clutter_actor_get_debug_name (priv->parent));
1320 /* If in reparent, we temporarily suspend unmap and unrealize.
1322 * We want to go in the order "realize, map" and "unmap, unrealize"
1326 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1327 clutter_actor_set_mapped (self, FALSE);
1330 if (must_be_realized)
1331 clutter_actor_realize (self);
1333 /* if we must be realized then we may be, presumably */
1334 g_assert (!(must_be_realized && !may_be_realized));
1337 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1338 clutter_actor_unrealize_not_hiding (self);
1341 if (should_be_mapped)
1343 if (!must_be_realized)
1344 g_warning ("Somehow we think actor '%s' should be mapped but "
1345 "not realized, which isn't allowed",
1346 _clutter_actor_get_debug_name (self));
1348 /* realization is allowed to fail (though I don't know what
1349 * an app is supposed to do about that - shouldn't it just
1350 * be a g_error? anyway, we have to avoid mapping if this
1353 if (CLUTTER_ACTOR_IS_REALIZED (self))
1354 clutter_actor_set_mapped (self, TRUE);
1358 #ifdef CLUTTER_ENABLE_DEBUG
1359 /* check all invariants were kept */
1360 clutter_actor_verify_map_state (self);
1365 clutter_actor_real_map (ClutterActor *self)
1367 ClutterActorPrivate *priv = self->priv;
1368 ClutterActor *stage, *iter;
1370 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1372 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1373 _clutter_actor_get_debug_name (self));
1375 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1377 stage = _clutter_actor_get_stage_internal (self);
1378 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1380 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1382 _clutter_actor_get_debug_name (self));
1384 /* notify on parent mapped before potentially mapping
1385 * children, so apps see a top-down notification.
1387 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1389 for (iter = self->priv->first_child;
1391 iter = iter->priv->next_sibling)
1393 clutter_actor_map (iter);
1398 * clutter_actor_map:
1399 * @self: A #ClutterActor
1401 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1402 * and realizes its children if they are visible. Does nothing if the
1403 * actor is not visible.
1405 * Calling this function is strongly disencouraged: the default
1406 * implementation of #ClutterActorClass.map() will map all the children
1407 * of an actor when mapping its parent.
1409 * When overriding map, it is mandatory to chain up to the parent
1415 clutter_actor_map (ClutterActor *self)
1417 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1419 if (CLUTTER_ACTOR_IS_MAPPED (self))
1422 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1425 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1429 clutter_actor_real_unmap (ClutterActor *self)
1431 ClutterActorPrivate *priv = self->priv;
1434 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1436 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1437 _clutter_actor_get_debug_name (self));
1439 for (iter = self->priv->first_child;
1441 iter = iter->priv->next_sibling)
1443 clutter_actor_unmap (iter);
1446 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1448 /* clear the contents of the last paint volume, so that hiding + moving +
1449 * showing will not result in the wrong area being repainted
1451 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1452 priv->last_paint_volume_valid = TRUE;
1454 /* notify on parent mapped after potentially unmapping
1455 * children, so apps see a bottom-up notification.
1457 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1459 /* relinquish keyboard focus if we were unmapped while owning it */
1460 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1462 ClutterStage *stage;
1464 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1467 _clutter_stage_release_pick_id (stage, priv->pick_id);
1471 if (stage != NULL &&
1472 clutter_stage_get_key_focus (stage) == self)
1474 clutter_stage_set_key_focus (stage, NULL);
1480 * clutter_actor_unmap:
1481 * @self: A #ClutterActor
1483 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1484 * unmaps its children if they were mapped.
1486 * Calling this function is not encouraged: the default #ClutterActor
1487 * implementation of #ClutterActorClass.unmap() will also unmap any
1488 * eventual children by default when their parent is unmapped.
1490 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1491 * chain up to the parent implementation.
1493 * <note>It is important to note that the implementation of the
1494 * #ClutterActorClass.unmap() virtual function may be called after
1495 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1496 * implementation, but it is guaranteed to be called before the
1497 * #GObjectClass.finalize() implementation.</note>
1502 clutter_actor_unmap (ClutterActor *self)
1504 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1506 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1509 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1513 clutter_actor_real_show (ClutterActor *self)
1515 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1517 ClutterActorPrivate *priv = self->priv;
1519 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1521 /* we notify on the "visible" flag in the clutter_actor_show()
1522 * wrapper so the entire show signal emission completes first
1525 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1527 /* we queue a relayout unless the actor is inside a
1528 * container that explicitly told us not to
1530 if (priv->parent != NULL &&
1531 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1533 /* While an actor is hidden the parent may not have
1534 * allocated/requested so we need to start from scratch
1535 * and avoid the short-circuiting in
1536 * clutter_actor_queue_relayout().
1538 priv->needs_width_request = FALSE;
1539 priv->needs_height_request = FALSE;
1540 priv->needs_allocation = FALSE;
1541 clutter_actor_queue_relayout (self);
1547 set_show_on_set_parent (ClutterActor *self,
1550 ClutterActorPrivate *priv = self->priv;
1552 set_show = !!set_show;
1554 if (priv->show_on_set_parent == set_show)
1557 if (priv->parent == NULL)
1559 priv->show_on_set_parent = set_show;
1560 g_object_notify_by_pspec (G_OBJECT (self),
1561 obj_props[PROP_SHOW_ON_SET_PARENT]);
1566 * clutter_actor_show:
1567 * @self: A #ClutterActor
1569 * Flags an actor to be displayed. An actor that isn't shown will not
1570 * be rendered on the stage.
1572 * Actors are visible by default.
1574 * If this function is called on an actor without a parent, the
1575 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1579 clutter_actor_show (ClutterActor *self)
1581 ClutterActorPrivate *priv;
1583 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1585 /* simple optimization */
1586 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1588 /* we still need to set the :show-on-set-parent property, in
1589 * case show() is called on an unparented actor
1591 set_show_on_set_parent (self, TRUE);
1595 #ifdef CLUTTER_ENABLE_DEBUG
1596 clutter_actor_verify_map_state (self);
1601 g_object_freeze_notify (G_OBJECT (self));
1603 set_show_on_set_parent (self, TRUE);
1605 g_signal_emit (self, actor_signals[SHOW], 0);
1606 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1608 if (priv->parent != NULL)
1609 clutter_actor_queue_redraw (priv->parent);
1611 g_object_thaw_notify (G_OBJECT (self));
1615 * clutter_actor_show_all:
1616 * @self: a #ClutterActor
1618 * Calls clutter_actor_show() on all children of an actor (if any).
1622 * Deprecated: 1.10: Actors are visible by default
1625 clutter_actor_show_all (ClutterActor *self)
1627 ClutterActorClass *klass;
1629 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1631 klass = CLUTTER_ACTOR_GET_CLASS (self);
1632 if (klass->show_all)
1633 klass->show_all (self);
1637 clutter_actor_real_hide (ClutterActor *self)
1639 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1641 ClutterActorPrivate *priv = self->priv;
1643 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1645 /* we notify on the "visible" flag in the clutter_actor_hide()
1646 * wrapper so the entire hide signal emission completes first
1649 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1651 /* we queue a relayout unless the actor is inside a
1652 * container that explicitly told us not to
1654 if (priv->parent != NULL &&
1655 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1656 clutter_actor_queue_relayout (priv->parent);
1661 * clutter_actor_hide:
1662 * @self: A #ClutterActor
1664 * Flags an actor to be hidden. A hidden actor will not be
1665 * rendered on the stage.
1667 * Actors are visible by default.
1669 * If this function is called on an actor without a parent, the
1670 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1674 clutter_actor_hide (ClutterActor *self)
1676 ClutterActorPrivate *priv;
1678 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1680 /* simple optimization */
1681 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1683 /* we still need to set the :show-on-set-parent property, in
1684 * case hide() is called on an unparented actor
1686 set_show_on_set_parent (self, FALSE);
1690 #ifdef CLUTTER_ENABLE_DEBUG
1691 clutter_actor_verify_map_state (self);
1696 g_object_freeze_notify (G_OBJECT (self));
1698 set_show_on_set_parent (self, FALSE);
1700 g_signal_emit (self, actor_signals[HIDE], 0);
1701 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1703 if (priv->parent != NULL)
1704 clutter_actor_queue_redraw (priv->parent);
1706 g_object_thaw_notify (G_OBJECT (self));
1710 * clutter_actor_hide_all:
1711 * @self: a #ClutterActor
1713 * Calls clutter_actor_hide() on all child actors (if any).
1717 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1718 * prevent its children from being painted as well.
1721 clutter_actor_hide_all (ClutterActor *self)
1723 ClutterActorClass *klass;
1725 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1727 klass = CLUTTER_ACTOR_GET_CLASS (self);
1728 if (klass->hide_all)
1729 klass->hide_all (self);
1733 * clutter_actor_realize:
1734 * @self: A #ClutterActor
1736 * Realization informs the actor that it is attached to a stage. It
1737 * can use this to allocate resources if it wanted to delay allocation
1738 * until it would be rendered. However it is perfectly acceptable for
1739 * an actor to create resources before being realized because Clutter
1740 * only ever has a single rendering context so that actor is free to
1741 * be moved from one stage to another.
1743 * This function does nothing if the actor is already realized.
1745 * Because a realized actor must have realized parent actors, calling
1746 * clutter_actor_realize() will also realize all parents of the actor.
1748 * This function does not realize child actors, except in the special
1749 * case that realizing the stage, when the stage is visible, will
1750 * suddenly map (and thus realize) the children of the stage.
1753 clutter_actor_realize (ClutterActor *self)
1755 ClutterActorPrivate *priv;
1757 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1761 #ifdef CLUTTER_ENABLE_DEBUG
1762 clutter_actor_verify_map_state (self);
1765 if (CLUTTER_ACTOR_IS_REALIZED (self))
1768 /* To be realized, our parent actors must be realized first.
1769 * This will only succeed if we're inside a toplevel.
1771 if (priv->parent != NULL)
1772 clutter_actor_realize (priv->parent);
1774 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1776 /* toplevels can be realized at any time */
1780 /* "Fail" the realization if parent is missing or unrealized;
1781 * this should really be a g_warning() not some kind of runtime
1782 * failure; how can an app possibly recover? Instead it's a bug
1783 * in the app and the app should get an explanatory warning so
1784 * someone can fix it. But for now it's too hard to fix this
1785 * because e.g. ClutterTexture needs reworking.
1787 if (priv->parent == NULL ||
1788 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1792 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1794 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1795 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1797 g_signal_emit (self, actor_signals[REALIZE], 0);
1799 /* Stage actor is allowed to unset the realized flag again in its
1800 * default signal handler, though that is a pathological situation.
1803 /* If realization "failed" we'll have to update child state. */
1804 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1808 clutter_actor_real_unrealize (ClutterActor *self)
1810 /* we must be unmapped (implying our children are also unmapped) */
1811 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1815 * clutter_actor_unrealize:
1816 * @self: A #ClutterActor
1818 * Unrealization informs the actor that it may be being destroyed or
1819 * moved to another stage. The actor may want to destroy any
1820 * underlying graphics resources at this point. However it is
1821 * perfectly acceptable for it to retain the resources until the actor
1822 * is destroyed because Clutter only ever uses a single rendering
1823 * context and all of the graphics resources are valid on any stage.
1825 * Because mapped actors must be realized, actors may not be
1826 * unrealized if they are mapped. This function hides the actor to be
1827 * sure it isn't mapped, an application-visible side effect that you
1828 * may not be expecting.
1830 * This function should not be called by application code.
1833 clutter_actor_unrealize (ClutterActor *self)
1835 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1836 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1838 /* This function should not really be in the public API, because
1839 * there isn't a good reason to call it. ClutterActor will already
1840 * unrealize things for you when it's important to do so.
1842 * If you were using clutter_actor_unrealize() in a dispose
1843 * implementation, then don't, just chain up to ClutterActor's
1846 * If you were using clutter_actor_unrealize() to implement
1847 * unrealizing children of your container, then don't, ClutterActor
1848 * will already take care of that.
1850 * If you were using clutter_actor_unrealize() to re-realize to
1851 * create your resources in a different way, then use
1852 * _clutter_actor_rerealize() (inside Clutter) or just call your
1853 * code that recreates your resources directly (outside Clutter).
1856 #ifdef CLUTTER_ENABLE_DEBUG
1857 clutter_actor_verify_map_state (self);
1860 clutter_actor_hide (self);
1862 clutter_actor_unrealize_not_hiding (self);
1865 static ClutterActorTraverseVisitFlags
1866 unrealize_actor_before_children_cb (ClutterActor *self,
1870 /* If an actor is already unrealized we know its children have also
1871 * already been unrealized... */
1872 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1873 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1875 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1877 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1880 static ClutterActorTraverseVisitFlags
1881 unrealize_actor_after_children_cb (ClutterActor *self,
1885 /* We want to unset the realized flag only _after_
1886 * child actors are unrealized, to maintain invariants.
1888 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1889 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1890 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1894 * clutter_actor_unrealize_not_hiding:
1895 * @self: A #ClutterActor
1897 * Unrealization informs the actor that it may be being destroyed or
1898 * moved to another stage. The actor may want to destroy any
1899 * underlying graphics resources at this point. However it is
1900 * perfectly acceptable for it to retain the resources until the actor
1901 * is destroyed because Clutter only ever uses a single rendering
1902 * context and all of the graphics resources are valid on any stage.
1904 * Because mapped actors must be realized, actors may not be
1905 * unrealized if they are mapped. You must hide the actor or one of
1906 * its parents before attempting to unrealize.
1908 * This function is separate from clutter_actor_unrealize() because it
1909 * does not automatically hide the actor.
1910 * Actors need not be hidden to be unrealized, they just need to
1911 * be unmapped. In fact we don't want to mess up the application's
1912 * setting of the "visible" flag, so hiding is very undesirable.
1914 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1915 * backward compatibility.
1918 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1920 _clutter_actor_traverse (self,
1921 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1922 unrealize_actor_before_children_cb,
1923 unrealize_actor_after_children_cb,
1928 * _clutter_actor_rerealize:
1929 * @self: A #ClutterActor
1930 * @callback: Function to call while unrealized
1931 * @data: data for callback
1933 * If an actor is already unrealized, this just calls the callback.
1935 * If it is realized, it unrealizes temporarily, calls the callback,
1936 * and then re-realizes the actor.
1938 * As a side effect, leaves all children of the actor unrealized if
1939 * the actor was realized but not showing. This is because when we
1940 * unrealize the actor temporarily we must unrealize its children
1941 * (e.g. children of a stage can't be realized if stage window is
1942 * gone). And we aren't clever enough to save the realization state of
1943 * all children. In most cases this should not matter, because
1944 * the children will automatically realize when they next become mapped.
1947 _clutter_actor_rerealize (ClutterActor *self,
1948 ClutterCallback callback,
1951 gboolean was_mapped;
1952 gboolean was_showing;
1953 gboolean was_realized;
1955 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1957 #ifdef CLUTTER_ENABLE_DEBUG
1958 clutter_actor_verify_map_state (self);
1961 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1962 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1963 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1965 /* Must be unmapped to unrealize. Note we only have to hide this
1966 * actor if it was mapped (if all parents were showing). If actor
1967 * is merely visible (but not mapped), then that's fine, we can
1971 clutter_actor_hide (self);
1973 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1975 /* unrealize self and all children */
1976 clutter_actor_unrealize_not_hiding (self);
1978 if (callback != NULL)
1980 (* callback) (self, data);
1984 clutter_actor_show (self); /* will realize only if mapping implies it */
1985 else if (was_realized)
1986 clutter_actor_realize (self); /* realize self and all parents */
1990 clutter_actor_real_pick (ClutterActor *self,
1991 const ClutterColor *color)
1993 /* the default implementation is just to paint a rectangle
1994 * with the same size of the actor using the passed color
1996 if (clutter_actor_should_pick_paint (self))
1998 ClutterActorBox box = { 0, };
1999 float width, height;
2001 clutter_actor_get_allocation_box (self, &box);
2003 width = box.x2 - box.x1;
2004 height = box.y2 - box.y1;
2006 cogl_set_source_color4ub (color->red,
2011 cogl_rectangle (0, 0, width, height);
2014 /* XXX - this thoroughly sucks, but we need to maintain compatibility
2015 * with existing container classes that override the pick() virtual
2016 * and chain up to the default implementation - otherwise we'll end up
2017 * painting our children twice.
2019 * this has to go away for 2.0; hopefully along the pick() itself.
2021 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2025 for (iter = self->priv->first_child;
2027 iter = iter->priv->next_sibling)
2028 clutter_actor_paint (iter);
2033 * clutter_actor_should_pick_paint:
2034 * @self: A #ClutterActor
2036 * Should be called inside the implementation of the
2037 * #ClutterActor::pick virtual function in order to check whether
2038 * the actor should paint itself in pick mode or not.
2040 * This function should never be called directly by applications.
2042 * Return value: %TRUE if the actor should paint its silhouette,
2046 clutter_actor_should_pick_paint (ClutterActor *self)
2048 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2050 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2051 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2052 CLUTTER_ACTOR_IS_REACTIVE (self)))
2059 clutter_actor_real_get_preferred_width (ClutterActor *self,
2061 gfloat *min_width_p,
2062 gfloat *natural_width_p)
2064 ClutterActorPrivate *priv = self->priv;
2066 if (priv->n_children != 0 &&
2067 priv->layout_manager != NULL)
2069 ClutterContainer *container = CLUTTER_CONTAINER (self);
2071 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2072 "for the preferred width",
2073 G_OBJECT_TYPE_NAME (priv->layout_manager),
2074 priv->layout_manager);
2076 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2085 /* Default implementation is always 0x0, usually an actor
2086 * using this default is relying on someone to set the
2089 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2094 if (natural_width_p)
2095 *natural_width_p = 0;
2099 clutter_actor_real_get_preferred_height (ClutterActor *self,
2101 gfloat *min_height_p,
2102 gfloat *natural_height_p)
2104 ClutterActorPrivate *priv = self->priv;
2106 if (priv->n_children != 0 &&
2107 priv->layout_manager != NULL)
2109 ClutterContainer *container = CLUTTER_CONTAINER (self);
2111 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2112 "for the preferred height",
2113 G_OBJECT_TYPE_NAME (priv->layout_manager),
2114 priv->layout_manager);
2116 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2124 /* Default implementation is always 0x0, usually an actor
2125 * using this default is relying on someone to set the
2128 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2133 if (natural_height_p)
2134 *natural_height_p = 0;
2138 clutter_actor_store_old_geometry (ClutterActor *self,
2139 ClutterActorBox *box)
2141 *box = self->priv->allocation;
2145 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2146 const ClutterActorBox *old)
2148 ClutterActorPrivate *priv = self->priv;
2149 GObject *obj = G_OBJECT (self);
2151 g_object_freeze_notify (obj);
2153 /* to avoid excessive requisition or allocation cycles we
2154 * use the cached values.
2156 * - if we don't have an allocation we assume that we need
2158 * - if we don't have a width or a height request we notify
2160 * - if we have a valid allocation then we check the old
2161 * bounding box with the current allocation and we notify
2164 if (priv->needs_allocation)
2166 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2167 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2168 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2169 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2171 else if (priv->needs_width_request || priv->needs_height_request)
2173 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2174 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2179 gfloat width, height;
2181 x = priv->allocation.x1;
2182 y = priv->allocation.y1;
2183 width = priv->allocation.x2 - priv->allocation.x1;
2184 height = priv->allocation.y2 - priv->allocation.y1;
2187 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2190 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2192 if (width != (old->x2 - old->x1))
2193 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2195 if (height != (old->y2 - old->y1))
2196 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2199 g_object_thaw_notify (obj);
2203 * clutter_actor_set_allocation_internal:
2204 * @self: a #ClutterActor
2205 * @box: a #ClutterActorBox
2206 * @flags: allocation flags
2208 * Stores the allocation of @self.
2210 * This function only performs basic storage and property notification.
2212 * This function should be called by clutter_actor_set_allocation()
2213 * and by the default implementation of #ClutterActorClass.allocate().
2215 * Return value: %TRUE if the allocation of the #ClutterActor has been
2216 * changed, and %FALSE otherwise
2218 static inline gboolean
2219 clutter_actor_set_allocation_internal (ClutterActor *self,
2220 const ClutterActorBox *box,
2221 ClutterAllocationFlags flags)
2223 ClutterActorPrivate *priv = self->priv;
2225 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2226 gboolean flags_changed;
2228 ClutterActorBox old_alloc = { 0, };
2230 obj = G_OBJECT (self);
2232 g_object_freeze_notify (obj);
2234 clutter_actor_store_old_geometry (self, &old_alloc);
2236 x1_changed = priv->allocation.x1 != box->x1;
2237 y1_changed = priv->allocation.y1 != box->y1;
2238 x2_changed = priv->allocation.x2 != box->x2;
2239 y2_changed = priv->allocation.y2 != box->y2;
2241 flags_changed = priv->allocation_flags != flags;
2243 priv->allocation = *box;
2244 priv->allocation_flags = flags;
2246 /* allocation is authoritative */
2247 priv->needs_width_request = FALSE;
2248 priv->needs_height_request = FALSE;
2249 priv->needs_allocation = FALSE;
2251 if (x1_changed || y1_changed ||
2252 x2_changed || y2_changed ||
2255 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2256 _clutter_actor_get_debug_name (self));
2258 priv->transform_valid = FALSE;
2260 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2262 /* if the allocation changes, so does the content box */
2263 if (priv->content != NULL)
2265 priv->content_box_valid = FALSE;
2266 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2274 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2276 g_object_thaw_notify (obj);
2281 static void clutter_actor_real_allocate (ClutterActor *self,
2282 const ClutterActorBox *box,
2283 ClutterAllocationFlags flags);
2286 clutter_actor_maybe_layout_children (ClutterActor *self,
2287 const ClutterActorBox *allocation,
2288 ClutterAllocationFlags flags)
2290 ClutterActorPrivate *priv = self->priv;
2292 /* this is going to be a bit hard to follow, so let's put an explanation
2295 * we want ClutterActor to have a default layout manager if the actor was
2296 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2298 * we also want any subclass of ClutterActor that does not override the
2299 * ::allocate() virtual function to delegate to a layout manager.
2301 * finally, we want to allow people subclassing ClutterActor and overriding
2302 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2304 * on the other hand, we want existing actor subclasses overriding the
2305 * ::allocate() virtual function and chaining up to the parent's
2306 * implementation to continue working without allocating their children
2307 * twice, or without entering an allocation loop.
2309 * for the first two points, we check if the class of the actor is
2310 * overridding the ::allocate() virtual function; if it isn't, then we
2311 * follow through with checking whether we have children and a layout
2312 * manager, and eventually calling clutter_layout_manager_allocate().
2314 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2315 * allocation flags that we got passed, and if it is present, we continue
2316 * with the check above.
2318 * if neither of these two checks yields a positive result, we just
2319 * assume that the ::allocate() virtual function that resulted in this
2320 * function being called will also allocate the children of the actor.
2323 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2326 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2332 if (priv->n_children != 0 &&
2333 priv->layout_manager != NULL)
2335 ClutterContainer *container = CLUTTER_CONTAINER (self);
2336 ClutterAllocationFlags children_flags;
2337 ClutterActorBox children_box;
2339 /* normalize the box passed to the layout manager */
2340 children_box.x1 = children_box.y1 = 0.f;
2341 children_box.x2 = (allocation->x2 - allocation->x1);
2342 children_box.y2 = (allocation->y2 - allocation->y1);
2344 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2345 * the actor's children, since it refers only to the current
2346 * actor's allocation.
2348 children_flags = flags;
2349 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2351 CLUTTER_NOTE (LAYOUT,
2352 "Allocating %d children of %s "
2353 "at { %.2f, %.2f - %.2f x %.2f } "
2356 _clutter_actor_get_debug_name (self),
2359 (allocation->x2 - allocation->x1),
2360 (allocation->y2 - allocation->y1),
2361 G_OBJECT_TYPE_NAME (priv->layout_manager));
2363 clutter_layout_manager_allocate (priv->layout_manager,
2371 clutter_actor_real_allocate (ClutterActor *self,
2372 const ClutterActorBox *box,
2373 ClutterAllocationFlags flags)
2375 ClutterActorPrivate *priv = self->priv;
2378 g_object_freeze_notify (G_OBJECT (self));
2380 changed = clutter_actor_set_allocation_internal (self, box, flags);
2382 /* we allocate our children before we notify changes in our geometry,
2383 * so that people connecting to properties will be able to get valid
2384 * data out of the sub-tree of the scene graph that has this actor at
2387 clutter_actor_maybe_layout_children (self, box, flags);
2391 ClutterActorBox signal_box = priv->allocation;
2392 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2394 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2399 g_object_thaw_notify (G_OBJECT (self));
2403 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2404 ClutterActor *origin)
2406 /* no point in queuing a redraw on a destroyed actor */
2407 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2410 /* NB: We can't bail out early here if the actor is hidden in case
2411 * the actor bas been cloned. In this case the clone will need to
2412 * receive the signal so it can queue its own redraw.
2415 /* calls klass->queue_redraw in default handler */
2416 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2420 clutter_actor_real_queue_redraw (ClutterActor *self,
2421 ClutterActor *origin)
2423 ClutterActor *parent;
2425 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2426 _clutter_actor_get_debug_name (self),
2427 origin != NULL ? _clutter_actor_get_debug_name (origin)
2430 /* no point in queuing a redraw on a destroyed actor */
2431 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2434 /* If the queue redraw is coming from a child then the actor has
2435 become dirty and any queued effect is no longer valid */
2438 self->priv->is_dirty = TRUE;
2439 self->priv->effect_to_redraw = NULL;
2442 /* If the actor isn't visible, we still had to emit the signal
2443 * to allow for a ClutterClone, but the appearance of the parent
2444 * won't change so we don't have to propagate up the hierarchy.
2446 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2449 /* Although we could determine here that a full stage redraw
2450 * has already been queued and immediately bail out, we actually
2451 * guarantee that we will propagate a queue-redraw signal to our
2452 * parent at least once so that it's possible to implement a
2453 * container that tracks which of its children have queued a
2456 if (self->priv->propagated_one_redraw)
2458 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2459 if (stage != NULL &&
2460 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2464 self->priv->propagated_one_redraw = TRUE;
2466 /* notify parents, if they are all visible eventually we'll
2467 * queue redraw on the stage, which queues the redraw idle.
2469 parent = clutter_actor_get_parent (self);
2472 /* this will go up recursively */
2473 _clutter_actor_signal_queue_redraw (parent, origin);
2478 clutter_actor_real_queue_relayout (ClutterActor *self)
2480 ClutterActorPrivate *priv = self->priv;
2482 /* no point in queueing a redraw on a destroyed actor */
2483 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2486 priv->needs_width_request = TRUE;
2487 priv->needs_height_request = TRUE;
2488 priv->needs_allocation = TRUE;
2490 /* reset the cached size requests */
2491 memset (priv->width_requests, 0,
2492 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2493 memset (priv->height_requests, 0,
2494 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2496 /* We need to go all the way up the hierarchy */
2497 if (priv->parent != NULL)
2498 _clutter_actor_queue_only_relayout (priv->parent);
2502 * clutter_actor_apply_relative_transform_to_point:
2503 * @self: A #ClutterActor
2504 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2505 * default #ClutterStage
2506 * @point: A point as #ClutterVertex
2507 * @vertex: (out caller-allocates): The translated #ClutterVertex
2509 * Transforms @point in coordinates relative to the actor into
2510 * ancestor-relative coordinates using the relevant transform
2511 * stack (i.e. scale, rotation, etc).
2513 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2514 * this case, the coordinates returned will be the coordinates on
2515 * the stage before the projection is applied. This is different from
2516 * the behaviour of clutter_actor_apply_transform_to_point().
2521 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2522 ClutterActor *ancestor,
2523 const ClutterVertex *point,
2524 ClutterVertex *vertex)
2529 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2530 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2531 g_return_if_fail (point != NULL);
2532 g_return_if_fail (vertex != NULL);
2537 if (ancestor == NULL)
2538 ancestor = _clutter_actor_get_stage_internal (self);
2540 if (ancestor == NULL)
2546 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2547 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2551 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2552 const ClutterVertex *vertices_in,
2553 ClutterVertex *vertices_out,
2556 ClutterActor *stage;
2557 CoglMatrix modelview;
2558 CoglMatrix projection;
2561 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2563 stage = _clutter_actor_get_stage_internal (self);
2565 /* We really can't do anything meaningful in this case so don't try
2566 * to do any transform */
2570 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2571 * that gets us to stage coordinates, we want to go all the way to eye
2573 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2575 /* Fetch the projection and viewport */
2576 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2577 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2583 _clutter_util_fully_transform_vertices (&modelview,
2594 * clutter_actor_apply_transform_to_point:
2595 * @self: A #ClutterActor
2596 * @point: A point as #ClutterVertex
2597 * @vertex: (out caller-allocates): The translated #ClutterVertex
2599 * Transforms @point in coordinates relative to the actor
2600 * into screen-relative coordinates with the current actor
2601 * transformation (i.e. scale, rotation, etc)
2606 clutter_actor_apply_transform_to_point (ClutterActor *self,
2607 const ClutterVertex *point,
2608 ClutterVertex *vertex)
2610 g_return_if_fail (point != NULL);
2611 g_return_if_fail (vertex != NULL);
2612 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2616 * _clutter_actor_get_relative_transformation_matrix:
2617 * @self: The actor whose coordinate space you want to transform from.
2618 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2619 * or %NULL if you want to transform all the way to eye coordinates.
2620 * @matrix: A #CoglMatrix to store the transformation
2622 * This gets a transformation @matrix that will transform coordinates from the
2623 * coordinate space of @self into the coordinate space of @ancestor.
2625 * For example if you need a matrix that can transform the local actor
2626 * coordinates of @self into stage coordinates you would pass the actor's stage
2627 * pointer as the @ancestor.
2629 * If you pass %NULL then the transformation will take you all the way through
2630 * to eye coordinates. This can be useful if you want to extract the entire
2631 * modelview transform that Clutter applies before applying the projection
2632 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2633 * using cogl_set_modelview_matrix() for example then you would want a matrix
2634 * that transforms into eye coordinates.
2636 * <note><para>This function explicitly initializes the given @matrix. If you just
2637 * want clutter to multiply a relative transformation with an existing matrix
2638 * you can use clutter_actor_apply_relative_transformation_matrix()
2639 * instead.</para></note>
2642 /* XXX: We should consider caching the stage relative modelview along with
2643 * the actor itself */
2645 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2646 ClutterActor *ancestor,
2649 cogl_matrix_init_identity (matrix);
2651 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2654 /* Project the given @box into stage window coordinates, writing the
2655 * transformed vertices to @verts[]. */
2657 _clutter_actor_transform_and_project_box (ClutterActor *self,
2658 const ClutterActorBox *box,
2659 ClutterVertex verts[])
2661 ClutterVertex box_vertices[4];
2663 box_vertices[0].x = box->x1;
2664 box_vertices[0].y = box->y1;
2665 box_vertices[0].z = 0;
2666 box_vertices[1].x = box->x2;
2667 box_vertices[1].y = box->y1;
2668 box_vertices[1].z = 0;
2669 box_vertices[2].x = box->x1;
2670 box_vertices[2].y = box->y2;
2671 box_vertices[2].z = 0;
2672 box_vertices[3].x = box->x2;
2673 box_vertices[3].y = box->y2;
2674 box_vertices[3].z = 0;
2677 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2681 * clutter_actor_get_allocation_vertices:
2682 * @self: A #ClutterActor
2683 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2684 * against, or %NULL to use the #ClutterStage
2685 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2686 * location for an array of 4 #ClutterVertex in which to store the result
2688 * Calculates the transformed coordinates of the four corners of the
2689 * actor in the plane of @ancestor. The returned vertices relate to
2690 * the #ClutterActorBox coordinates as follows:
2692 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2693 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2694 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2695 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2698 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2699 * this case, the coordinates returned will be the coordinates on
2700 * the stage before the projection is applied. This is different from
2701 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2706 clutter_actor_get_allocation_vertices (ClutterActor *self,
2707 ClutterActor *ancestor,
2708 ClutterVertex verts[])
2710 ClutterActorPrivate *priv;
2711 ClutterActorBox box;
2712 ClutterVertex vertices[4];
2713 CoglMatrix modelview;
2715 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2716 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2718 if (ancestor == NULL)
2719 ancestor = _clutter_actor_get_stage_internal (self);
2721 /* Fallback to a NOP transform if the actor isn't parented under a
2723 if (ancestor == NULL)
2728 /* if the actor needs to be allocated we force a relayout, so that
2729 * we will have valid values to use in the transformations */
2730 if (priv->needs_allocation)
2732 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2734 _clutter_stage_maybe_relayout (stage);
2737 box.x1 = box.y1 = 0;
2738 /* The result isn't really meaningful in this case but at
2739 * least try to do something *vaguely* reasonable... */
2740 clutter_actor_get_size (self, &box.x2, &box.y2);
2744 clutter_actor_get_allocation_box (self, &box);
2746 vertices[0].x = box.x1;
2747 vertices[0].y = box.y1;
2749 vertices[1].x = box.x2;
2750 vertices[1].y = box.y1;
2752 vertices[2].x = box.x1;
2753 vertices[2].y = box.y2;
2755 vertices[3].x = box.x2;
2756 vertices[3].y = box.y2;
2759 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2762 cogl_matrix_transform_points (&modelview,
2764 sizeof (ClutterVertex),
2766 sizeof (ClutterVertex),
2772 * clutter_actor_get_abs_allocation_vertices:
2773 * @self: A #ClutterActor
2774 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2775 * of 4 #ClutterVertex where to store the result.
2777 * Calculates the transformed screen coordinates of the four corners of
2778 * the actor; the returned vertices relate to the #ClutterActorBox
2779 * coordinates as follows:
2781 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2782 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2783 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2784 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2790 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2791 ClutterVertex verts[])
2793 ClutterActorPrivate *priv;
2794 ClutterActorBox actor_space_allocation;
2796 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2800 /* if the actor needs to be allocated we force a relayout, so that
2801 * the actor allocation box will be valid for
2802 * _clutter_actor_transform_and_project_box()
2804 if (priv->needs_allocation)
2806 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2807 /* There's nothing meaningful we can do now */
2811 _clutter_stage_maybe_relayout (stage);
2814 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2815 * own coordinate space... */
2816 actor_space_allocation.x1 = 0;
2817 actor_space_allocation.y1 = 0;
2818 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2819 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2820 _clutter_actor_transform_and_project_box (self,
2821 &actor_space_allocation,
2826 clutter_actor_real_apply_transform (ClutterActor *self,
2829 ClutterActorPrivate *priv = self->priv;
2831 if (!priv->transform_valid)
2833 CoglMatrix *transform = &priv->transform;
2834 const ClutterTransformInfo *info;
2836 info = _clutter_actor_get_transform_info_or_defaults (self);
2838 cogl_matrix_init_identity (transform);
2840 cogl_matrix_translate (transform,
2841 priv->allocation.x1,
2842 priv->allocation.y1,
2846 cogl_matrix_translate (transform, 0, 0, info->depth);
2849 * because the rotation involves translations, we must scale
2850 * before applying the rotations (if we apply the scale after
2851 * the rotations, the translations included in the rotation are
2852 * not scaled and so the entire object will move on the screen
2853 * as a result of rotating it).
2855 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2857 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2858 &info->scale_center,
2859 cogl_matrix_scale (transform,
2866 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2868 cogl_matrix_rotate (transform,
2873 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2875 cogl_matrix_rotate (transform,
2880 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2882 cogl_matrix_rotate (transform,
2886 if (!clutter_anchor_coord_is_zero (&info->anchor))
2890 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2891 cogl_matrix_translate (transform, -x, -y, -z);
2894 priv->transform_valid = TRUE;
2897 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2900 /* Applies the transforms associated with this actor to the given
2903 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2906 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2910 * clutter_actor_apply_relative_transformation_matrix:
2911 * @self: The actor whose coordinate space you want to transform from.
2912 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2913 * or %NULL if you want to transform all the way to eye coordinates.
2914 * @matrix: A #CoglMatrix to apply the transformation too.
2916 * This multiplies a transform with @matrix that will transform coordinates
2917 * from the coordinate space of @self into the coordinate space of @ancestor.
2919 * For example if you need a matrix that can transform the local actor
2920 * coordinates of @self into stage coordinates you would pass the actor's stage
2921 * pointer as the @ancestor.
2923 * If you pass %NULL then the transformation will take you all the way through
2924 * to eye coordinates. This can be useful if you want to extract the entire
2925 * modelview transform that Clutter applies before applying the projection
2926 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2927 * using cogl_set_modelview_matrix() for example then you would want a matrix
2928 * that transforms into eye coordinates.
2930 * <note>This function doesn't initialize the given @matrix, it simply
2931 * multiplies the requested transformation matrix with the existing contents of
2932 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2933 * before calling this function, or you can use
2934 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2937 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2938 ClutterActor *ancestor,
2941 ClutterActor *parent;
2943 /* Note we terminate before ever calling stage->apply_transform()
2944 * since that would conceptually be relative to the underlying
2945 * window OpenGL coordinates so we'd need a special @ancestor
2946 * value to represent the fake parent of the stage. */
2947 if (self == ancestor)
2950 parent = clutter_actor_get_parent (self);
2953 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2956 _clutter_actor_apply_modelview_transform (self, matrix);
2960 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2961 ClutterPaintVolume *pv,
2963 const CoglColor *color)
2965 static CoglPipeline *outline = NULL;
2966 CoglPrimitive *prim;
2967 ClutterVertex line_ends[12 * 2];
2970 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2971 /* XXX: at some point we'll query this from the stage but we can't
2972 * do that until the osx backend uses Cogl natively. */
2973 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2975 if (outline == NULL)
2976 outline = cogl_pipeline_new (ctx);
2978 _clutter_paint_volume_complete (pv);
2980 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2983 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2984 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2985 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2986 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2991 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2992 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2993 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2994 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2996 /* Lines connecting front face to back face */
2997 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2998 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2999 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3000 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3003 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3005 (CoglVertexP3 *)line_ends);
3007 cogl_pipeline_set_color (outline, color);
3008 cogl_framebuffer_draw_primitive (fb, outline, prim);
3009 cogl_object_unref (prim);
3013 PangoLayout *layout;
3014 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3015 pango_layout_set_text (layout, label, -1);
3016 cogl_pango_render_layout (layout,
3021 g_object_unref (layout);
3026 _clutter_actor_draw_paint_volume (ClutterActor *self)
3028 ClutterPaintVolume *pv;
3031 pv = _clutter_actor_get_paint_volume_mutable (self);
3034 gfloat width, height;
3035 ClutterPaintVolume fake_pv;
3037 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3038 _clutter_paint_volume_init_static (&fake_pv, stage);
3040 clutter_actor_get_size (self, &width, &height);
3041 clutter_paint_volume_set_width (&fake_pv, width);
3042 clutter_paint_volume_set_height (&fake_pv, height);
3044 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3045 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3046 _clutter_actor_get_debug_name (self),
3049 clutter_paint_volume_free (&fake_pv);
3053 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3054 _clutter_actor_draw_paint_volume_full (self, pv,
3055 _clutter_actor_get_debug_name (self),
3061 _clutter_actor_paint_cull_result (ClutterActor *self,
3063 ClutterCullResult result)
3065 ClutterPaintVolume *pv;
3070 if (result == CLUTTER_CULL_RESULT_IN)
3071 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3072 else if (result == CLUTTER_CULL_RESULT_OUT)
3073 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3075 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3078 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3080 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3081 _clutter_actor_draw_paint_volume_full (self, pv,
3082 _clutter_actor_get_debug_name (self),
3086 PangoLayout *layout;
3088 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3089 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3090 cogl_set_source_color (&color);
3092 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3093 pango_layout_set_text (layout, label, -1);
3094 cogl_pango_render_layout (layout,
3100 g_object_unref (layout);
3104 static int clone_paint_level = 0;
3107 _clutter_actor_push_clone_paint (void)
3109 clone_paint_level++;
3113 _clutter_actor_pop_clone_paint (void)
3115 clone_paint_level--;
3119 in_clone_paint (void)
3121 return clone_paint_level > 0;
3124 /* Returns TRUE if the actor can be ignored */
3125 /* FIXME: we should return a ClutterCullResult, and
3126 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3127 * means there's no point in trying to cull descendants of the current
3130 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3132 ClutterActorPrivate *priv = self->priv;
3133 ClutterActor *stage;
3134 const ClutterPlane *stage_clip;
3136 if (!priv->last_paint_volume_valid)
3138 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3139 "->last_paint_volume_valid == FALSE",
3140 _clutter_actor_get_debug_name (self));
3144 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3147 stage = _clutter_actor_get_stage_internal (self);
3148 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3149 if (G_UNLIKELY (!stage_clip))
3151 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3152 "No stage clip set",
3153 _clutter_actor_get_debug_name (self));
3157 if (cogl_get_draw_framebuffer () !=
3158 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3160 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3161 "Current framebuffer doesn't correspond to stage",
3162 _clutter_actor_get_debug_name (self));
3167 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3172 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3174 ClutterActorPrivate *priv = self->priv;
3175 const ClutterPaintVolume *pv;
3177 if (priv->last_paint_volume_valid)
3179 clutter_paint_volume_free (&priv->last_paint_volume);
3180 priv->last_paint_volume_valid = FALSE;
3183 pv = clutter_actor_get_paint_volume (self);
3186 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3187 "Actor failed to report a paint volume",
3188 _clutter_actor_get_debug_name (self));
3192 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3194 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3195 NULL); /* eye coordinates */
3197 priv->last_paint_volume_valid = TRUE;
3200 static inline gboolean
3201 actor_has_shader_data (ClutterActor *self)
3203 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3207 _clutter_actor_get_pick_id (ClutterActor *self)
3209 if (self->priv->pick_id < 0)
3212 return self->priv->pick_id;
3215 /* This is the same as clutter_actor_add_effect except that it doesn't
3216 queue a redraw and it doesn't notify on the effect property */
3218 _clutter_actor_add_effect_internal (ClutterActor *self,
3219 ClutterEffect *effect)
3221 ClutterActorPrivate *priv = self->priv;
3223 if (priv->effects == NULL)
3225 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3226 priv->effects->actor = self;
3229 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3232 /* This is the same as clutter_actor_remove_effect except that it doesn't
3233 queue a redraw and it doesn't notify on the effect property */
3235 _clutter_actor_remove_effect_internal (ClutterActor *self,
3236 ClutterEffect *effect)
3238 ClutterActorPrivate *priv = self->priv;
3240 if (priv->effects == NULL)
3243 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3247 needs_flatten_effect (ClutterActor *self)
3249 ClutterActorPrivate *priv = self->priv;
3251 if (G_UNLIKELY (clutter_paint_debug_flags &
3252 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3255 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3257 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3259 if (clutter_actor_get_paint_opacity (self) < 255 &&
3260 clutter_actor_has_overlaps (self))
3268 add_or_remove_flatten_effect (ClutterActor *self)
3270 ClutterActorPrivate *priv = self->priv;
3272 /* Add or remove the flatten effect depending on the
3273 offscreen-redirect property. */
3274 if (needs_flatten_effect (self))
3276 if (priv->flatten_effect == NULL)
3278 ClutterActorMeta *actor_meta;
3281 priv->flatten_effect = _clutter_flatten_effect_new ();
3282 /* Keep a reference to the effect so that we can queue
3284 g_object_ref_sink (priv->flatten_effect);
3286 /* Set the priority of the effect to high so that it will
3287 always be applied to the actor first. It uses an internal
3288 priority so that it won't be visible to applications */
3289 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3290 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3291 _clutter_actor_meta_set_priority (actor_meta, priority);
3293 /* This will add the effect without queueing a redraw */
3294 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3299 if (priv->flatten_effect != NULL)
3301 /* Destroy the effect so that it will lose its fbo cache of
3303 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3304 g_clear_object (&priv->flatten_effect);
3310 clutter_actor_real_paint (ClutterActor *actor)
3312 ClutterActorPrivate *priv = actor->priv;
3315 for (iter = priv->first_child;
3317 iter = iter->priv->next_sibling)
3319 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3320 _clutter_actor_get_debug_name (iter),
3321 _clutter_actor_get_debug_name (actor),
3322 iter->priv->allocation.x1,
3323 iter->priv->allocation.y1,
3324 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3325 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3327 clutter_actor_paint (iter);
3332 clutter_actor_paint_node (ClutterActor *actor,
3333 ClutterPaintNode *root)
3335 ClutterActorPrivate *priv = actor->priv;
3340 if (priv->bg_color_set &&
3341 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3343 ClutterPaintNode *node;
3344 ClutterColor bg_color;
3345 ClutterActorBox box;
3349 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3350 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3352 bg_color = priv->bg_color;
3353 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3354 * priv->bg_color.alpha
3357 node = clutter_color_node_new (&bg_color);
3358 clutter_paint_node_set_name (node, "backgroundColor");
3359 clutter_paint_node_add_rectangle (node, &box);
3360 clutter_paint_node_add_child (root, node);
3361 clutter_paint_node_unref (node);
3364 if (priv->content != NULL)
3365 _clutter_content_paint_content (priv->content, actor, root);
3367 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3368 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3370 if (clutter_paint_node_get_n_children (root) == 0)
3373 #ifdef CLUTTER_ENABLE_DEBUG
3374 if (CLUTTER_HAS_DEBUG (PAINT))
3376 /* dump the tree only if we have one */
3377 _clutter_paint_node_dump_tree (root);
3379 #endif /* CLUTTER_ENABLE_DEBUG */
3381 _clutter_paint_node_paint (root);
3384 /* XXX: Uncomment this when we disable emitting the paint signal */
3385 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3392 * clutter_actor_paint:
3393 * @self: A #ClutterActor
3395 * Renders the actor to display.
3397 * This function should not be called directly by applications.
3398 * Call clutter_actor_queue_redraw() to queue paints, instead.
3400 * This function is context-aware, and will either cause a
3401 * regular paint or a pick paint.
3403 * This function will emit the #ClutterActor::paint signal or
3404 * the #ClutterActor::pick signal, depending on the context.
3406 * This function does not paint the actor if the actor is set to 0,
3407 * unless it is performing a pick paint.
3410 clutter_actor_paint (ClutterActor *self)
3412 ClutterActorPrivate *priv;
3413 ClutterPickMode pick_mode;
3414 gboolean clip_set = FALSE;
3415 gboolean shader_applied = FALSE;
3417 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3418 "Actor real-paint counter",
3419 "Increments each time any actor is painted",
3420 0 /* no application private data */);
3421 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3422 "Actor pick-paint counter",
3423 "Increments each time any actor is painted "
3425 0 /* no application private data */);
3427 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3429 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3434 pick_mode = _clutter_context_get_pick_mode ();
3436 if (pick_mode == CLUTTER_PICK_NONE)
3437 priv->propagated_one_redraw = FALSE;
3439 /* It's an important optimization that we consider painting of
3440 * actors with 0 opacity to be a NOP... */
3441 if (pick_mode == CLUTTER_PICK_NONE &&
3442 /* ignore top-levels, since they might be transparent */
3443 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3444 /* Use the override opacity if its been set */
3445 ((priv->opacity_override >= 0) ?
3446 priv->opacity_override : priv->opacity) == 0)
3449 /* if we aren't paintable (not in a toplevel with all
3450 * parents paintable) then do nothing.
3452 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3455 /* mark that we are in the paint process */
3456 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3460 if (priv->enable_model_view_transform)
3464 /* XXX: It could be better to cache the modelview with the actor
3465 * instead of progressively building up the transformations on
3466 * the matrix stack every time we paint. */
3467 cogl_get_modelview_matrix (&matrix);
3468 _clutter_actor_apply_modelview_transform (self, &matrix);
3470 #ifdef CLUTTER_ENABLE_DEBUG
3471 /* Catch when out-of-band transforms have been made by actors not as part
3472 * of an apply_transform vfunc... */
3473 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3475 CoglMatrix expected_matrix;
3477 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3480 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3482 GString *buf = g_string_sized_new (1024);
3483 ClutterActor *parent;
3486 while (parent != NULL)
3488 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3490 if (parent->priv->parent != NULL)
3491 g_string_append (buf, "->");
3493 parent = parent->priv->parent;
3496 g_warning ("Unexpected transform found when painting actor "
3497 "\"%s\". This will be caused by one of the actor's "
3498 "ancestors (%s) using the Cogl API directly to transform "
3499 "children instead of using ::apply_transform().",
3500 _clutter_actor_get_debug_name (self),
3503 g_string_free (buf, TRUE);
3506 #endif /* CLUTTER_ENABLE_DEBUG */
3508 cogl_set_modelview_matrix (&matrix);
3513 cogl_clip_push_rectangle (priv->clip.x,
3515 priv->clip.x + priv->clip.width,
3516 priv->clip.y + priv->clip.height);
3519 else if (priv->clip_to_allocation)
3521 gfloat width, height;
3523 width = priv->allocation.x2 - priv->allocation.x1;
3524 height = priv->allocation.y2 - priv->allocation.y1;
3526 cogl_clip_push_rectangle (0, 0, width, height);
3530 if (pick_mode == CLUTTER_PICK_NONE)
3532 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3534 /* We check whether we need to add the flatten effect before
3535 each paint so that we can avoid having a mechanism for
3536 applications to notify when the value of the
3537 has_overlaps virtual changes. */
3538 add_or_remove_flatten_effect (self);
3541 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3543 /* We save the current paint volume so that the next time the
3544 * actor queues a redraw we can constrain the redraw to just
3545 * cover the union of the new bounding box and the old.
3547 * We also fetch the current paint volume to perform culling so
3548 * we can avoid painting actors outside the current clip region.
3550 * If we are painting inside a clone, we should neither update
3551 * the paint volume or use it to cull painting, since the paint
3552 * box represents the location of the source actor on the
3555 * XXX: We are starting to do a lot of vertex transforms on
3556 * the CPU in a typical paint, so at some point we should
3557 * audit these and consider caching some things.
3559 * NB: We don't perform culling while picking at this point because
3560 * clutter-stage.c doesn't setup the clipping planes appropriately.
3562 * NB: We don't want to update the last-paint-volume during picking
3563 * because the last-paint-volume is used to determine the old screen
3564 * space location of an actor that has moved so we can know the
3565 * minimal region to redraw to clear an old view of the actor. If we
3566 * update this during picking then by the time we come around to
3567 * paint then the last-paint-volume would likely represent the new
3568 * actor position not the old.
3570 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3573 /* annoyingly gcc warns if uninitialized even though
3574 * the initialization is redundant :-( */
3575 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3577 if (G_LIKELY ((clutter_paint_debug_flags &
3578 (CLUTTER_DEBUG_DISABLE_CULLING |
3579 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3580 (CLUTTER_DEBUG_DISABLE_CULLING |
3581 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3582 _clutter_actor_update_last_paint_volume (self);
3584 success = cull_actor (self, &result);
3586 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3587 _clutter_actor_paint_cull_result (self, success, result);
3588 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3592 if (priv->effects == NULL)
3594 if (pick_mode == CLUTTER_PICK_NONE &&
3595 actor_has_shader_data (self))
3597 _clutter_actor_shader_pre_paint (self, FALSE);
3598 shader_applied = TRUE;
3601 priv->next_effect_to_paint = NULL;
3604 priv->next_effect_to_paint =
3605 _clutter_meta_group_peek_metas (priv->effects);
3607 clutter_actor_continue_paint (self);
3610 _clutter_actor_shader_post_paint (self);
3612 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3613 pick_mode == CLUTTER_PICK_NONE))
3614 _clutter_actor_draw_paint_volume (self);
3617 /* If we make it here then the actor has run through a complete
3618 paint run including all the effects so it's no longer dirty */
3619 if (pick_mode == CLUTTER_PICK_NONE)
3620 priv->is_dirty = FALSE;
3627 /* paint sequence complete */
3628 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3632 * clutter_actor_continue_paint:
3633 * @self: A #ClutterActor
3635 * Run the next stage of the paint sequence. This function should only
3636 * be called within the implementation of the ‘run’ virtual of a
3637 * #ClutterEffect. It will cause the run method of the next effect to
3638 * be applied, or it will paint the actual actor if the current effect
3639 * is the last effect in the chain.
3644 clutter_actor_continue_paint (ClutterActor *self)
3646 ClutterActorPrivate *priv;
3648 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3649 /* This should only be called from with in the ‘run’ implementation
3650 of a ClutterEffect */
3651 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3655 /* Skip any effects that are disabled */
3656 while (priv->next_effect_to_paint &&
3657 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3658 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3660 /* If this has come from the last effect then we'll just paint the
3662 if (priv->next_effect_to_paint == NULL)
3664 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3666 ClutterPaintNode *dummy;
3668 /* XXX - this will go away in 2.0, when we can get rid of this
3669 * stuff and switch to a pure retained render tree of PaintNodes
3670 * for the entire frame, starting from the Stage; the paint()
3671 * virtual function can then be called directly.
3673 dummy = _clutter_dummy_node_new (self);
3674 clutter_paint_node_set_name (dummy, "Root");
3676 /* XXX - for 1.12, we use the return value of paint_node() to
3677 * decide whether we should emit the ::paint signal.
3679 clutter_actor_paint_node (self, dummy);
3680 clutter_paint_node_unref (dummy);
3682 g_signal_emit (self, actor_signals[PAINT], 0);
3686 ClutterColor col = { 0, };
3688 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3690 /* Actor will then paint silhouette of itself in supplied
3691 * color. See clutter_stage_get_actor_at_pos() for where
3692 * picking is enabled.
3694 g_signal_emit (self, actor_signals[PICK], 0, &col);
3699 ClutterEffect *old_current_effect;
3700 ClutterEffectPaintFlags run_flags = 0;
3702 /* Cache the current effect so that we can put it back before
3704 old_current_effect = priv->current_effect;
3706 priv->current_effect = priv->next_effect_to_paint->data;
3707 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3709 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3713 /* If there's an effect queued with this redraw then all
3714 effects up to that one will be considered dirty. It
3715 is expected the queued effect will paint the cached
3716 image and not call clutter_actor_continue_paint again
3717 (although it should work ok if it does) */
3718 if (priv->effect_to_redraw == NULL ||
3719 priv->current_effect != priv->effect_to_redraw)
3720 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3723 _clutter_effect_paint (priv->current_effect, run_flags);
3727 /* We can't determine when an actor has been modified since
3728 its last pick so lets just assume it has always been
3730 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3732 _clutter_effect_pick (priv->current_effect, run_flags);
3735 priv->current_effect = old_current_effect;
3739 static ClutterActorTraverseVisitFlags
3740 invalidate_queue_redraw_entry (ClutterActor *self,
3744 ClutterActorPrivate *priv = self->priv;
3746 if (priv->queue_redraw_entry != NULL)
3748 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3749 priv->queue_redraw_entry = NULL;
3752 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3756 remove_child (ClutterActor *self,
3757 ClutterActor *child)
3759 ClutterActor *prev_sibling, *next_sibling;
3761 prev_sibling = child->priv->prev_sibling;
3762 next_sibling = child->priv->next_sibling;
3764 if (prev_sibling != NULL)
3765 prev_sibling->priv->next_sibling = next_sibling;
3767 if (next_sibling != NULL)
3768 next_sibling->priv->prev_sibling = prev_sibling;
3770 if (self->priv->first_child == child)
3771 self->priv->first_child = next_sibling;
3773 if (self->priv->last_child == child)
3774 self->priv->last_child = prev_sibling;
3776 child->priv->parent = NULL;
3777 child->priv->prev_sibling = NULL;
3778 child->priv->next_sibling = NULL;
3782 REMOVE_CHILD_DESTROY_META = 1 << 0,
3783 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3784 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3785 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3786 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3787 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3789 /* default flags for public API */
3790 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3791 REMOVE_CHILD_EMIT_PARENT_SET |
3792 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3793 REMOVE_CHILD_CHECK_STATE |
3794 REMOVE_CHILD_FLUSH_QUEUE |
3795 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3797 /* flags for legacy/deprecated API */
3798 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3799 REMOVE_CHILD_FLUSH_QUEUE |
3800 REMOVE_CHILD_EMIT_PARENT_SET |
3801 REMOVE_CHILD_NOTIFY_FIRST_LAST
3802 } ClutterActorRemoveChildFlags;
3805 * clutter_actor_remove_child_internal:
3806 * @self: a #ClutterActor
3807 * @child: the child of @self that has to be removed
3808 * @flags: control the removal operations
3810 * Removes @child from the list of children of @self.
3813 clutter_actor_remove_child_internal (ClutterActor *self,
3814 ClutterActor *child,
3815 ClutterActorRemoveChildFlags flags)
3817 ClutterActor *old_first, *old_last;
3818 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3819 gboolean flush_queue;
3820 gboolean notify_first_last;
3821 gboolean was_mapped;
3823 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3824 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3825 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3826 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3827 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3828 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3830 g_object_freeze_notify (G_OBJECT (self));
3833 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3837 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3839 /* we need to unrealize *before* we set parent_actor to NULL,
3840 * because in an unrealize method actors are dissociating from the
3841 * stage, which means they need to be able to
3842 * clutter_actor_get_stage().
3844 * yhis should unmap and unrealize, unless we're reparenting.
3846 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3853 /* We take this opportunity to invalidate any queue redraw entry
3854 * associated with the actor and descendants since we won't be able to
3855 * determine the appropriate stage after this.
3857 * we do this after we updated the mapped state because actors might
3858 * end up queueing redraws inside their mapped/unmapped virtual
3859 * functions, and if we invalidate the redraw entry we could end up
3860 * with an inconsistent state and weird memory corruption. see
3863 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3864 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3866 _clutter_actor_traverse (child,
3868 invalidate_queue_redraw_entry,
3873 old_first = self->priv->first_child;
3874 old_last = self->priv->last_child;
3876 remove_child (self, child);
3878 self->priv->n_children -= 1;
3880 self->priv->age += 1;
3882 /* clutter_actor_reparent() will emit ::parent-set for us */
3883 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3884 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3886 /* if the child was mapped then we need to relayout ourselves to account
3887 * for the removed child
3890 clutter_actor_queue_relayout (self);
3892 /* we need to emit the signal before dropping the reference */
3893 if (emit_actor_removed)
3894 g_signal_emit_by_name (self, "actor-removed", child);
3896 if (notify_first_last)
3898 if (old_first != self->priv->first_child)
3899 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3901 if (old_last != self->priv->last_child)
3902 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3905 g_object_thaw_notify (G_OBJECT (self));
3907 /* remove the reference we acquired in clutter_actor_add_child() */
3908 g_object_unref (child);
3911 static const ClutterTransformInfo default_transform_info = {
3912 0.0, { 0, }, /* rotation-x */
3913 0.0, { 0, }, /* rotation-y */
3914 0.0, { 0, }, /* rotation-z */
3916 1.0, 1.0, { 0, }, /* scale */
3918 { 0, }, /* anchor */
3924 * _clutter_actor_get_transform_info_or_defaults:
3925 * @self: a #ClutterActor
3927 * Retrieves the ClutterTransformInfo structure associated to an actor.
3929 * If the actor does not have a ClutterTransformInfo structure associated
3930 * to it, then the default structure will be returned.
3932 * This function should only be used for getters.
3934 * Return value: a const pointer to the ClutterTransformInfo structure
3936 const ClutterTransformInfo *
3937 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3939 ClutterTransformInfo *info;
3941 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3945 return &default_transform_info;
3949 clutter_transform_info_free (gpointer data)
3952 g_slice_free (ClutterTransformInfo, data);
3956 * _clutter_actor_get_transform_info:
3957 * @self: a #ClutterActor
3959 * Retrieves a pointer to the ClutterTransformInfo structure.
3961 * If the actor does not have a ClutterTransformInfo associated to it, one
3962 * will be created and initialized to the default values.
3964 * This function should be used for setters.
3966 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3969 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3972 ClutterTransformInfo *
3973 _clutter_actor_get_transform_info (ClutterActor *self)
3975 ClutterTransformInfo *info;
3977 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3980 info = g_slice_new (ClutterTransformInfo);
3982 *info = default_transform_info;
3984 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3986 clutter_transform_info_free);
3993 * clutter_actor_set_rotation_angle_internal:
3994 * @self: a #ClutterActor
3995 * @axis: the axis of the angle to change
3996 * @angle: the angle of rotation
3998 * Sets the rotation angle on the given axis without affecting the
3999 * rotation center point.
4002 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
4003 ClutterRotateAxis axis,
4006 GObject *obj = G_OBJECT (self);
4007 ClutterTransformInfo *info;
4009 info = _clutter_actor_get_transform_info (self);
4011 g_object_freeze_notify (obj);
4015 case CLUTTER_X_AXIS:
4016 info->rx_angle = angle;
4017 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4020 case CLUTTER_Y_AXIS:
4021 info->ry_angle = angle;
4022 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4025 case CLUTTER_Z_AXIS:
4026 info->rz_angle = angle;
4027 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4031 self->priv->transform_valid = FALSE;
4033 g_object_thaw_notify (obj);
4035 clutter_actor_queue_redraw (self);
4039 clutter_actor_set_rotation_angle (ClutterActor *self,
4040 ClutterRotateAxis axis,
4043 const ClutterTransformInfo *info;
4044 const double *cur_angle_p = NULL;
4045 GParamSpec *pspec = NULL;
4047 info = _clutter_actor_get_transform_info_or_defaults (self);
4051 case CLUTTER_X_AXIS:
4052 cur_angle_p = &info->rx_angle;
4053 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4056 case CLUTTER_Y_AXIS:
4057 cur_angle_p = &info->ry_angle;
4058 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4061 case CLUTTER_Z_AXIS:
4062 cur_angle_p = &info->rz_angle;
4063 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4067 g_assert (pspec != NULL);
4068 g_assert (cur_angle_p != NULL);
4070 if (_clutter_actor_get_transition (self, pspec) == NULL)
4071 _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4073 _clutter_actor_update_transition (self, pspec, angle);
4075 clutter_actor_queue_redraw (self);
4079 * clutter_actor_set_rotation_center_internal:
4080 * @self: a #ClutterActor
4081 * @axis: the axis of the center to change
4082 * @center: the coordinates of the rotation center
4084 * Sets the rotation center on the given axis without affecting the
4088 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4089 ClutterRotateAxis axis,
4090 const ClutterVertex *center)
4092 GObject *obj = G_OBJECT (self);
4093 ClutterTransformInfo *info;
4094 ClutterVertex v = { 0, 0, 0 };
4096 info = _clutter_actor_get_transform_info (self);
4101 g_object_freeze_notify (obj);
4105 case CLUTTER_X_AXIS:
4106 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4107 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4110 case CLUTTER_Y_AXIS:
4111 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4112 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4115 case CLUTTER_Z_AXIS:
4116 /* if the previously set rotation center was fractional, then
4117 * setting explicit coordinates will have to notify the
4118 * :rotation-center-z-gravity property as well
4120 if (info->rz_center.is_fractional)
4121 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4123 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4124 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4128 self->priv->transform_valid = FALSE;
4130 g_object_thaw_notify (obj);
4132 clutter_actor_queue_redraw (self);
4136 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4140 GObject *obj = G_OBJECT (self);
4141 ClutterTransformInfo *info;
4143 info = _clutter_actor_get_transform_info (self);
4145 if (pspec == obj_props[PROP_SCALE_X])
4146 info->scale_x = factor;
4148 info->scale_y = factor;
4150 self->priv->transform_valid = FALSE;
4151 clutter_actor_queue_redraw (self);
4152 g_object_notify_by_pspec (obj, pspec);
4156 clutter_actor_set_scale_factor (ClutterActor *self,
4157 ClutterRotateAxis axis,
4160 const ClutterTransformInfo *info;
4161 const double *scale_p = NULL;
4162 GParamSpec *pspec = NULL;
4164 info = _clutter_actor_get_transform_info_or_defaults (self);
4168 case CLUTTER_X_AXIS:
4169 pspec = obj_props[PROP_SCALE_X];
4170 scale_p = &info->scale_x;
4173 case CLUTTER_Y_AXIS:
4174 pspec = obj_props[PROP_SCALE_Y];
4175 scale_p = &info->scale_y;
4178 case CLUTTER_Z_AXIS:
4182 g_assert (pspec != NULL);
4183 g_assert (scale_p != NULL);
4185 if (_clutter_actor_get_transition (self, pspec) == NULL)
4186 _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4188 _clutter_actor_update_transition (self, pspec, factor);
4190 clutter_actor_queue_redraw (self);
4194 clutter_actor_set_scale_center (ClutterActor *self,
4195 ClutterRotateAxis axis,
4198 GObject *obj = G_OBJECT (self);
4199 ClutterTransformInfo *info;
4200 gfloat center_x, center_y;
4202 info = _clutter_actor_get_transform_info (self);
4204 g_object_freeze_notify (obj);
4206 /* get the current scale center coordinates */
4207 clutter_anchor_coord_get_units (self, &info->scale_center,
4212 /* we need to notify this too, because setting explicit coordinates will
4213 * change the gravity as a side effect
4215 if (info->scale_center.is_fractional)
4216 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4220 case CLUTTER_X_AXIS:
4221 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4222 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4225 case CLUTTER_Y_AXIS:
4226 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4227 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4231 g_assert_not_reached ();
4234 self->priv->transform_valid = FALSE;
4236 clutter_actor_queue_redraw (self);
4238 g_object_thaw_notify (obj);
4242 clutter_actor_set_scale_gravity (ClutterActor *self,
4243 ClutterGravity gravity)
4245 ClutterTransformInfo *info;
4248 info = _clutter_actor_get_transform_info (self);
4249 obj = G_OBJECT (self);
4251 if (gravity == CLUTTER_GRAVITY_NONE)
4252 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4254 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4256 self->priv->transform_valid = FALSE;
4258 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4259 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4260 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4262 clutter_actor_queue_redraw (self);
4266 clutter_actor_set_anchor_coord (ClutterActor *self,
4267 ClutterRotateAxis axis,
4270 GObject *obj = G_OBJECT (self);
4271 ClutterTransformInfo *info;
4272 gfloat anchor_x, anchor_y;
4274 info = _clutter_actor_get_transform_info (self);
4276 g_object_freeze_notify (obj);
4278 clutter_anchor_coord_get_units (self, &info->anchor,
4283 if (info->anchor.is_fractional)
4284 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4288 case CLUTTER_X_AXIS:
4289 clutter_anchor_coord_set_units (&info->anchor,
4293 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4296 case CLUTTER_Y_AXIS:
4297 clutter_anchor_coord_set_units (&info->anchor,
4301 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4305 g_assert_not_reached ();
4308 self->priv->transform_valid = FALSE;
4310 clutter_actor_queue_redraw (self);
4312 g_object_thaw_notify (obj);
4316 clutter_actor_set_property (GObject *object,
4318 const GValue *value,
4321 ClutterActor *actor = CLUTTER_ACTOR (object);
4322 ClutterActorPrivate *priv = actor->priv;
4327 clutter_actor_set_x (actor, g_value_get_float (value));
4331 clutter_actor_set_y (actor, g_value_get_float (value));
4335 clutter_actor_set_width (actor, g_value_get_float (value));
4339 clutter_actor_set_height (actor, g_value_get_float (value));
4343 clutter_actor_set_x (actor, g_value_get_float (value));
4347 clutter_actor_set_y (actor, g_value_get_float (value));
4350 case PROP_FIXED_POSITION_SET:
4351 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4354 case PROP_MIN_WIDTH:
4355 clutter_actor_set_min_width (actor, g_value_get_float (value));
4358 case PROP_MIN_HEIGHT:
4359 clutter_actor_set_min_height (actor, g_value_get_float (value));
4362 case PROP_NATURAL_WIDTH:
4363 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4366 case PROP_NATURAL_HEIGHT:
4367 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4370 case PROP_MIN_WIDTH_SET:
4371 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4374 case PROP_MIN_HEIGHT_SET:
4375 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4378 case PROP_NATURAL_WIDTH_SET:
4379 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4382 case PROP_NATURAL_HEIGHT_SET:
4383 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4386 case PROP_REQUEST_MODE:
4387 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4391 clutter_actor_set_depth (actor, g_value_get_float (value));
4395 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4398 case PROP_OFFSCREEN_REDIRECT:
4399 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4403 clutter_actor_set_name (actor, g_value_get_string (value));
4407 if (g_value_get_boolean (value) == TRUE)
4408 clutter_actor_show (actor);
4410 clutter_actor_hide (actor);
4414 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4415 g_value_get_double (value));
4419 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4420 g_value_get_double (value));
4423 case PROP_SCALE_CENTER_X:
4424 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4425 g_value_get_float (value));
4428 case PROP_SCALE_CENTER_Y:
4429 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4430 g_value_get_float (value));
4433 case PROP_SCALE_GRAVITY:
4434 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4439 const ClutterGeometry *geom = g_value_get_boxed (value);
4441 clutter_actor_set_clip (actor,
4443 geom->width, geom->height);
4447 case PROP_CLIP_TO_ALLOCATION:
4448 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4452 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4455 case PROP_ROTATION_ANGLE_X:
4456 clutter_actor_set_rotation_angle (actor,
4458 g_value_get_double (value));
4461 case PROP_ROTATION_ANGLE_Y:
4462 clutter_actor_set_rotation_angle (actor,
4464 g_value_get_double (value));
4467 case PROP_ROTATION_ANGLE_Z:
4468 clutter_actor_set_rotation_angle (actor,
4470 g_value_get_double (value));
4473 case PROP_ROTATION_CENTER_X:
4474 clutter_actor_set_rotation_center_internal (actor,
4476 g_value_get_boxed (value));
4479 case PROP_ROTATION_CENTER_Y:
4480 clutter_actor_set_rotation_center_internal (actor,
4482 g_value_get_boxed (value));
4485 case PROP_ROTATION_CENTER_Z:
4486 clutter_actor_set_rotation_center_internal (actor,
4488 g_value_get_boxed (value));
4491 case PROP_ROTATION_CENTER_Z_GRAVITY:
4493 const ClutterTransformInfo *info;
4495 info = _clutter_actor_get_transform_info_or_defaults (actor);
4496 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4497 g_value_get_enum (value));
4502 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4503 g_value_get_float (value));
4507 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4508 g_value_get_float (value));
4511 case PROP_ANCHOR_GRAVITY:
4512 clutter_actor_set_anchor_point_from_gravity (actor,
4513 g_value_get_enum (value));
4516 case PROP_SHOW_ON_SET_PARENT:
4517 priv->show_on_set_parent = g_value_get_boolean (value);
4520 case PROP_TEXT_DIRECTION:
4521 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4525 clutter_actor_add_action (actor, g_value_get_object (value));
4528 case PROP_CONSTRAINTS:
4529 clutter_actor_add_constraint (actor, g_value_get_object (value));
4533 clutter_actor_add_effect (actor, g_value_get_object (value));
4536 case PROP_LAYOUT_MANAGER:
4537 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4541 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4545 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4548 case PROP_MARGIN_TOP:
4549 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4552 case PROP_MARGIN_BOTTOM:
4553 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4556 case PROP_MARGIN_LEFT:
4557 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4560 case PROP_MARGIN_RIGHT:
4561 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4564 case PROP_BACKGROUND_COLOR:
4565 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4569 clutter_actor_set_content (actor, g_value_get_object (value));
4572 case PROP_CONTENT_GRAVITY:
4573 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4576 case PROP_MINIFICATION_FILTER:
4577 clutter_actor_set_content_scaling_filters (actor,
4578 g_value_get_enum (value),
4579 actor->priv->mag_filter);
4582 case PROP_MAGNIFICATION_FILTER:
4583 clutter_actor_set_content_scaling_filters (actor,
4584 actor->priv->min_filter,
4585 g_value_get_enum (value));
4589 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4595 clutter_actor_get_property (GObject *object,
4600 ClutterActor *actor = CLUTTER_ACTOR (object);
4601 ClutterActorPrivate *priv = actor->priv;
4606 g_value_set_float (value, clutter_actor_get_x (actor));
4610 g_value_set_float (value, clutter_actor_get_y (actor));
4614 g_value_set_float (value, clutter_actor_get_width (actor));
4618 g_value_set_float (value, clutter_actor_get_height (actor));
4623 const ClutterLayoutInfo *info;
4625 info = _clutter_actor_get_layout_info_or_defaults (actor);
4626 g_value_set_float (value, info->fixed_x);
4632 const ClutterLayoutInfo *info;
4634 info = _clutter_actor_get_layout_info_or_defaults (actor);
4635 g_value_set_float (value, info->fixed_y);
4639 case PROP_FIXED_POSITION_SET:
4640 g_value_set_boolean (value, priv->position_set);
4643 case PROP_MIN_WIDTH:
4645 const ClutterLayoutInfo *info;
4647 info = _clutter_actor_get_layout_info_or_defaults (actor);
4648 g_value_set_float (value, info->min_width);
4652 case PROP_MIN_HEIGHT:
4654 const ClutterLayoutInfo *info;
4656 info = _clutter_actor_get_layout_info_or_defaults (actor);
4657 g_value_set_float (value, info->min_height);
4661 case PROP_NATURAL_WIDTH:
4663 const ClutterLayoutInfo *info;
4665 info = _clutter_actor_get_layout_info_or_defaults (actor);
4666 g_value_set_float (value, info->natural_width);
4670 case PROP_NATURAL_HEIGHT:
4672 const ClutterLayoutInfo *info;
4674 info = _clutter_actor_get_layout_info_or_defaults (actor);
4675 g_value_set_float (value, info->natural_height);
4679 case PROP_MIN_WIDTH_SET:
4680 g_value_set_boolean (value, priv->min_width_set);
4683 case PROP_MIN_HEIGHT_SET:
4684 g_value_set_boolean (value, priv->min_height_set);
4687 case PROP_NATURAL_WIDTH_SET:
4688 g_value_set_boolean (value, priv->natural_width_set);
4691 case PROP_NATURAL_HEIGHT_SET:
4692 g_value_set_boolean (value, priv->natural_height_set);
4695 case PROP_REQUEST_MODE:
4696 g_value_set_enum (value, priv->request_mode);
4699 case PROP_ALLOCATION:
4700 g_value_set_boxed (value, &priv->allocation);
4704 g_value_set_float (value, clutter_actor_get_depth (actor));
4708 g_value_set_uint (value, priv->opacity);
4711 case PROP_OFFSCREEN_REDIRECT:
4712 g_value_set_enum (value, priv->offscreen_redirect);
4716 g_value_set_string (value, priv->name);
4720 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4724 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4728 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4732 g_value_set_boolean (value, priv->has_clip);
4737 ClutterGeometry clip;
4739 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4740 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4741 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4742 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4744 g_value_set_boxed (value, &clip);
4748 case PROP_CLIP_TO_ALLOCATION:
4749 g_value_set_boolean (value, priv->clip_to_allocation);
4754 const ClutterTransformInfo *info;
4756 info = _clutter_actor_get_transform_info_or_defaults (actor);
4757 g_value_set_double (value, info->scale_x);
4763 const ClutterTransformInfo *info;
4765 info = _clutter_actor_get_transform_info_or_defaults (actor);
4766 g_value_set_double (value, info->scale_y);
4770 case PROP_SCALE_CENTER_X:
4774 clutter_actor_get_scale_center (actor, ¢er, NULL);
4776 g_value_set_float (value, center);
4780 case PROP_SCALE_CENTER_Y:
4784 clutter_actor_get_scale_center (actor, NULL, ¢er);
4786 g_value_set_float (value, center);
4790 case PROP_SCALE_GRAVITY:
4791 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4795 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4798 case PROP_ROTATION_ANGLE_X:
4800 const ClutterTransformInfo *info;
4802 info = _clutter_actor_get_transform_info_or_defaults (actor);
4803 g_value_set_double (value, info->rx_angle);
4807 case PROP_ROTATION_ANGLE_Y:
4809 const ClutterTransformInfo *info;
4811 info = _clutter_actor_get_transform_info_or_defaults (actor);
4812 g_value_set_double (value, info->ry_angle);
4816 case PROP_ROTATION_ANGLE_Z:
4818 const ClutterTransformInfo *info;
4820 info = _clutter_actor_get_transform_info_or_defaults (actor);
4821 g_value_set_double (value, info->rz_angle);
4825 case PROP_ROTATION_CENTER_X:
4827 ClutterVertex center;
4829 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4834 g_value_set_boxed (value, ¢er);
4838 case PROP_ROTATION_CENTER_Y:
4840 ClutterVertex center;
4842 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4847 g_value_set_boxed (value, ¢er);
4851 case PROP_ROTATION_CENTER_Z:
4853 ClutterVertex center;
4855 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4860 g_value_set_boxed (value, ¢er);
4864 case PROP_ROTATION_CENTER_Z_GRAVITY:
4865 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4870 const ClutterTransformInfo *info;
4873 info = _clutter_actor_get_transform_info_or_defaults (actor);
4874 clutter_anchor_coord_get_units (actor, &info->anchor,
4878 g_value_set_float (value, anchor_x);
4884 const ClutterTransformInfo *info;
4887 info = _clutter_actor_get_transform_info_or_defaults (actor);
4888 clutter_anchor_coord_get_units (actor, &info->anchor,
4892 g_value_set_float (value, anchor_y);
4896 case PROP_ANCHOR_GRAVITY:
4897 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4900 case PROP_SHOW_ON_SET_PARENT:
4901 g_value_set_boolean (value, priv->show_on_set_parent);
4904 case PROP_TEXT_DIRECTION:
4905 g_value_set_enum (value, priv->text_direction);
4908 case PROP_HAS_POINTER:
4909 g_value_set_boolean (value, priv->has_pointer);
4912 case PROP_LAYOUT_MANAGER:
4913 g_value_set_object (value, priv->layout_manager);
4918 const ClutterLayoutInfo *info;
4920 info = _clutter_actor_get_layout_info_or_defaults (actor);
4921 g_value_set_enum (value, info->x_align);
4927 const ClutterLayoutInfo *info;
4929 info = _clutter_actor_get_layout_info_or_defaults (actor);
4930 g_value_set_enum (value, info->y_align);
4934 case PROP_MARGIN_TOP:
4936 const ClutterLayoutInfo *info;
4938 info = _clutter_actor_get_layout_info_or_defaults (actor);
4939 g_value_set_float (value, info->margin.top);
4943 case PROP_MARGIN_BOTTOM:
4945 const ClutterLayoutInfo *info;
4947 info = _clutter_actor_get_layout_info_or_defaults (actor);
4948 g_value_set_float (value, info->margin.bottom);
4952 case PROP_MARGIN_LEFT:
4954 const ClutterLayoutInfo *info;
4956 info = _clutter_actor_get_layout_info_or_defaults (actor);
4957 g_value_set_float (value, info->margin.left);
4961 case PROP_MARGIN_RIGHT:
4963 const ClutterLayoutInfo *info;
4965 info = _clutter_actor_get_layout_info_or_defaults (actor);
4966 g_value_set_float (value, info->margin.right);
4970 case PROP_BACKGROUND_COLOR_SET:
4971 g_value_set_boolean (value, priv->bg_color_set);
4974 case PROP_BACKGROUND_COLOR:
4975 g_value_set_boxed (value, &priv->bg_color);
4978 case PROP_FIRST_CHILD:
4979 g_value_set_object (value, priv->first_child);
4982 case PROP_LAST_CHILD:
4983 g_value_set_object (value, priv->last_child);
4987 g_value_set_object (value, priv->content);
4990 case PROP_CONTENT_GRAVITY:
4991 g_value_set_enum (value, priv->content_gravity);
4994 case PROP_CONTENT_BOX:
4996 ClutterActorBox box = { 0, };
4998 clutter_actor_get_content_box (actor, &box);
4999 g_value_set_boxed (value, &box);
5003 case PROP_MINIFICATION_FILTER:
5004 g_value_set_enum (value, priv->min_filter);
5007 case PROP_MAGNIFICATION_FILTER:
5008 g_value_set_enum (value, priv->mag_filter);
5012 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5018 clutter_actor_dispose (GObject *object)
5020 ClutterActor *self = CLUTTER_ACTOR (object);
5021 ClutterActorPrivate *priv = self->priv;
5023 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5025 g_type_name (G_OBJECT_TYPE (self)),
5028 g_signal_emit (self, actor_signals[DESTROY], 0);
5030 /* avoid recursing when called from clutter_actor_destroy() */
5031 if (priv->parent != NULL)
5033 ClutterActor *parent = priv->parent;
5035 /* go through the Container implementation unless this
5036 * is an internal child and has been marked as such.
5038 * removing the actor from its parent will reset the
5039 * realized and mapped states.
5041 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5042 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5044 clutter_actor_remove_child_internal (parent, self,
5045 REMOVE_CHILD_LEGACY_FLAGS);
5048 /* parent must be gone at this point */
5049 g_assert (priv->parent == NULL);
5051 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5053 /* can't be mapped or realized with no parent */
5054 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5055 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5058 g_clear_object (&priv->pango_context);
5059 g_clear_object (&priv->actions);
5060 g_clear_object (&priv->constraints);
5061 g_clear_object (&priv->effects);
5062 g_clear_object (&priv->flatten_effect);
5064 if (priv->layout_manager != NULL)
5066 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5067 g_clear_object (&priv->layout_manager);
5070 if (priv->content != NULL)
5072 _clutter_content_detached (priv->content, self);
5073 g_clear_object (&priv->content);
5076 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5080 clutter_actor_finalize (GObject *object)
5082 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5084 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5085 priv->name != NULL ? priv->name : "<none>",
5087 g_type_name (G_OBJECT_TYPE (object)));
5089 _clutter_context_release_id (priv->id);
5091 g_free (priv->name);
5093 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5098 * clutter_actor_get_accessible:
5099 * @self: a #ClutterActor
5101 * Returns the accessible object that describes the actor to an
5102 * assistive technology.
5104 * If no class-specific #AtkObject implementation is available for the
5105 * actor instance in question, it will inherit an #AtkObject
5106 * implementation from the first ancestor class for which such an
5107 * implementation is defined.
5109 * The documentation of the <ulink
5110 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5111 * library contains more information about accessible objects and
5114 * Returns: (transfer none): the #AtkObject associated with @actor
5117 clutter_actor_get_accessible (ClutterActor *self)
5119 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5121 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5125 clutter_actor_real_get_accessible (ClutterActor *actor)
5127 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5131 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5133 AtkObject *accessible;
5135 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5136 if (accessible != NULL)
5137 g_object_ref (accessible);
5143 atk_implementor_iface_init (AtkImplementorIface *iface)
5145 iface->ref_accessible = _clutter_actor_ref_accessible;
5149 clutter_actor_update_default_paint_volume (ClutterActor *self,
5150 ClutterPaintVolume *volume)
5152 ClutterActorPrivate *priv = self->priv;
5153 gboolean res = FALSE;
5155 /* we start from the allocation */
5156 clutter_paint_volume_set_width (volume,
5157 priv->allocation.x2 - priv->allocation.x1);
5158 clutter_paint_volume_set_height (volume,
5159 priv->allocation.y2 - priv->allocation.y1);
5161 /* if the actor has a clip set then we have a pretty definite
5162 * size for the paint volume: the actor cannot possibly paint
5163 * outside the clip region.
5165 if (priv->clip_to_allocation)
5167 /* the allocation has already been set, so we just flip the
5174 ClutterActor *child;
5176 if (priv->has_clip &&
5177 priv->clip.width >= 0 &&
5178 priv->clip.height >= 0)
5180 ClutterVertex origin;
5182 origin.x = priv->clip.x;
5183 origin.y = priv->clip.y;
5186 clutter_paint_volume_set_origin (volume, &origin);
5187 clutter_paint_volume_set_width (volume, priv->clip.width);
5188 clutter_paint_volume_set_height (volume, priv->clip.height);
5193 /* if we don't have children we just bail out here... */
5194 if (priv->n_children == 0)
5197 /* ...but if we have children then we ask for their paint volume in
5198 * our coordinates. if any of our children replies that it doesn't
5199 * have a paint volume, we bail out
5201 for (child = priv->first_child;
5203 child = child->priv->next_sibling)
5205 const ClutterPaintVolume *child_volume;
5207 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5208 if (child_volume == NULL)
5214 clutter_paint_volume_union (volume, child_volume);
5224 clutter_actor_real_get_paint_volume (ClutterActor *self,
5225 ClutterPaintVolume *volume)
5227 ClutterActorClass *klass;
5230 klass = CLUTTER_ACTOR_GET_CLASS (self);
5232 /* XXX - this thoroughly sucks, but we don't want to penalize users
5233 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5234 * redraw. This should go away in 2.0.
5236 if (klass->paint == clutter_actor_real_paint &&
5237 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5243 /* this is the default return value: we cannot know if a class
5244 * is going to paint outside its allocation, so we take the
5245 * conservative approach.
5250 if (clutter_actor_update_default_paint_volume (self, volume))
5257 * clutter_actor_get_default_paint_volume:
5258 * @self: a #ClutterActor
5260 * Retrieves the default paint volume for @self.
5262 * This function provides the same #ClutterPaintVolume that would be
5263 * computed by the default implementation inside #ClutterActor of the
5264 * #ClutterActorClass.get_paint_volume() virtual function.
5266 * This function should only be used by #ClutterActor subclasses that
5267 * cannot chain up to the parent implementation when computing their
5270 * Return value: (transfer none): a pointer to the default
5271 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5272 * the actor could not compute a valid paint volume. The returned value
5273 * is not guaranteed to be stable across multiple frames, so if you
5274 * want to retain it, you will need to copy it using
5275 * clutter_paint_volume_copy().
5279 const ClutterPaintVolume *
5280 clutter_actor_get_default_paint_volume (ClutterActor *self)
5282 ClutterPaintVolume volume;
5283 ClutterPaintVolume *res;
5285 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5288 _clutter_paint_volume_init_static (&volume, self);
5289 if (clutter_actor_update_default_paint_volume (self, &volume))
5291 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5295 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5296 _clutter_paint_volume_copy_static (&volume, res);
5300 clutter_paint_volume_free (&volume);
5306 clutter_actor_real_has_overlaps (ClutterActor *self)
5308 /* By default we'll assume that all actors need an offscreen redirect to get
5309 * the correct opacity. Actors such as ClutterTexture that would never need
5310 * an offscreen redirect can override this to return FALSE. */
5315 clutter_actor_real_destroy (ClutterActor *actor)
5317 ClutterActorIter iter;
5319 g_object_freeze_notify (G_OBJECT (actor));
5321 clutter_actor_iter_init (&iter, actor);
5322 while (clutter_actor_iter_next (&iter, NULL))
5323 clutter_actor_iter_destroy (&iter);
5325 g_object_thaw_notify (G_OBJECT (actor));
5329 clutter_actor_constructor (GType gtype,
5331 GObjectConstructParam *props)
5333 GObjectClass *gobject_class;
5337 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5338 retval = gobject_class->constructor (gtype, n_props, props);
5339 self = CLUTTER_ACTOR (retval);
5341 if (self->priv->layout_manager == NULL)
5343 ClutterLayoutManager *default_layout;
5345 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5347 default_layout = clutter_fixed_layout_new ();
5348 clutter_actor_set_layout_manager (self, default_layout);
5355 clutter_actor_class_init (ClutterActorClass *klass)
5357 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5359 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5360 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5361 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5362 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5364 object_class->constructor = clutter_actor_constructor;
5365 object_class->set_property = clutter_actor_set_property;
5366 object_class->get_property = clutter_actor_get_property;
5367 object_class->dispose = clutter_actor_dispose;
5368 object_class->finalize = clutter_actor_finalize;
5370 klass->show = clutter_actor_real_show;
5371 klass->show_all = clutter_actor_show;
5372 klass->hide = clutter_actor_real_hide;
5373 klass->hide_all = clutter_actor_hide;
5374 klass->map = clutter_actor_real_map;
5375 klass->unmap = clutter_actor_real_unmap;
5376 klass->unrealize = clutter_actor_real_unrealize;
5377 klass->pick = clutter_actor_real_pick;
5378 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5379 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5380 klass->allocate = clutter_actor_real_allocate;
5381 klass->queue_redraw = clutter_actor_real_queue_redraw;
5382 klass->queue_relayout = clutter_actor_real_queue_relayout;
5383 klass->apply_transform = clutter_actor_real_apply_transform;
5384 klass->get_accessible = clutter_actor_real_get_accessible;
5385 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5386 klass->has_overlaps = clutter_actor_real_has_overlaps;
5387 klass->paint = clutter_actor_real_paint;
5388 klass->destroy = clutter_actor_real_destroy;
5390 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5395 * X coordinate of the actor in pixels. If written, forces a fixed
5396 * position for the actor. If read, returns the fixed position if any,
5397 * otherwise the allocation if available, otherwise 0.
5399 * The #ClutterActor:x property is animatable.
5402 g_param_spec_float ("x",
5404 P_("X coordinate of the actor"),
5405 -G_MAXFLOAT, G_MAXFLOAT,
5408 G_PARAM_STATIC_STRINGS |
5409 CLUTTER_PARAM_ANIMATABLE);
5414 * Y coordinate of the actor in pixels. If written, forces a fixed
5415 * position for the actor. If read, returns the fixed position if
5416 * any, otherwise the allocation if available, otherwise 0.
5418 * The #ClutterActor:y property is animatable.
5421 g_param_spec_float ("y",
5423 P_("Y coordinate of the actor"),
5424 -G_MAXFLOAT, G_MAXFLOAT,
5427 G_PARAM_STATIC_STRINGS |
5428 CLUTTER_PARAM_ANIMATABLE);
5431 * ClutterActor:width:
5433 * Width of the actor (in pixels). If written, forces the minimum and
5434 * natural size request of the actor to the given width. If read, returns
5435 * the allocated width if available, otherwise the width request.
5437 * The #ClutterActor:width property is animatable.
5439 obj_props[PROP_WIDTH] =
5440 g_param_spec_float ("width",
5442 P_("Width of the actor"),
5446 G_PARAM_STATIC_STRINGS |
5447 CLUTTER_PARAM_ANIMATABLE);
5450 * ClutterActor:height:
5452 * Height of the actor (in pixels). If written, forces the minimum and
5453 * natural size request of the actor to the given height. If read, returns
5454 * the allocated height if available, otherwise the height request.
5456 * The #ClutterActor:height property is animatable.
5458 obj_props[PROP_HEIGHT] =
5459 g_param_spec_float ("height",
5461 P_("Height of the actor"),
5465 G_PARAM_STATIC_STRINGS |
5466 CLUTTER_PARAM_ANIMATABLE);
5469 * ClutterActor:fixed-x:
5471 * The fixed X position of the actor in pixels.
5473 * Writing this property sets #ClutterActor:fixed-position-set
5474 * property as well, as a side effect
5478 obj_props[PROP_FIXED_X] =
5479 g_param_spec_float ("fixed-x",
5481 P_("Forced X position of the actor"),
5482 -G_MAXFLOAT, G_MAXFLOAT,
5484 CLUTTER_PARAM_READWRITE);
5487 * ClutterActor:fixed-y:
5489 * The fixed Y position of the actor in pixels.
5491 * Writing this property sets the #ClutterActor:fixed-position-set
5492 * property as well, as a side effect
5496 obj_props[PROP_FIXED_Y] =
5497 g_param_spec_float ("fixed-y",
5499 P_("Forced Y position of the actor"),
5500 -G_MAXFLOAT, G_MAXFLOAT,
5502 CLUTTER_PARAM_READWRITE);
5505 * ClutterActor:fixed-position-set:
5507 * This flag controls whether the #ClutterActor:fixed-x and
5508 * #ClutterActor:fixed-y properties are used
5512 obj_props[PROP_FIXED_POSITION_SET] =
5513 g_param_spec_boolean ("fixed-position-set",
5514 P_("Fixed position set"),
5515 P_("Whether to use fixed positioning for the actor"),
5517 CLUTTER_PARAM_READWRITE);
5520 * ClutterActor:min-width:
5522 * A forced minimum width request for the actor, in pixels
5524 * Writing this property sets the #ClutterActor:min-width-set property
5525 * as well, as a side effect.
5527 *This property overrides the usual width request of the actor.
5531 obj_props[PROP_MIN_WIDTH] =
5532 g_param_spec_float ("min-width",
5534 P_("Forced minimum width request for the actor"),
5537 CLUTTER_PARAM_READWRITE);
5540 * ClutterActor:min-height:
5542 * A forced minimum height request for the actor, in pixels
5544 * Writing this property sets the #ClutterActor:min-height-set property
5545 * as well, as a side effect. This property overrides the usual height
5546 * request of the actor.
5550 obj_props[PROP_MIN_HEIGHT] =
5551 g_param_spec_float ("min-height",
5553 P_("Forced minimum height request for the actor"),
5556 CLUTTER_PARAM_READWRITE);
5559 * ClutterActor:natural-width:
5561 * A forced natural width request for the actor, in pixels
5563 * Writing this property sets the #ClutterActor:natural-width-set
5564 * property as well, as a side effect. This property overrides the
5565 * usual width request of the actor
5569 obj_props[PROP_NATURAL_WIDTH] =
5570 g_param_spec_float ("natural-width",
5571 P_("Natural Width"),
5572 P_("Forced natural width request for the actor"),
5575 CLUTTER_PARAM_READWRITE);
5578 * ClutterActor:natural-height:
5580 * A forced natural height request for the actor, in pixels
5582 * Writing this property sets the #ClutterActor:natural-height-set
5583 * property as well, as a side effect. This property overrides the
5584 * usual height request of the actor
5588 obj_props[PROP_NATURAL_HEIGHT] =
5589 g_param_spec_float ("natural-height",
5590 P_("Natural Height"),
5591 P_("Forced natural height request for the actor"),
5594 CLUTTER_PARAM_READWRITE);
5597 * ClutterActor:min-width-set:
5599 * This flag controls whether the #ClutterActor:min-width property
5604 obj_props[PROP_MIN_WIDTH_SET] =
5605 g_param_spec_boolean ("min-width-set",
5606 P_("Minimum width set"),
5607 P_("Whether to use the min-width property"),
5609 CLUTTER_PARAM_READWRITE);
5612 * ClutterActor:min-height-set:
5614 * This flag controls whether the #ClutterActor:min-height property
5619 obj_props[PROP_MIN_HEIGHT_SET] =
5620 g_param_spec_boolean ("min-height-set",
5621 P_("Minimum height set"),
5622 P_("Whether to use the min-height property"),
5624 CLUTTER_PARAM_READWRITE);
5627 * ClutterActor:natural-width-set:
5629 * This flag controls whether the #ClutterActor:natural-width property
5634 obj_props[PROP_NATURAL_WIDTH_SET] =
5635 g_param_spec_boolean ("natural-width-set",
5636 P_("Natural width set"),
5637 P_("Whether to use the natural-width property"),
5639 CLUTTER_PARAM_READWRITE);
5642 * ClutterActor:natural-height-set:
5644 * This flag controls whether the #ClutterActor:natural-height property
5649 obj_props[PROP_NATURAL_HEIGHT_SET] =
5650 g_param_spec_boolean ("natural-height-set",
5651 P_("Natural height set"),
5652 P_("Whether to use the natural-height property"),
5654 CLUTTER_PARAM_READWRITE);
5657 * ClutterActor:allocation:
5659 * The allocation for the actor, in pixels
5661 * This is property is read-only, but you might monitor it to know when an
5662 * actor moves or resizes
5666 obj_props[PROP_ALLOCATION] =
5667 g_param_spec_boxed ("allocation",
5669 P_("The actor's allocation"),
5670 CLUTTER_TYPE_ACTOR_BOX,
5671 CLUTTER_PARAM_READABLE);
5674 * ClutterActor:request-mode:
5676 * Request mode for the #ClutterActor. The request mode determines the
5677 * type of geometry management used by the actor, either height for width
5678 * (the default) or width for height.
5680 * For actors implementing height for width, the parent container should get
5681 * the preferred width first, and then the preferred height for that width.
5683 * For actors implementing width for height, the parent container should get
5684 * the preferred height first, and then the preferred width for that height.
5689 * ClutterRequestMode mode;
5690 * gfloat natural_width, min_width;
5691 * gfloat natural_height, min_height;
5693 * mode = clutter_actor_get_request_mode (child);
5694 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5696 * clutter_actor_get_preferred_width (child, -1,
5698 * &natural_width);
5699 * clutter_actor_get_preferred_height (child, natural_width,
5701 * &natural_height);
5705 * clutter_actor_get_preferred_height (child, -1,
5707 * &natural_height);
5708 * clutter_actor_get_preferred_width (child, natural_height,
5710 * &natural_width);
5714 * will retrieve the minimum and natural width and height depending on the
5715 * preferred request mode of the #ClutterActor "child".
5717 * The clutter_actor_get_preferred_size() function will implement this
5722 obj_props[PROP_REQUEST_MODE] =
5723 g_param_spec_enum ("request-mode",
5725 P_("The actor's request mode"),
5726 CLUTTER_TYPE_REQUEST_MODE,
5727 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5728 CLUTTER_PARAM_READWRITE);
5731 * ClutterActor:depth:
5733 * The position of the actor on the Z axis.
5735 * The #ClutterActor:depth property is relative to the parent's
5738 * The #ClutterActor:depth property is animatable.
5742 obj_props[PROP_DEPTH] =
5743 g_param_spec_float ("depth",
5745 P_("Position on the Z axis"),
5746 -G_MAXFLOAT, G_MAXFLOAT,
5749 G_PARAM_STATIC_STRINGS |
5750 CLUTTER_PARAM_ANIMATABLE);
5753 * ClutterActor:opacity:
5755 * Opacity of an actor, between 0 (fully transparent) and
5756 * 255 (fully opaque)
5758 * The #ClutterActor:opacity property is animatable.
5760 obj_props[PROP_OPACITY] =
5761 g_param_spec_uint ("opacity",
5763 P_("Opacity of an actor"),
5767 G_PARAM_STATIC_STRINGS |
5768 CLUTTER_PARAM_ANIMATABLE);
5771 * ClutterActor:offscreen-redirect:
5773 * Determines the conditions in which the actor will be redirected
5774 * to an offscreen framebuffer while being painted. For example this
5775 * can be used to cache an actor in a framebuffer or for improved
5776 * handling of transparent actors. See
5777 * clutter_actor_set_offscreen_redirect() for details.
5781 obj_props[PROP_OFFSCREEN_REDIRECT] =
5782 g_param_spec_flags ("offscreen-redirect",
5783 P_("Offscreen redirect"),
5784 P_("Flags controlling when to flatten the actor into a single image"),
5785 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5787 CLUTTER_PARAM_READWRITE);
5790 * ClutterActor:visible:
5792 * Whether the actor is set to be visible or not
5794 * See also #ClutterActor:mapped
5796 obj_props[PROP_VISIBLE] =
5797 g_param_spec_boolean ("visible",
5799 P_("Whether the actor is visible or not"),
5801 CLUTTER_PARAM_READWRITE);
5804 * ClutterActor:mapped:
5806 * Whether the actor is mapped (will be painted when the stage
5807 * to which it belongs is mapped)
5811 obj_props[PROP_MAPPED] =
5812 g_param_spec_boolean ("mapped",
5814 P_("Whether the actor will be painted"),
5816 CLUTTER_PARAM_READABLE);
5819 * ClutterActor:realized:
5821 * Whether the actor has been realized
5825 obj_props[PROP_REALIZED] =
5826 g_param_spec_boolean ("realized",
5828 P_("Whether the actor has been realized"),
5830 CLUTTER_PARAM_READABLE);
5833 * ClutterActor:reactive:
5835 * Whether the actor is reactive to events or not
5837 * Only reactive actors will emit event-related signals
5841 obj_props[PROP_REACTIVE] =
5842 g_param_spec_boolean ("reactive",
5844 P_("Whether the actor is reactive to events"),
5846 CLUTTER_PARAM_READWRITE);
5849 * ClutterActor:has-clip:
5851 * Whether the actor has the #ClutterActor:clip property set or not
5853 obj_props[PROP_HAS_CLIP] =
5854 g_param_spec_boolean ("has-clip",
5856 P_("Whether the actor has a clip set"),
5858 CLUTTER_PARAM_READABLE);
5861 * ClutterActor:clip:
5863 * The clip region for the actor, in actor-relative coordinates
5865 * Every part of the actor outside the clip region will not be
5868 obj_props[PROP_CLIP] =
5869 g_param_spec_boxed ("clip",
5871 P_("The clip region for the actor"),
5872 CLUTTER_TYPE_GEOMETRY,
5873 CLUTTER_PARAM_READWRITE);
5876 * ClutterActor:name:
5878 * The name of the actor
5882 obj_props[PROP_NAME] =
5883 g_param_spec_string ("name",
5885 P_("Name of the actor"),
5887 CLUTTER_PARAM_READWRITE);
5890 * ClutterActor:scale-x:
5892 * The horizontal scale of the actor.
5894 * The #ClutterActor:scale-x property is animatable.
5898 obj_props[PROP_SCALE_X] =
5899 g_param_spec_double ("scale-x",
5901 P_("Scale factor on the X axis"),
5905 G_PARAM_STATIC_STRINGS |
5906 CLUTTER_PARAM_ANIMATABLE);
5909 * ClutterActor:scale-y:
5911 * The vertical scale of the actor.
5913 * The #ClutterActor:scale-y property is animatable.
5917 obj_props[PROP_SCALE_Y] =
5918 g_param_spec_double ("scale-y",
5920 P_("Scale factor on the Y axis"),
5924 G_PARAM_STATIC_STRINGS |
5925 CLUTTER_PARAM_ANIMATABLE);
5928 * ClutterActor:scale-center-x:
5930 * The horizontal center point for scaling
5934 obj_props[PROP_SCALE_CENTER_X] =
5935 g_param_spec_float ("scale-center-x",
5936 P_("Scale Center X"),
5937 P_("Horizontal scale center"),
5938 -G_MAXFLOAT, G_MAXFLOAT,
5940 CLUTTER_PARAM_READWRITE);
5943 * ClutterActor:scale-center-y:
5945 * The vertical center point for scaling
5949 obj_props[PROP_SCALE_CENTER_Y] =
5950 g_param_spec_float ("scale-center-y",
5951 P_("Scale Center Y"),
5952 P_("Vertical scale center"),
5953 -G_MAXFLOAT, G_MAXFLOAT,
5955 CLUTTER_PARAM_READWRITE);
5958 * ClutterActor:scale-gravity:
5960 * The center point for scaling expressed as a #ClutterGravity
5964 obj_props[PROP_SCALE_GRAVITY] =
5965 g_param_spec_enum ("scale-gravity",
5966 P_("Scale Gravity"),
5967 P_("The center of scaling"),
5968 CLUTTER_TYPE_GRAVITY,
5969 CLUTTER_GRAVITY_NONE,
5970 CLUTTER_PARAM_READWRITE);
5973 * ClutterActor:rotation-angle-x:
5975 * The rotation angle on the X axis.
5977 * The #ClutterActor:rotation-angle-x property is animatable.
5981 obj_props[PROP_ROTATION_ANGLE_X] =
5982 g_param_spec_double ("rotation-angle-x",
5983 P_("Rotation Angle X"),
5984 P_("The rotation angle on the X axis"),
5985 -G_MAXDOUBLE, G_MAXDOUBLE,
5988 G_PARAM_STATIC_STRINGS |
5989 CLUTTER_PARAM_ANIMATABLE);
5992 * ClutterActor:rotation-angle-y:
5994 * The rotation angle on the Y axis
5996 * The #ClutterActor:rotation-angle-y property is animatable.
6000 obj_props[PROP_ROTATION_ANGLE_Y] =
6001 g_param_spec_double ("rotation-angle-y",
6002 P_("Rotation Angle Y"),
6003 P_("The rotation angle on the Y axis"),
6004 -G_MAXDOUBLE, G_MAXDOUBLE,
6007 G_PARAM_STATIC_STRINGS |
6008 CLUTTER_PARAM_ANIMATABLE);
6011 * ClutterActor:rotation-angle-z:
6013 * The rotation angle on the Z axis
6015 * The #ClutterActor:rotation-angle-z property is animatable.
6019 obj_props[PROP_ROTATION_ANGLE_Z] =
6020 g_param_spec_double ("rotation-angle-z",
6021 P_("Rotation Angle Z"),
6022 P_("The rotation angle on the Z axis"),
6023 -G_MAXDOUBLE, G_MAXDOUBLE,
6026 G_PARAM_STATIC_STRINGS |
6027 CLUTTER_PARAM_ANIMATABLE);
6030 * ClutterActor:rotation-center-x:
6032 * The rotation center on the X axis.
6036 obj_props[PROP_ROTATION_CENTER_X] =
6037 g_param_spec_boxed ("rotation-center-x",
6038 P_("Rotation Center X"),
6039 P_("The rotation center on the X axis"),
6040 CLUTTER_TYPE_VERTEX,
6041 CLUTTER_PARAM_READWRITE);
6044 * ClutterActor:rotation-center-y:
6046 * The rotation center on the Y axis.
6050 obj_props[PROP_ROTATION_CENTER_Y] =
6051 g_param_spec_boxed ("rotation-center-y",
6052 P_("Rotation Center Y"),
6053 P_("The rotation center on the Y axis"),
6054 CLUTTER_TYPE_VERTEX,
6055 CLUTTER_PARAM_READWRITE);
6058 * ClutterActor:rotation-center-z:
6060 * The rotation center on the Z axis.
6064 obj_props[PROP_ROTATION_CENTER_Z] =
6065 g_param_spec_boxed ("rotation-center-z",
6066 P_("Rotation Center Z"),
6067 P_("The rotation center on the Z axis"),
6068 CLUTTER_TYPE_VERTEX,
6069 CLUTTER_PARAM_READWRITE);
6072 * ClutterActor:rotation-center-z-gravity:
6074 * The rotation center on the Z axis expressed as a #ClutterGravity.
6078 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6079 g_param_spec_enum ("rotation-center-z-gravity",
6080 P_("Rotation Center Z Gravity"),
6081 P_("Center point for rotation around the Z axis"),
6082 CLUTTER_TYPE_GRAVITY,
6083 CLUTTER_GRAVITY_NONE,
6084 CLUTTER_PARAM_READWRITE);
6087 * ClutterActor:anchor-x:
6089 * The X coordinate of an actor's anchor point, relative to
6090 * the actor coordinate space, in pixels
6094 obj_props[PROP_ANCHOR_X] =
6095 g_param_spec_float ("anchor-x",
6097 P_("X coordinate of the anchor point"),
6098 -G_MAXFLOAT, G_MAXFLOAT,
6100 CLUTTER_PARAM_READWRITE);
6103 * ClutterActor:anchor-y:
6105 * The Y coordinate of an actor's anchor point, relative to
6106 * the actor coordinate space, in pixels
6110 obj_props[PROP_ANCHOR_Y] =
6111 g_param_spec_float ("anchor-y",
6113 P_("Y coordinate of the anchor point"),
6114 -G_MAXFLOAT, G_MAXFLOAT,
6116 CLUTTER_PARAM_READWRITE);
6119 * ClutterActor:anchor-gravity:
6121 * The anchor point expressed as a #ClutterGravity
6125 obj_props[PROP_ANCHOR_GRAVITY] =
6126 g_param_spec_enum ("anchor-gravity",
6127 P_("Anchor Gravity"),
6128 P_("The anchor point as a ClutterGravity"),
6129 CLUTTER_TYPE_GRAVITY,
6130 CLUTTER_GRAVITY_NONE,
6131 CLUTTER_PARAM_READWRITE);
6134 * ClutterActor:show-on-set-parent:
6136 * If %TRUE, the actor is automatically shown when parented.
6138 * Calling clutter_actor_hide() on an actor which has not been
6139 * parented will set this property to %FALSE as a side effect.
6143 obj_props[PROP_SHOW_ON_SET_PARENT] =
6144 g_param_spec_boolean ("show-on-set-parent",
6145 P_("Show on set parent"),
6146 P_("Whether the actor is shown when parented"),
6148 CLUTTER_PARAM_READWRITE);
6151 * ClutterActor:clip-to-allocation:
6153 * Whether the clip region should track the allocated area
6156 * This property is ignored if a clip area has been explicitly
6157 * set using clutter_actor_set_clip().
6161 obj_props[PROP_CLIP_TO_ALLOCATION] =
6162 g_param_spec_boolean ("clip-to-allocation",
6163 P_("Clip to Allocation"),
6164 P_("Sets the clip region to track the actor's allocation"),
6166 CLUTTER_PARAM_READWRITE);
6169 * ClutterActor:text-direction:
6171 * The direction of the text inside a #ClutterActor.
6175 obj_props[PROP_TEXT_DIRECTION] =
6176 g_param_spec_enum ("text-direction",
6177 P_("Text Direction"),
6178 P_("Direction of the text"),
6179 CLUTTER_TYPE_TEXT_DIRECTION,
6180 CLUTTER_TEXT_DIRECTION_LTR,
6181 CLUTTER_PARAM_READWRITE);
6184 * ClutterActor:has-pointer:
6186 * Whether the actor contains the pointer of a #ClutterInputDevice
6191 obj_props[PROP_HAS_POINTER] =
6192 g_param_spec_boolean ("has-pointer",
6194 P_("Whether the actor contains the pointer of an input device"),
6196 CLUTTER_PARAM_READABLE);
6199 * ClutterActor:actions:
6201 * Adds a #ClutterAction to the actor
6205 obj_props[PROP_ACTIONS] =
6206 g_param_spec_object ("actions",
6208 P_("Adds an action to the actor"),
6209 CLUTTER_TYPE_ACTION,
6210 CLUTTER_PARAM_WRITABLE);
6213 * ClutterActor:constraints:
6215 * Adds a #ClutterConstraint to the actor
6219 obj_props[PROP_CONSTRAINTS] =
6220 g_param_spec_object ("constraints",
6222 P_("Adds a constraint to the actor"),
6223 CLUTTER_TYPE_CONSTRAINT,
6224 CLUTTER_PARAM_WRITABLE);
6227 * ClutterActor:effect:
6229 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6233 obj_props[PROP_EFFECT] =
6234 g_param_spec_object ("effect",
6236 P_("Add an effect to be applied on the actor"),
6237 CLUTTER_TYPE_EFFECT,
6238 CLUTTER_PARAM_WRITABLE);
6241 * ClutterActor:layout-manager:
6243 * A delegate object for controlling the layout of the children of
6248 obj_props[PROP_LAYOUT_MANAGER] =
6249 g_param_spec_object ("layout-manager",
6250 P_("Layout Manager"),
6251 P_("The object controlling the layout of an actor's children"),
6252 CLUTTER_TYPE_LAYOUT_MANAGER,
6253 CLUTTER_PARAM_READWRITE);
6257 * ClutterActor:x-align:
6259 * The alignment of an actor on the X axis, if the actor has been given
6260 * extra space for its allocation.
6264 obj_props[PROP_X_ALIGN] =
6265 g_param_spec_enum ("x-align",
6267 P_("The alignment of the actor on the X axis within its allocation"),
6268 CLUTTER_TYPE_ACTOR_ALIGN,
6269 CLUTTER_ACTOR_ALIGN_FILL,
6270 CLUTTER_PARAM_READWRITE);
6273 * ClutterActor:y-align:
6275 * The alignment of an actor on the Y axis, if the actor has been given
6276 * extra space for its allocation.
6280 obj_props[PROP_Y_ALIGN] =
6281 g_param_spec_enum ("y-align",
6283 P_("The alignment of the actor on the Y axis within its allocation"),
6284 CLUTTER_TYPE_ACTOR_ALIGN,
6285 CLUTTER_ACTOR_ALIGN_FILL,
6286 CLUTTER_PARAM_READWRITE);
6289 * ClutterActor:margin-top:
6291 * The margin (in pixels) from the top of the actor.
6293 * This property adds a margin to the actor's preferred size; the margin
6294 * will be automatically taken into account when allocating the actor.
6298 obj_props[PROP_MARGIN_TOP] =
6299 g_param_spec_float ("margin-top",
6301 P_("Extra space at the top"),
6304 CLUTTER_PARAM_READWRITE);
6307 * ClutterActor:margin-bottom:
6309 * The margin (in pixels) from the bottom of the actor.
6311 * This property adds a margin to the actor's preferred size; the margin
6312 * will be automatically taken into account when allocating the actor.
6316 obj_props[PROP_MARGIN_BOTTOM] =
6317 g_param_spec_float ("margin-bottom",
6318 P_("Margin Bottom"),
6319 P_("Extra space at the bottom"),
6322 CLUTTER_PARAM_READWRITE);
6325 * ClutterActor:margin-left:
6327 * The margin (in pixels) from the left of the actor.
6329 * This property adds a margin to the actor's preferred size; the margin
6330 * will be automatically taken into account when allocating the actor.
6334 obj_props[PROP_MARGIN_LEFT] =
6335 g_param_spec_float ("margin-left",
6337 P_("Extra space at the left"),
6340 CLUTTER_PARAM_READWRITE);
6343 * ClutterActor:margin-right:
6345 * The margin (in pixels) from the right of the actor.
6347 * This property adds a margin to the actor's preferred size; the margin
6348 * will be automatically taken into account when allocating the actor.
6352 obj_props[PROP_MARGIN_RIGHT] =
6353 g_param_spec_float ("margin-right",
6355 P_("Extra space at the right"),
6358 CLUTTER_PARAM_READWRITE);
6361 * ClutterActor:background-color-set:
6363 * Whether the #ClutterActor:background-color property has been set.
6367 obj_props[PROP_BACKGROUND_COLOR_SET] =
6368 g_param_spec_boolean ("background-color-set",
6369 P_("Background Color Set"),
6370 P_("Whether the background color is set"),
6372 CLUTTER_PARAM_READABLE);
6375 * ClutterActor:background-color:
6377 * Paints a solid fill of the actor's allocation using the specified
6380 * The #ClutterActor:background-color property is animatable.
6384 obj_props[PROP_BACKGROUND_COLOR] =
6385 clutter_param_spec_color ("background-color",
6386 P_("Background color"),
6387 P_("The actor's background color"),
6388 CLUTTER_COLOR_Transparent,
6390 G_PARAM_STATIC_STRINGS |
6391 CLUTTER_PARAM_ANIMATABLE);
6394 * ClutterActor:first-child:
6396 * The actor's first child.
6400 obj_props[PROP_FIRST_CHILD] =
6401 g_param_spec_object ("first-child",
6403 P_("The actor's first child"),
6405 CLUTTER_PARAM_READABLE);
6408 * ClutterActor:last-child:
6410 * The actor's last child.
6414 obj_props[PROP_LAST_CHILD] =
6415 g_param_spec_object ("last-child",
6417 P_("The actor's last child"),
6419 CLUTTER_PARAM_READABLE);
6422 * ClutterActor:content:
6424 * The #ClutterContent implementation that controls the content
6429 obj_props[PROP_CONTENT] =
6430 g_param_spec_object ("content",
6432 P_("Delegate object for painting the actor's content"),
6433 CLUTTER_TYPE_CONTENT,
6434 CLUTTER_PARAM_READWRITE);
6437 * ClutterActor:content-gravity:
6439 * The alignment that should be honoured by the #ClutterContent
6440 * set with the #ClutterActor:content property.
6442 * Changing the value of this property will change the bounding box of
6443 * the content; you can use the #ClutterActor:content-box property to
6444 * get the position and size of the content within the actor's
6447 * This property is meaningful only for #ClutterContent implementations
6448 * that have a preferred size, and if the preferred size is smaller than
6449 * the actor's allocation.
6451 * The #ClutterActor:content-gravity property is animatable.
6455 obj_props[PROP_CONTENT_GRAVITY] =
6456 g_param_spec_enum ("content-gravity",
6457 P_("Content Gravity"),
6458 P_("Alignment of the actor's content"),
6459 CLUTTER_TYPE_CONTENT_GRAVITY,
6460 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6461 CLUTTER_PARAM_READWRITE);
6464 * ClutterActor:content-box:
6466 * The bounding box for the #ClutterContent used by the actor.
6468 * The value of this property is controlled by the #ClutterActor:allocation
6469 * and #ClutterActor:content-gravity properties of #ClutterActor.
6471 * The bounding box for the content is guaranteed to never exceed the
6472 * allocation's of the actor.
6476 obj_props[PROP_CONTENT_BOX] =
6477 g_param_spec_boxed ("content-box",
6479 P_("The bounding box of the actor's content"),
6480 CLUTTER_TYPE_ACTOR_BOX,
6482 G_PARAM_STATIC_STRINGS |
6483 CLUTTER_PARAM_ANIMATABLE);
6485 obj_props[PROP_MINIFICATION_FILTER] =
6486 g_param_spec_enum ("minification-filter",
6487 P_("Minification Filter"),
6488 P_("The filter used when reducing the size of the content"),
6489 CLUTTER_TYPE_SCALING_FILTER,
6490 CLUTTER_SCALING_FILTER_LINEAR,
6491 CLUTTER_PARAM_READWRITE);
6493 obj_props[PROP_MAGNIFICATION_FILTER] =
6494 g_param_spec_enum ("magnification-filter",
6495 P_("Magnification Filter"),
6496 P_("The filter used when increasing the size of the content"),
6497 CLUTTER_TYPE_SCALING_FILTER,
6498 CLUTTER_SCALING_FILTER_LINEAR,
6499 CLUTTER_PARAM_READWRITE);
6501 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6504 * ClutterActor::destroy:
6505 * @actor: the #ClutterActor which emitted the signal
6507 * The ::destroy signal notifies that all references held on the
6508 * actor which emitted it should be released.
6510 * The ::destroy signal should be used by all holders of a reference
6513 * This signal might result in the finalization of the #ClutterActor
6514 * if all references are released.
6516 * Composite actors and actors implementing the #ClutterContainer
6517 * interface should override the default implementation of the
6518 * class handler of this signal and call clutter_actor_destroy() on
6519 * their children. When overriding the default class handler, it is
6520 * required to chain up to the parent's implementation.
6524 actor_signals[DESTROY] =
6525 g_signal_new (I_("destroy"),
6526 G_TYPE_FROM_CLASS (object_class),
6527 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6528 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6530 _clutter_marshal_VOID__VOID,
6533 * ClutterActor::show:
6534 * @actor: the object which received the signal
6536 * The ::show signal is emitted when an actor is visible and
6537 * rendered on the stage.
6541 actor_signals[SHOW] =
6542 g_signal_new (I_("show"),
6543 G_TYPE_FROM_CLASS (object_class),
6545 G_STRUCT_OFFSET (ClutterActorClass, show),
6547 _clutter_marshal_VOID__VOID,
6550 * ClutterActor::hide:
6551 * @actor: the object which received the signal
6553 * The ::hide signal is emitted when an actor is no longer rendered
6558 actor_signals[HIDE] =
6559 g_signal_new (I_("hide"),
6560 G_TYPE_FROM_CLASS (object_class),
6562 G_STRUCT_OFFSET (ClutterActorClass, hide),
6564 _clutter_marshal_VOID__VOID,
6567 * ClutterActor::parent-set:
6568 * @actor: the object which received the signal
6569 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6571 * This signal is emitted when the parent of the actor changes.
6575 actor_signals[PARENT_SET] =
6576 g_signal_new (I_("parent-set"),
6577 G_TYPE_FROM_CLASS (object_class),
6579 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6581 _clutter_marshal_VOID__OBJECT,
6583 CLUTTER_TYPE_ACTOR);
6586 * ClutterActor::queue-redraw:
6587 * @actor: the actor we're bubbling the redraw request through
6588 * @origin: the actor which initiated the redraw request
6590 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6591 * is called on @origin.
6593 * The default implementation for #ClutterActor chains up to the
6594 * parent actor and queues a redraw on the parent, thus "bubbling"
6595 * the redraw queue up through the actor graph. The default
6596 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6597 * in a main loop idle handler.
6599 * Note that the @origin actor may be the stage, or a container; it
6600 * does not have to be a leaf node in the actor graph.
6602 * Toolkits embedding a #ClutterStage which require a redraw and
6603 * relayout cycle can stop the emission of this signal using the
6604 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6609 * on_redraw_complete (gpointer data)
6611 * ClutterStage *stage = data;
6613 * /* execute the Clutter drawing pipeline */
6614 * clutter_stage_ensure_redraw (stage);
6618 * on_stage_queue_redraw (ClutterStage *stage)
6620 * /* this prevents the default handler to run */
6621 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6623 * /* queue a redraw with the host toolkit and call
6624 * * a function when the redraw has been completed
6626 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6630 * <note><para>This signal is emitted before the Clutter paint
6631 * pipeline is executed. If you want to know when the pipeline has
6632 * been completed you should connect to the ::paint signal on the
6633 * Stage with g_signal_connect_after().</para></note>
6637 actor_signals[QUEUE_REDRAW] =
6638 g_signal_new (I_("queue-redraw"),
6639 G_TYPE_FROM_CLASS (object_class),
6642 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6644 _clutter_marshal_VOID__OBJECT,
6646 CLUTTER_TYPE_ACTOR);
6649 * ClutterActor::queue-relayout
6650 * @actor: the actor being queued for relayout
6652 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6653 * is called on an actor.
6655 * The default implementation for #ClutterActor chains up to the
6656 * parent actor and queues a relayout on the parent, thus "bubbling"
6657 * the relayout queue up through the actor graph.
6659 * The main purpose of this signal is to allow relayout to be propagated
6660 * properly in the procense of #ClutterClone actors. Applications will
6661 * not normally need to connect to this signal.
6665 actor_signals[QUEUE_RELAYOUT] =
6666 g_signal_new (I_("queue-relayout"),
6667 G_TYPE_FROM_CLASS (object_class),
6670 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6672 _clutter_marshal_VOID__VOID,
6676 * ClutterActor::event:
6677 * @actor: the actor which received the event
6678 * @event: a #ClutterEvent
6680 * The ::event signal is emitted each time an event is received
6681 * by the @actor. This signal will be emitted on every actor,
6682 * following the hierarchy chain, until it reaches the top-level
6683 * container (the #ClutterStage).
6685 * Return value: %TRUE if the event has been handled by the actor,
6686 * or %FALSE to continue the emission.
6690 actor_signals[EVENT] =
6691 g_signal_new (I_("event"),
6692 G_TYPE_FROM_CLASS (object_class),
6694 G_STRUCT_OFFSET (ClutterActorClass, event),
6695 _clutter_boolean_handled_accumulator, NULL,
6696 _clutter_marshal_BOOLEAN__BOXED,
6698 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6700 * ClutterActor::button-press-event:
6701 * @actor: the actor which received the event
6702 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6704 * The ::button-press-event signal is emitted each time a mouse button
6705 * is pressed on @actor.
6707 * Return value: %TRUE if the event has been handled by the actor,
6708 * or %FALSE to continue the emission.
6712 actor_signals[BUTTON_PRESS_EVENT] =
6713 g_signal_new (I_("button-press-event"),
6714 G_TYPE_FROM_CLASS (object_class),
6716 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6717 _clutter_boolean_handled_accumulator, NULL,
6718 _clutter_marshal_BOOLEAN__BOXED,
6720 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6722 * ClutterActor::button-release-event:
6723 * @actor: the actor which received the event
6724 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6726 * The ::button-release-event signal is emitted each time a mouse button
6727 * is released on @actor.
6729 * Return value: %TRUE if the event has been handled by the actor,
6730 * or %FALSE to continue the emission.
6734 actor_signals[BUTTON_RELEASE_EVENT] =
6735 g_signal_new (I_("button-release-event"),
6736 G_TYPE_FROM_CLASS (object_class),
6738 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6739 _clutter_boolean_handled_accumulator, NULL,
6740 _clutter_marshal_BOOLEAN__BOXED,
6742 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6744 * ClutterActor::scroll-event:
6745 * @actor: the actor which received the event
6746 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6748 * The ::scroll-event signal is emitted each time the mouse is
6749 * scrolled on @actor
6751 * Return value: %TRUE if the event has been handled by the actor,
6752 * or %FALSE to continue the emission.
6756 actor_signals[SCROLL_EVENT] =
6757 g_signal_new (I_("scroll-event"),
6758 G_TYPE_FROM_CLASS (object_class),
6760 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6761 _clutter_boolean_handled_accumulator, NULL,
6762 _clutter_marshal_BOOLEAN__BOXED,
6764 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6766 * ClutterActor::key-press-event:
6767 * @actor: the actor which received the event
6768 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6770 * The ::key-press-event signal is emitted each time a keyboard button
6771 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6773 * Return value: %TRUE if the event has been handled by the actor,
6774 * or %FALSE to continue the emission.
6778 actor_signals[KEY_PRESS_EVENT] =
6779 g_signal_new (I_("key-press-event"),
6780 G_TYPE_FROM_CLASS (object_class),
6782 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6783 _clutter_boolean_handled_accumulator, NULL,
6784 _clutter_marshal_BOOLEAN__BOXED,
6786 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6788 * ClutterActor::key-release-event:
6789 * @actor: the actor which received the event
6790 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6792 * The ::key-release-event signal is emitted each time a keyboard button
6793 * is released while @actor has key focus (see
6794 * clutter_stage_set_key_focus()).
6796 * Return value: %TRUE if the event has been handled by the actor,
6797 * or %FALSE to continue the emission.
6801 actor_signals[KEY_RELEASE_EVENT] =
6802 g_signal_new (I_("key-release-event"),
6803 G_TYPE_FROM_CLASS (object_class),
6805 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6806 _clutter_boolean_handled_accumulator, NULL,
6807 _clutter_marshal_BOOLEAN__BOXED,
6809 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6811 * ClutterActor::motion-event:
6812 * @actor: the actor which received the event
6813 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6815 * The ::motion-event signal is emitted each time the mouse pointer is
6816 * moved over @actor.
6818 * Return value: %TRUE if the event has been handled by the actor,
6819 * or %FALSE to continue the emission.
6823 actor_signals[MOTION_EVENT] =
6824 g_signal_new (I_("motion-event"),
6825 G_TYPE_FROM_CLASS (object_class),
6827 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6828 _clutter_boolean_handled_accumulator, NULL,
6829 _clutter_marshal_BOOLEAN__BOXED,
6831 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6834 * ClutterActor::key-focus-in:
6835 * @actor: the actor which now has key focus
6837 * The ::key-focus-in signal is emitted when @actor receives key focus.
6841 actor_signals[KEY_FOCUS_IN] =
6842 g_signal_new (I_("key-focus-in"),
6843 G_TYPE_FROM_CLASS (object_class),
6845 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6847 _clutter_marshal_VOID__VOID,
6851 * ClutterActor::key-focus-out:
6852 * @actor: the actor which now has key focus
6854 * The ::key-focus-out signal is emitted when @actor loses key focus.
6858 actor_signals[KEY_FOCUS_OUT] =
6859 g_signal_new (I_("key-focus-out"),
6860 G_TYPE_FROM_CLASS (object_class),
6862 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6864 _clutter_marshal_VOID__VOID,
6868 * ClutterActor::enter-event:
6869 * @actor: the actor which the pointer has entered.
6870 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6872 * The ::enter-event signal is emitted when the pointer enters the @actor
6874 * Return value: %TRUE if the event has been handled by the actor,
6875 * or %FALSE to continue the emission.
6879 actor_signals[ENTER_EVENT] =
6880 g_signal_new (I_("enter-event"),
6881 G_TYPE_FROM_CLASS (object_class),
6883 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6884 _clutter_boolean_handled_accumulator, NULL,
6885 _clutter_marshal_BOOLEAN__BOXED,
6887 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6890 * ClutterActor::leave-event:
6891 * @actor: the actor which the pointer has left
6892 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6894 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6896 * Return value: %TRUE if the event has been handled by the actor,
6897 * or %FALSE to continue the emission.
6901 actor_signals[LEAVE_EVENT] =
6902 g_signal_new (I_("leave-event"),
6903 G_TYPE_FROM_CLASS (object_class),
6905 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6906 _clutter_boolean_handled_accumulator, NULL,
6907 _clutter_marshal_BOOLEAN__BOXED,
6909 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6912 * ClutterActor::captured-event:
6913 * @actor: the actor which received the signal
6914 * @event: a #ClutterEvent
6916 * The ::captured-event signal is emitted when an event is captured
6917 * by Clutter. This signal will be emitted starting from the top-level
6918 * container (the #ClutterStage) to the actor which received the event
6919 * going down the hierarchy. This signal can be used to intercept every
6920 * event before the specialized events (like
6921 * ClutterActor::button-press-event or ::key-released-event) are
6924 * Return value: %TRUE if the event has been handled by the actor,
6925 * or %FALSE to continue the emission.
6929 actor_signals[CAPTURED_EVENT] =
6930 g_signal_new (I_("captured-event"),
6931 G_TYPE_FROM_CLASS (object_class),
6933 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6934 _clutter_boolean_handled_accumulator, NULL,
6935 _clutter_marshal_BOOLEAN__BOXED,
6937 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6940 * ClutterActor::paint:
6941 * @actor: the #ClutterActor that received the signal
6943 * The ::paint signal is emitted each time an actor is being painted.
6945 * Subclasses of #ClutterActor should override the class signal handler
6946 * and paint themselves in that function.
6948 * It is possible to connect a handler to the ::paint signal in order
6949 * to set up some custom aspect of a paint.
6953 actor_signals[PAINT] =
6954 g_signal_new (I_("paint"),
6955 G_TYPE_FROM_CLASS (object_class),
6958 G_STRUCT_OFFSET (ClutterActorClass, paint),
6960 _clutter_marshal_VOID__VOID,
6963 * ClutterActor::realize:
6964 * @actor: the #ClutterActor that received the signal
6966 * The ::realize signal is emitted each time an actor is being
6971 actor_signals[REALIZE] =
6972 g_signal_new (I_("realize"),
6973 G_TYPE_FROM_CLASS (object_class),
6975 G_STRUCT_OFFSET (ClutterActorClass, realize),
6977 _clutter_marshal_VOID__VOID,
6980 * ClutterActor::unrealize:
6981 * @actor: the #ClutterActor that received the signal
6983 * The ::unrealize signal is emitted each time an actor is being
6988 actor_signals[UNREALIZE] =
6989 g_signal_new (I_("unrealize"),
6990 G_TYPE_FROM_CLASS (object_class),
6992 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6994 _clutter_marshal_VOID__VOID,
6998 * ClutterActor::pick:
6999 * @actor: the #ClutterActor that received the signal
7000 * @color: the #ClutterColor to be used when picking
7002 * The ::pick signal is emitted each time an actor is being painted
7003 * in "pick mode". The pick mode is used to identify the actor during
7004 * the event handling phase, or by clutter_stage_get_actor_at_pos().
7005 * The actor should paint its shape using the passed @pick_color.
7007 * Subclasses of #ClutterActor should override the class signal handler
7008 * and paint themselves in that function.
7010 * It is possible to connect a handler to the ::pick signal in order
7011 * to set up some custom aspect of a paint in pick mode.
7015 actor_signals[PICK] =
7016 g_signal_new (I_("pick"),
7017 G_TYPE_FROM_CLASS (object_class),
7019 G_STRUCT_OFFSET (ClutterActorClass, pick),
7021 _clutter_marshal_VOID__BOXED,
7023 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7026 * ClutterActor::allocation-changed:
7027 * @actor: the #ClutterActor that emitted the signal
7028 * @box: a #ClutterActorBox with the new allocation
7029 * @flags: #ClutterAllocationFlags for the allocation
7031 * The ::allocation-changed signal is emitted when the
7032 * #ClutterActor:allocation property changes. Usually, application
7033 * code should just use the notifications for the :allocation property
7034 * but if you want to track the allocation flags as well, for instance
7035 * to know whether the absolute origin of @actor changed, then you might
7036 * want use this signal instead.
7040 actor_signals[ALLOCATION_CHANGED] =
7041 g_signal_new (I_("allocation-changed"),
7042 G_TYPE_FROM_CLASS (object_class),
7046 _clutter_marshal_VOID__BOXED_FLAGS,
7048 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7049 CLUTTER_TYPE_ALLOCATION_FLAGS);
7052 * ClutterActor::transitions-completed:
7053 * @actor: a #ClutterActor
7055 * The ::transitions-completed signal is emitted once all transitions
7056 * involving @actor are complete.
7060 actor_signals[TRANSITIONS_COMPLETED] =
7061 g_signal_new (I_("transitions-completed"),
7062 G_TYPE_FROM_CLASS (object_class),
7066 _clutter_marshal_VOID__VOID,
7071 clutter_actor_init (ClutterActor *self)
7073 ClutterActorPrivate *priv;
7075 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7077 priv->id = _clutter_context_acquire_id (self);
7080 priv->opacity = 0xff;
7081 priv->show_on_set_parent = TRUE;
7083 priv->needs_width_request = TRUE;
7084 priv->needs_height_request = TRUE;
7085 priv->needs_allocation = TRUE;
7087 priv->cached_width_age = 1;
7088 priv->cached_height_age = 1;
7090 priv->opacity_override = -1;
7091 priv->enable_model_view_transform = TRUE;
7093 /* Initialize an empty paint volume to start with */
7094 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7095 priv->last_paint_volume_valid = TRUE;
7097 priv->transform_valid = FALSE;
7099 /* the default is to stretch the content, to match the
7100 * current behaviour of basically all actors. also, it's
7101 * the easiest thing to compute.
7103 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7104 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7105 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7109 * clutter_actor_new:
7111 * Creates a new #ClutterActor.
7113 * A newly created actor has a floating reference, which will be sunk
7114 * when it is added to another actor.
7116 * Return value: (transfer full): the newly created #ClutterActor
7121 clutter_actor_new (void)
7123 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7127 * clutter_actor_destroy:
7128 * @self: a #ClutterActor
7130 * Destroys an actor. When an actor is destroyed, it will break any
7131 * references it holds to other objects. If the actor is inside a
7132 * container, the actor will be removed.
7134 * When you destroy a container, its children will be destroyed as well.
7136 * Note: you cannot destroy the #ClutterStage returned by
7137 * clutter_stage_get_default().
7140 clutter_actor_destroy (ClutterActor *self)
7142 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7144 g_object_ref (self);
7146 /* avoid recursion while destroying */
7147 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7149 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7151 g_object_run_dispose (G_OBJECT (self));
7153 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7156 g_object_unref (self);
7160 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7161 ClutterPaintVolume *clip)
7163 ClutterActorPrivate *priv = self->priv;
7164 ClutterPaintVolume *pv;
7167 /* Remove queue entry early in the process, otherwise a new
7168 queue_redraw() during signal handling could put back this
7169 object in the stage redraw list (but the entry is freed as
7170 soon as we return from this function, causing a segfault
7173 priv->queue_redraw_entry = NULL;
7175 /* If we've been explicitly passed a clip volume then there's
7176 * nothing more to calculate, but otherwise the only thing we know
7177 * is that the change is constrained to the given actor.
7179 * The idea is that if we know the paint volume for where the actor
7180 * was last drawn (in eye coordinates) and we also have the paint
7181 * volume for where it will be drawn next (in actor coordinates)
7182 * then if we queue a redraw for both these volumes that will cover
7183 * everything that needs to be redrawn to clear the old view and
7184 * show the latest view of the actor.
7186 * Don't clip this redraw if we don't know what position we had for
7187 * the previous redraw since we don't know where to set the clip so
7188 * it will clear the actor as it is currently.
7192 _clutter_actor_set_queue_redraw_clip (self, clip);
7195 else if (G_LIKELY (priv->last_paint_volume_valid))
7197 pv = _clutter_actor_get_paint_volume_mutable (self);
7200 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7202 /* make sure we redraw the actors old position... */
7203 _clutter_actor_set_queue_redraw_clip (stage,
7204 &priv->last_paint_volume);
7205 _clutter_actor_signal_queue_redraw (stage, stage);
7206 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7208 /* XXX: Ideally the redraw signal would take a clip volume
7209 * argument, but that would be an ABI break. Until we can
7210 * break the ABI we pass the argument out-of-band
7213 /* setup the clip for the actors new position... */
7214 _clutter_actor_set_queue_redraw_clip (self, pv);
7223 _clutter_actor_signal_queue_redraw (self, self);
7225 /* Just in case anyone is manually firing redraw signals without
7226 * using the public queue_redraw() API we are careful to ensure that
7227 * our out-of-band clip member is cleared before returning...
7229 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7231 if (G_LIKELY (clipped))
7232 _clutter_actor_set_queue_redraw_clip (self, NULL);
7236 _clutter_actor_get_allocation_clip (ClutterActor *self,
7237 ClutterActorBox *clip)
7239 ClutterActorBox allocation;
7241 /* XXX: we don't care if we get an out of date allocation here
7242 * because clutter_actor_queue_redraw_with_clip knows to ignore
7243 * the clip if the actor's allocation is invalid.
7245 * This is noted because clutter_actor_get_allocation_box does some
7246 * unnecessary work to support buggy code with a comment suggesting
7247 * that it could be changed later which would be good for this use
7250 clutter_actor_get_allocation_box (self, &allocation);
7252 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7253 * actor's own coordinate space but the allocation is in parent
7257 clip->x2 = allocation.x2 - allocation.x1;
7258 clip->y2 = allocation.y2 - allocation.y1;
7262 _clutter_actor_queue_redraw_full (ClutterActor *self,
7263 ClutterRedrawFlags flags,
7264 ClutterPaintVolume *volume,
7265 ClutterEffect *effect)
7267 ClutterActorPrivate *priv = self->priv;
7268 ClutterPaintVolume allocation_pv;
7269 ClutterPaintVolume *pv;
7270 gboolean should_free_pv;
7271 ClutterActor *stage;
7273 /* Here's an outline of the actor queue redraw mechanism:
7275 * The process starts in one of the following two functions which
7276 * are wrappers for this function:
7277 * clutter_actor_queue_redraw
7278 * _clutter_actor_queue_redraw_with_clip
7280 * additionally, an effect can queue a redraw by wrapping this
7281 * function in clutter_effect_queue_rerun
7283 * This functions queues an entry in a list associated with the
7284 * stage which is a list of actors that queued a redraw while
7285 * updating the timelines, performing layouting and processing other
7286 * mainloop sources before the next paint starts.
7288 * We aim to minimize the processing done at this point because
7289 * there is a good chance other events will happen while updating
7290 * the scenegraph that would invalidate any expensive work we might
7291 * otherwise try to do here. For example we don't try and resolve
7292 * the screen space bounding box of an actor at this stage so as to
7293 * minimize how much of the screen redraw because it's possible
7294 * something else will happen which will force a full redraw anyway.
7296 * When all updates are complete and we come to paint the stage then
7297 * we iterate this list and actually emit the "queue-redraw" signals
7298 * for each of the listed actors which will bubble up to the stage
7299 * for each actor and at that point we will transform the actors
7300 * paint volume into screen coordinates to determine the clip region
7301 * for what needs to be redrawn in the next paint.
7303 * Besides minimizing redundant work another reason for this
7304 * deferred design is that it's more likely we will be able to
7305 * determine the paint volume of an actor once we've finished
7306 * updating the scenegraph because its allocation should be up to
7307 * date. NB: If we can't determine an actors paint volume then we
7308 * can't automatically queue a clipped redraw which can make a big
7309 * difference to performance.
7311 * So the control flow goes like this:
7312 * One of clutter_actor_queue_redraw,
7313 * _clutter_actor_queue_redraw_with_clip
7314 * or clutter_effect_queue_rerun
7316 * then control moves to:
7317 * _clutter_stage_queue_actor_redraw
7319 * later during _clutter_stage_do_update, once relayouting is done
7320 * and the scenegraph has been updated we will call:
7321 * _clutter_stage_finish_queue_redraws
7323 * _clutter_stage_finish_queue_redraws will call
7324 * _clutter_actor_finish_queue_redraw for each listed actor.
7325 * Note: actors *are* allowed to queue further redraws during this
7326 * process (considering clone actors or texture_new_from_actor which
7327 * respond to their source queueing a redraw by queuing a redraw
7328 * themselves). We repeat the process until the list is empty.
7330 * This will result in the "queue-redraw" signal being fired for
7331 * each actor which will pass control to the default signal handler:
7332 * clutter_actor_real_queue_redraw
7334 * This will bubble up to the stages handler:
7335 * clutter_stage_real_queue_redraw
7337 * clutter_stage_real_queue_redraw will transform the actors paint
7338 * volume into screen space and add it as a clip region for the next
7342 /* ignore queueing a redraw for actors being destroyed */
7343 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7346 stage = _clutter_actor_get_stage_internal (self);
7348 /* Ignore queueing a redraw for actors not descended from a stage */
7352 /* ignore queueing a redraw on stages that are being destroyed */
7353 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7356 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7358 ClutterActorBox allocation_clip;
7359 ClutterVertex origin;
7361 /* If the actor doesn't have a valid allocation then we will
7362 * queue a full stage redraw. */
7363 if (priv->needs_allocation)
7365 /* NB: NULL denotes an undefined clip which will result in a
7367 _clutter_actor_set_queue_redraw_clip (self, NULL);
7368 _clutter_actor_signal_queue_redraw (self, self);
7372 _clutter_paint_volume_init_static (&allocation_pv, self);
7373 pv = &allocation_pv;
7375 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7377 origin.x = allocation_clip.x1;
7378 origin.y = allocation_clip.y1;
7380 clutter_paint_volume_set_origin (pv, &origin);
7381 clutter_paint_volume_set_width (pv,
7382 allocation_clip.x2 - allocation_clip.x1);
7383 clutter_paint_volume_set_height (pv,
7384 allocation_clip.y2 -
7385 allocation_clip.y1);
7386 should_free_pv = TRUE;
7391 should_free_pv = FALSE;
7394 self->priv->queue_redraw_entry =
7395 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7396 priv->queue_redraw_entry,
7401 clutter_paint_volume_free (pv);
7403 /* If this is the first redraw queued then we can directly use the
7405 if (!priv->is_dirty)
7406 priv->effect_to_redraw = effect;
7407 /* Otherwise we need to merge it with the existing effect parameter */
7408 else if (effect != NULL)
7410 /* If there's already an effect then we need to use whichever is
7411 later in the chain of actors. Otherwise a full redraw has
7412 already been queued on the actor so we need to ignore the
7414 if (priv->effect_to_redraw != NULL)
7416 if (priv->effects == NULL)
7417 g_warning ("Redraw queued with an effect that is "
7418 "not applied to the actor");
7423 for (l = _clutter_meta_group_peek_metas (priv->effects);
7427 if (l->data == priv->effect_to_redraw ||
7429 priv->effect_to_redraw = l->data;
7436 /* If no effect is specified then we need to redraw the whole
7438 priv->effect_to_redraw = NULL;
7441 priv->is_dirty = TRUE;
7445 * clutter_actor_queue_redraw:
7446 * @self: A #ClutterActor
7448 * Queues up a redraw of an actor and any children. The redraw occurs
7449 * once the main loop becomes idle (after the current batch of events
7450 * has been processed, roughly).
7452 * Applications rarely need to call this, as redraws are handled
7453 * automatically by modification functions.
7455 * This function will not do anything if @self is not visible, or
7456 * if the actor is inside an invisible part of the scenegraph.
7458 * Also be aware that painting is a NOP for actors with an opacity of
7461 * When you are implementing a custom actor you must queue a redraw
7462 * whenever some private state changes that will affect painting or
7463 * picking of your actor.
7466 clutter_actor_queue_redraw (ClutterActor *self)
7468 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7470 _clutter_actor_queue_redraw_full (self,
7472 NULL, /* clip volume */
7477 * _clutter_actor_queue_redraw_with_clip:
7478 * @self: A #ClutterActor
7479 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7480 * this queue redraw.
7481 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7482 * redrawn or %NULL if you are just using a @flag to state your
7485 * Queues up a clipped redraw of an actor and any children. The redraw
7486 * occurs once the main loop becomes idle (after the current batch of
7487 * events has been processed, roughly).
7489 * If no flags are given the clip volume is defined by @volume
7490 * specified in actor coordinates and tells Clutter that only content
7491 * within this volume has been changed so Clutter can optionally
7492 * optimize the redraw.
7494 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7495 * should be %NULL and this tells Clutter to use the actor's current
7496 * allocation as a clip box. This flag can only be used for 2D actors,
7497 * because any actor with depth may be projected outside its
7500 * Applications rarely need to call this, as redraws are handled
7501 * automatically by modification functions.
7503 * This function will not do anything if @self is not visible, or if
7504 * the actor is inside an invisible part of the scenegraph.
7506 * Also be aware that painting is a NOP for actors with an opacity of
7509 * When you are implementing a custom actor you must queue a redraw
7510 * whenever some private state changes that will affect painting or
7511 * picking of your actor.
7514 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7515 ClutterRedrawFlags flags,
7516 ClutterPaintVolume *volume)
7518 _clutter_actor_queue_redraw_full (self,
7520 volume, /* clip volume */
7525 _clutter_actor_queue_only_relayout (ClutterActor *self)
7527 ClutterActorPrivate *priv = self->priv;
7529 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7532 if (priv->needs_width_request &&
7533 priv->needs_height_request &&
7534 priv->needs_allocation)
7535 return; /* save some cpu cycles */
7537 #if CLUTTER_ENABLE_DEBUG
7538 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7540 g_warning ("The actor '%s' is currently inside an allocation "
7541 "cycle; calling clutter_actor_queue_relayout() is "
7543 _clutter_actor_get_debug_name (self));
7545 #endif /* CLUTTER_ENABLE_DEBUG */
7547 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7551 * clutter_actor_queue_redraw_with_clip:
7552 * @self: a #ClutterActor
7553 * @clip: (allow-none): a rectangular clip region, or %NULL
7555 * Queues a redraw on @self limited to a specific, actor-relative
7558 * If @clip is %NULL this function is equivalent to
7559 * clutter_actor_queue_redraw().
7564 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7565 const cairo_rectangle_int_t *clip)
7567 ClutterPaintVolume volume;
7568 ClutterVertex origin;
7570 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7574 clutter_actor_queue_redraw (self);
7578 _clutter_paint_volume_init_static (&volume, self);
7584 clutter_paint_volume_set_origin (&volume, &origin);
7585 clutter_paint_volume_set_width (&volume, clip->width);
7586 clutter_paint_volume_set_height (&volume, clip->height);
7588 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7590 clutter_paint_volume_free (&volume);
7594 * clutter_actor_queue_relayout:
7595 * @self: A #ClutterActor
7597 * Indicates that the actor's size request or other layout-affecting
7598 * properties may have changed. This function is used inside #ClutterActor
7599 * subclass implementations, not by applications directly.
7601 * Queueing a new layout automatically queues a redraw as well.
7606 clutter_actor_queue_relayout (ClutterActor *self)
7608 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7610 _clutter_actor_queue_only_relayout (self);
7611 clutter_actor_queue_redraw (self);
7615 * clutter_actor_get_preferred_size:
7616 * @self: a #ClutterActor
7617 * @min_width_p: (out) (allow-none): return location for the minimum
7619 * @min_height_p: (out) (allow-none): return location for the minimum
7621 * @natural_width_p: (out) (allow-none): return location for the natural
7623 * @natural_height_p: (out) (allow-none): return location for the natural
7626 * Computes the preferred minimum and natural size of an actor, taking into
7627 * account the actor's geometry management (either height-for-width
7628 * or width-for-height).
7630 * The width and height used to compute the preferred height and preferred
7631 * width are the actor's natural ones.
7633 * If you need to control the height for the preferred width, or the width for
7634 * the preferred height, you should use clutter_actor_get_preferred_width()
7635 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7636 * geometry management using the #ClutterActor:request-mode property.
7641 clutter_actor_get_preferred_size (ClutterActor *self,
7642 gfloat *min_width_p,
7643 gfloat *min_height_p,
7644 gfloat *natural_width_p,
7645 gfloat *natural_height_p)
7647 ClutterActorPrivate *priv;
7648 gfloat min_width, min_height;
7649 gfloat natural_width, natural_height;
7651 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7655 min_width = min_height = 0;
7656 natural_width = natural_height = 0;
7658 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7660 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7661 clutter_actor_get_preferred_width (self, -1,
7664 clutter_actor_get_preferred_height (self, natural_width,
7670 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7671 clutter_actor_get_preferred_height (self, -1,
7674 clutter_actor_get_preferred_width (self, natural_height,
7680 *min_width_p = min_width;
7683 *min_height_p = min_height;
7685 if (natural_width_p)
7686 *natural_width_p = natural_width;
7688 if (natural_height_p)
7689 *natural_height_p = natural_height;
7694 * @align: a #ClutterActorAlign
7695 * @direction: a #ClutterTextDirection
7697 * Retrieves the correct alignment depending on the text direction
7699 * Return value: the effective alignment
7701 static ClutterActorAlign
7702 effective_align (ClutterActorAlign align,
7703 ClutterTextDirection direction)
7705 ClutterActorAlign res;
7709 case CLUTTER_ACTOR_ALIGN_START:
7710 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7711 ? CLUTTER_ACTOR_ALIGN_END
7712 : CLUTTER_ACTOR_ALIGN_START;
7715 case CLUTTER_ACTOR_ALIGN_END:
7716 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7717 ? CLUTTER_ACTOR_ALIGN_START
7718 : CLUTTER_ACTOR_ALIGN_END;
7730 adjust_for_margin (float margin_start,
7732 float *minimum_size,
7733 float *natural_size,
7734 float *allocated_start,
7735 float *allocated_end)
7737 *minimum_size -= (margin_start + margin_end);
7738 *natural_size -= (margin_start + margin_end);
7739 *allocated_start += margin_start;
7740 *allocated_end -= margin_end;
7744 adjust_for_alignment (ClutterActorAlign alignment,
7746 float *allocated_start,
7747 float *allocated_end)
7749 float allocated_size = *allocated_end - *allocated_start;
7753 case CLUTTER_ACTOR_ALIGN_FILL:
7757 case CLUTTER_ACTOR_ALIGN_START:
7759 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7762 case CLUTTER_ACTOR_ALIGN_END:
7763 if (allocated_size > natural_size)
7765 *allocated_start += (allocated_size - natural_size);
7766 *allocated_end = *allocated_start + natural_size;
7770 case CLUTTER_ACTOR_ALIGN_CENTER:
7771 if (allocated_size > natural_size)
7773 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7774 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7781 * clutter_actor_adjust_width:
7782 * @self: a #ClutterActor
7783 * @minimum_width: (inout): the actor's preferred minimum width, which
7784 * will be adjusted depending on the margin
7785 * @natural_width: (inout): the actor's preferred natural width, which
7786 * will be adjusted depending on the margin
7787 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7788 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7790 * Adjusts the preferred and allocated position and size of an actor,
7791 * depending on the margin and alignment properties.
7794 clutter_actor_adjust_width (ClutterActor *self,
7795 gfloat *minimum_width,
7796 gfloat *natural_width,
7797 gfloat *adjusted_x1,
7798 gfloat *adjusted_x2)
7800 ClutterTextDirection text_dir;
7801 const ClutterLayoutInfo *info;
7803 info = _clutter_actor_get_layout_info_or_defaults (self);
7804 text_dir = clutter_actor_get_text_direction (self);
7806 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7808 /* this will tweak natural_width to remove the margin, so that
7809 * adjust_for_alignment() will use the correct size
7811 adjust_for_margin (info->margin.left, info->margin.right,
7812 minimum_width, natural_width,
7813 adjusted_x1, adjusted_x2);
7815 adjust_for_alignment (effective_align (info->x_align, text_dir),
7817 adjusted_x1, adjusted_x2);
7821 * clutter_actor_adjust_height:
7822 * @self: a #ClutterActor
7823 * @minimum_height: (inout): the actor's preferred minimum height, which
7824 * will be adjusted depending on the margin
7825 * @natural_height: (inout): the actor's preferred natural height, which
7826 * will be adjusted depending on the margin
7827 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7828 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7830 * Adjusts the preferred and allocated position and size of an actor,
7831 * depending on the margin and alignment properties.
7834 clutter_actor_adjust_height (ClutterActor *self,
7835 gfloat *minimum_height,
7836 gfloat *natural_height,
7837 gfloat *adjusted_y1,
7838 gfloat *adjusted_y2)
7840 const ClutterLayoutInfo *info;
7842 info = _clutter_actor_get_layout_info_or_defaults (self);
7844 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7846 /* this will tweak natural_height to remove the margin, so that
7847 * adjust_for_alignment() will use the correct size
7849 adjust_for_margin (info->margin.top, info->margin.bottom,
7850 minimum_height, natural_height,
7854 /* we don't use effective_align() here, because text direction
7855 * only affects the horizontal axis
7857 adjust_for_alignment (info->y_align,
7864 /* looks for a cached size request for this for_size. If not
7865 * found, returns the oldest entry so it can be overwritten */
7867 _clutter_actor_get_cached_size_request (gfloat for_size,
7868 SizeRequest *cached_size_requests,
7869 SizeRequest **result)
7873 *result = &cached_size_requests[0];
7875 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7879 sr = &cached_size_requests[i];
7882 sr->for_size == for_size)
7884 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7888 else if (sr->age < (*result)->age)
7894 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7900 * clutter_actor_get_preferred_width:
7901 * @self: A #ClutterActor
7902 * @for_height: available height when computing the preferred width,
7903 * or a negative value to indicate that no height is defined
7904 * @min_width_p: (out) (allow-none): return location for minimum width,
7906 * @natural_width_p: (out) (allow-none): return location for the natural
7909 * Computes the requested minimum and natural widths for an actor,
7910 * optionally depending on the specified height, or if they are
7911 * already computed, returns the cached values.
7913 * An actor may not get its request - depending on the layout
7914 * manager that's in effect.
7916 * A request should not incorporate the actor's scale or anchor point;
7917 * those transformations do not affect layout, only rendering.
7922 clutter_actor_get_preferred_width (ClutterActor *self,
7924 gfloat *min_width_p,
7925 gfloat *natural_width_p)
7927 float request_min_width, request_natural_width;
7928 SizeRequest *cached_size_request;
7929 const ClutterLayoutInfo *info;
7930 ClutterActorPrivate *priv;
7931 gboolean found_in_cache;
7933 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7937 info = _clutter_actor_get_layout_info_or_defaults (self);
7939 /* we shortcircuit the case of a fixed size set using set_width() */
7940 if (priv->min_width_set && priv->natural_width_set)
7942 if (min_width_p != NULL)
7943 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7945 if (natural_width_p != NULL)
7946 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7951 /* the remaining cases are:
7953 * - either min_width or natural_width have been set
7954 * - neither min_width or natural_width have been set
7956 * in both cases, we go through the cache (and through the actor in case
7957 * of cache misses) and determine the authoritative value depending on
7961 if (!priv->needs_width_request)
7964 _clutter_actor_get_cached_size_request (for_height,
7965 priv->width_requests,
7966 &cached_size_request);
7970 /* if the actor needs a width request we use the first slot */
7971 found_in_cache = FALSE;
7972 cached_size_request = &priv->width_requests[0];
7975 if (!found_in_cache)
7977 gfloat minimum_width, natural_width;
7978 ClutterActorClass *klass;
7980 minimum_width = natural_width = 0;
7982 /* adjust for the margin */
7983 if (for_height >= 0)
7985 for_height -= (info->margin.top + info->margin.bottom);
7990 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7992 klass = CLUTTER_ACTOR_GET_CLASS (self);
7993 klass->get_preferred_width (self, for_height,
7997 /* adjust for the margin */
7998 minimum_width += (info->margin.left + info->margin.right);
7999 natural_width += (info->margin.left + info->margin.right);
8001 /* Due to accumulated float errors, it's better not to warn
8002 * on this, but just fix it.
8004 if (natural_width < minimum_width)
8005 natural_width = minimum_width;
8007 cached_size_request->min_size = minimum_width;
8008 cached_size_request->natural_size = natural_width;
8009 cached_size_request->for_size = for_height;
8010 cached_size_request->age = priv->cached_width_age;
8012 priv->cached_width_age += 1;
8013 priv->needs_width_request = FALSE;
8016 if (!priv->min_width_set)
8017 request_min_width = cached_size_request->min_size;
8019 request_min_width = info->min_width;
8021 if (!priv->natural_width_set)
8022 request_natural_width = cached_size_request->natural_size;
8024 request_natural_width = info->natural_width;
8027 *min_width_p = request_min_width;
8029 if (natural_width_p)
8030 *natural_width_p = request_natural_width;
8034 * clutter_actor_get_preferred_height:
8035 * @self: A #ClutterActor
8036 * @for_width: available width to assume in computing desired height,
8037 * or a negative value to indicate that no width is defined
8038 * @min_height_p: (out) (allow-none): return location for minimum height,
8040 * @natural_height_p: (out) (allow-none): return location for natural
8043 * Computes the requested minimum and natural heights for an actor,
8044 * or if they are already computed, returns the cached values.
8046 * An actor may not get its request - depending on the layout
8047 * manager that's in effect.
8049 * A request should not incorporate the actor's scale or anchor point;
8050 * those transformations do not affect layout, only rendering.
8055 clutter_actor_get_preferred_height (ClutterActor *self,
8057 gfloat *min_height_p,
8058 gfloat *natural_height_p)
8060 float request_min_height, request_natural_height;
8061 SizeRequest *cached_size_request;
8062 const ClutterLayoutInfo *info;
8063 ClutterActorPrivate *priv;
8064 gboolean found_in_cache;
8066 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8070 info = _clutter_actor_get_layout_info_or_defaults (self);
8072 /* we shortcircuit the case of a fixed size set using set_height() */
8073 if (priv->min_height_set && priv->natural_height_set)
8075 if (min_height_p != NULL)
8076 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
8078 if (natural_height_p != NULL)
8079 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
8084 /* the remaining cases are:
8086 * - either min_height or natural_height have been set
8087 * - neither min_height or natural_height have been set
8089 * in both cases, we go through the cache (and through the actor in case
8090 * of cache misses) and determine the authoritative value depending on
8094 if (!priv->needs_height_request)
8097 _clutter_actor_get_cached_size_request (for_width,
8098 priv->height_requests,
8099 &cached_size_request);
8103 found_in_cache = FALSE;
8104 cached_size_request = &priv->height_requests[0];
8107 if (!found_in_cache)
8109 gfloat minimum_height, natural_height;
8110 ClutterActorClass *klass;
8112 minimum_height = natural_height = 0;
8114 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8116 /* adjust for margin */
8119 for_width -= (info->margin.left + info->margin.right);
8124 klass = CLUTTER_ACTOR_GET_CLASS (self);
8125 klass->get_preferred_height (self, for_width,
8129 /* adjust for margin */
8130 minimum_height += (info->margin.top + info->margin.bottom);
8131 natural_height += (info->margin.top + info->margin.bottom);
8133 /* Due to accumulated float errors, it's better not to warn
8134 * on this, but just fix it.
8136 if (natural_height < minimum_height)
8137 natural_height = minimum_height;
8139 cached_size_request->min_size = minimum_height;
8140 cached_size_request->natural_size = natural_height;
8141 cached_size_request->for_size = for_width;
8142 cached_size_request->age = priv->cached_height_age;
8144 priv->cached_height_age += 1;
8145 priv->needs_height_request = FALSE;
8148 if (!priv->min_height_set)
8149 request_min_height = cached_size_request->min_size;
8151 request_min_height = info->min_height;
8153 if (!priv->natural_height_set)
8154 request_natural_height = cached_size_request->natural_size;
8156 request_natural_height = info->natural_height;
8159 *min_height_p = request_min_height;
8161 if (natural_height_p)
8162 *natural_height_p = request_natural_height;
8166 * clutter_actor_get_allocation_box:
8167 * @self: A #ClutterActor
8168 * @box: (out): the function fills this in with the actor's allocation
8170 * Gets the layout box an actor has been assigned. The allocation can
8171 * only be assumed valid inside a paint() method; anywhere else, it
8172 * may be out-of-date.
8174 * An allocation does not incorporate the actor's scale or anchor point;
8175 * those transformations do not affect layout, only rendering.
8177 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8178 * of functions inside the implementation of the get_preferred_width()
8179 * or get_preferred_height() virtual functions.</note>
8184 clutter_actor_get_allocation_box (ClutterActor *self,
8185 ClutterActorBox *box)
8187 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8189 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8190 * which limits calling get_allocation to inside paint() basically; or
8191 * we can 2) force a layout, which could be expensive if someone calls
8192 * get_allocation somewhere silly; or we can 3) just return the latest
8193 * value, allowing it to be out-of-date, and assume people know what
8196 * The least-surprises approach that keeps existing code working is
8197 * likely to be 2). People can end up doing some inefficient things,
8198 * though, and in general code that requires 2) is probably broken.
8201 /* this implements 2) */
8202 if (G_UNLIKELY (self->priv->needs_allocation))
8204 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8206 /* do not queue a relayout on an unparented actor */
8208 _clutter_stage_maybe_relayout (stage);
8211 /* commenting out the code above and just keeping this assigment
8214 *box = self->priv->allocation;
8218 * clutter_actor_get_allocation_geometry:
8219 * @self: A #ClutterActor
8220 * @geom: (out): allocation geometry in pixels
8222 * Gets the layout box an actor has been assigned. The allocation can
8223 * only be assumed valid inside a paint() method; anywhere else, it
8224 * may be out-of-date.
8226 * An allocation does not incorporate the actor's scale or anchor point;
8227 * those transformations do not affect layout, only rendering.
8229 * The returned rectangle is in pixels.
8234 clutter_actor_get_allocation_geometry (ClutterActor *self,
8235 ClutterGeometry *geom)
8237 ClutterActorBox box;
8239 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8240 g_return_if_fail (geom != NULL);
8242 clutter_actor_get_allocation_box (self, &box);
8244 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8245 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8246 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8247 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8251 clutter_actor_update_constraints (ClutterActor *self,
8252 ClutterActorBox *allocation)
8254 ClutterActorPrivate *priv = self->priv;
8255 const GList *constraints, *l;
8257 if (priv->constraints == NULL)
8260 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8261 for (l = constraints; l != NULL; l = l->next)
8263 ClutterConstraint *constraint = l->data;
8264 ClutterActorMeta *meta = l->data;
8266 if (clutter_actor_meta_get_enabled (meta))
8268 _clutter_constraint_update_allocation (constraint,
8272 CLUTTER_NOTE (LAYOUT,
8273 "Allocation of '%s' after constraint '%s': "
8274 "{ %.2f, %.2f, %.2f, %.2f }",
8275 _clutter_actor_get_debug_name (self),
8276 _clutter_actor_meta_get_debug_name (meta),
8286 * clutter_actor_adjust_allocation:
8287 * @self: a #ClutterActor
8288 * @allocation: (inout): the allocation to adjust
8290 * Adjusts the passed allocation box taking into account the actor's
8291 * layout information, like alignment, expansion, and margin.
8294 clutter_actor_adjust_allocation (ClutterActor *self,
8295 ClutterActorBox *allocation)
8297 ClutterActorBox adj_allocation;
8298 float alloc_width, alloc_height;
8299 float min_width, min_height;
8300 float nat_width, nat_height;
8301 ClutterRequestMode req_mode;
8303 adj_allocation = *allocation;
8305 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8307 /* we want to hit the cache, so we use the public API */
8308 req_mode = clutter_actor_get_request_mode (self);
8310 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8312 clutter_actor_get_preferred_width (self, -1,
8315 clutter_actor_get_preferred_height (self, alloc_width,
8319 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8321 clutter_actor_get_preferred_height (self, -1,
8324 clutter_actor_get_preferred_height (self, alloc_height,
8329 #ifdef CLUTTER_ENABLE_DEBUG
8330 /* warn about underallocations */
8331 if (_clutter_diagnostic_enabled () &&
8332 (floorf (min_width - alloc_width) > 0 ||
8333 floorf (min_height - alloc_height) > 0))
8335 ClutterActor *parent = clutter_actor_get_parent (self);
8337 /* the only actors that are allowed to be underallocated are the Stage,
8338 * as it doesn't have an implicit size, and Actors that specifically
8339 * told us that they want to opt-out from layout control mechanisms
8340 * through the NO_LAYOUT escape hatch.
8342 if (parent != NULL &&
8343 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8345 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8346 "of %.2f x %.2f from its parent actor '%s', but its "
8347 "requested minimum size is of %.2f x %.2f",
8348 _clutter_actor_get_debug_name (self),
8349 alloc_width, alloc_height,
8350 _clutter_actor_get_debug_name (parent),
8351 min_width, min_height);
8356 clutter_actor_adjust_width (self,
8360 &adj_allocation.x2);
8362 clutter_actor_adjust_height (self,
8366 &adj_allocation.y2);
8368 /* we maintain the invariant that an allocation cannot be adjusted
8369 * to be outside the parent-given box
8371 if (adj_allocation.x1 < allocation->x1 ||
8372 adj_allocation.y1 < allocation->y1 ||
8373 adj_allocation.x2 > allocation->x2 ||
8374 adj_allocation.y2 > allocation->y2)
8376 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8377 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8378 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8379 _clutter_actor_get_debug_name (self),
8380 adj_allocation.x1, adj_allocation.y1,
8381 adj_allocation.x2 - adj_allocation.x1,
8382 adj_allocation.y2 - adj_allocation.y1,
8383 allocation->x1, allocation->y1,
8384 allocation->x2 - allocation->x1,
8385 allocation->y2 - allocation->y1);
8389 *allocation = adj_allocation;
8393 * clutter_actor_allocate:
8394 * @self: A #ClutterActor
8395 * @box: new allocation of the actor, in parent-relative coordinates
8396 * @flags: flags that control the allocation
8398 * Called by the parent of an actor to assign the actor its size.
8399 * Should never be called by applications (except when implementing
8400 * a container or layout manager).
8402 * Actors can know from their allocation box whether they have moved
8403 * with respect to their parent actor. The @flags parameter describes
8404 * additional information about the allocation, for instance whether
8405 * the parent has moved with respect to the stage, for example because
8406 * a grandparent's origin has moved.
8411 clutter_actor_allocate (ClutterActor *self,
8412 const ClutterActorBox *box,
8413 ClutterAllocationFlags flags)
8415 ClutterActorPrivate *priv;
8416 ClutterActorClass *klass;
8417 ClutterActorBox old_allocation, real_allocation;
8418 gboolean origin_changed, child_moved, size_changed;
8419 gboolean stage_allocation_changed;
8421 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8422 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8424 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8425 "which isn't a descendent of the stage!\n",
8426 self, _clutter_actor_get_debug_name (self));
8432 old_allocation = priv->allocation;
8433 real_allocation = *box;
8435 /* constraints are allowed to modify the allocation only here; we do
8436 * this prior to all the other checks so that we can bail out if the
8437 * allocation did not change
8439 clutter_actor_update_constraints (self, &real_allocation);
8441 /* adjust the allocation depending on the align/margin properties */
8442 clutter_actor_adjust_allocation (self, &real_allocation);
8444 if (real_allocation.x2 < real_allocation.x1 ||
8445 real_allocation.y2 < real_allocation.y1)
8447 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8448 _clutter_actor_get_debug_name (self),
8449 real_allocation.x2 - real_allocation.x1,
8450 real_allocation.y2 - real_allocation.y1);
8453 /* we allow 0-sized actors, but not negative-sized ones */
8454 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8455 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8457 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8459 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8460 real_allocation.y1 != old_allocation.y1);
8462 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8463 real_allocation.y2 != old_allocation.y2);
8465 if (origin_changed || child_moved || size_changed)
8466 stage_allocation_changed = TRUE;
8468 stage_allocation_changed = FALSE;
8470 /* If we get an allocation "out of the blue"
8471 * (we did not queue relayout), then we want to
8472 * ignore it. But if we have needs_allocation set,
8473 * we want to guarantee that allocate() virtual
8474 * method is always called, i.e. that queue_relayout()
8475 * always results in an allocate() invocation on
8478 * The optimization here is to avoid re-allocating
8479 * actors that did not queue relayout and were
8482 if (!priv->needs_allocation && !stage_allocation_changed)
8484 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8488 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8489 * clutter_actor_allocate(), it indicates whether the parent has its
8490 * absolute origin moved; when passed in to ClutterActor::allocate()
8491 * virtual method though, it indicates whether the child has its
8492 * absolute origin moved. So we set it when child_moved is TRUE
8495 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8497 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8499 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8500 _clutter_actor_get_debug_name (self));
8502 klass = CLUTTER_ACTOR_GET_CLASS (self);
8503 klass->allocate (self, &real_allocation, flags);
8505 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8507 if (stage_allocation_changed)
8508 clutter_actor_queue_redraw (self);
8512 * clutter_actor_set_allocation:
8513 * @self: a #ClutterActor
8514 * @box: a #ClutterActorBox
8515 * @flags: allocation flags
8517 * Stores the allocation of @self as defined by @box.
8519 * This function can only be called from within the implementation of
8520 * the #ClutterActorClass.allocate() virtual function.
8522 * The allocation should have been adjusted to take into account constraints,
8523 * alignment, and margin properties. If you are implementing a #ClutterActor
8524 * subclass that provides its own layout management policy for its children
8525 * instead of using a #ClutterLayoutManager delegate, you should not call
8526 * this function on the children of @self; instead, you should call
8527 * clutter_actor_allocate(), which will adjust the allocation box for
8530 * This function should only be used by subclasses of #ClutterActor
8531 * that wish to store their allocation but cannot chain up to the
8532 * parent's implementation; the default implementation of the
8533 * #ClutterActorClass.allocate() virtual function will call this
8536 * It is important to note that, while chaining up was the recommended
8537 * behaviour for #ClutterActor subclasses prior to the introduction of
8538 * this function, it is recommended to call clutter_actor_set_allocation()
8541 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8542 * to handle the allocation of its children, this function will call
8543 * the clutter_layout_manager_allocate() function only if the
8544 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8545 * expected that the subclass will call clutter_layout_manager_allocate()
8546 * by itself. For instance, the following code:
8550 * my_actor_allocate (ClutterActor *actor,
8551 * const ClutterActorBox *allocation,
8552 * ClutterAllocationFlags flags)
8554 * ClutterActorBox new_alloc;
8555 * ClutterAllocationFlags new_flags;
8557 * adjust_allocation (allocation, &new_alloc);
8559 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8561 * /* this will use the layout manager set on the actor */
8562 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8566 * is equivalent to this:
8570 * my_actor_allocate (ClutterActor *actor,
8571 * const ClutterActorBox *allocation,
8572 * ClutterAllocationFlags flags)
8574 * ClutterLayoutManager *layout;
8575 * ClutterActorBox new_alloc;
8577 * adjust_allocation (allocation, &new_alloc);
8579 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8581 * layout = clutter_actor_get_layout_manager (actor);
8582 * clutter_layout_manager_allocate (layout,
8583 * CLUTTER_CONTAINER (actor),
8592 clutter_actor_set_allocation (ClutterActor *self,
8593 const ClutterActorBox *box,
8594 ClutterAllocationFlags flags)
8596 ClutterActorPrivate *priv;
8599 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8600 g_return_if_fail (box != NULL);
8602 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8604 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8605 "can only be called from within the implementation of "
8606 "the ClutterActor::allocate() virtual function.");
8612 g_object_freeze_notify (G_OBJECT (self));
8614 changed = clutter_actor_set_allocation_internal (self, box, flags);
8616 /* we allocate our children before we notify changes in our geometry,
8617 * so that people connecting to properties will be able to get valid
8618 * data out of the sub-tree of the scene graph that has this actor at
8621 clutter_actor_maybe_layout_children (self, box, flags);
8625 ClutterActorBox signal_box = priv->allocation;
8626 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8628 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8633 g_object_thaw_notify (G_OBJECT (self));
8637 * clutter_actor_set_geometry:
8638 * @self: A #ClutterActor
8639 * @geometry: A #ClutterGeometry
8641 * Sets the actor's fixed position and forces its minimum and natural
8642 * size, in pixels. This means the untransformed actor will have the
8643 * given geometry. This is the same as calling clutter_actor_set_position()
8644 * and clutter_actor_set_size().
8646 * Deprecated: 1.10: Use clutter_actor_set_position() and
8647 * clutter_actor_set_size() instead.
8650 clutter_actor_set_geometry (ClutterActor *self,
8651 const ClutterGeometry *geometry)
8653 g_object_freeze_notify (G_OBJECT (self));
8655 clutter_actor_set_position (self, geometry->x, geometry->y);
8656 clutter_actor_set_size (self, geometry->width, geometry->height);
8658 g_object_thaw_notify (G_OBJECT (self));
8662 * clutter_actor_get_geometry:
8663 * @self: A #ClutterActor
8664 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8666 * Gets the size and position of an actor relative to its parent
8667 * actor. This is the same as calling clutter_actor_get_position() and
8668 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8669 * requested size and position if the actor's allocation is invalid.
8671 * Deprecated: 1.10: Use clutter_actor_get_position() and
8672 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8676 clutter_actor_get_geometry (ClutterActor *self,
8677 ClutterGeometry *geometry)
8679 gfloat x, y, width, height;
8681 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8682 g_return_if_fail (geometry != NULL);
8684 clutter_actor_get_position (self, &x, &y);
8685 clutter_actor_get_size (self, &width, &height);
8687 geometry->x = (int) x;
8688 geometry->y = (int) y;
8689 geometry->width = (int) width;
8690 geometry->height = (int) height;
8694 * clutter_actor_set_position:
8695 * @self: A #ClutterActor
8696 * @x: New left position of actor in pixels.
8697 * @y: New top position of actor in pixels.
8699 * Sets the actor's fixed position in pixels relative to any parent
8702 * If a layout manager is in use, this position will override the
8703 * layout manager and force a fixed position.
8706 clutter_actor_set_position (ClutterActor *self,
8710 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8712 g_object_freeze_notify (G_OBJECT (self));
8714 clutter_actor_set_x (self, x);
8715 clutter_actor_set_y (self, y);
8717 g_object_thaw_notify (G_OBJECT (self));
8721 * clutter_actor_get_fixed_position_set:
8722 * @self: A #ClutterActor
8724 * Checks whether an actor has a fixed position set (and will thus be
8725 * unaffected by any layout manager).
8727 * Return value: %TRUE if the fixed position is set on the actor
8732 clutter_actor_get_fixed_position_set (ClutterActor *self)
8734 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8736 return self->priv->position_set;
8740 * clutter_actor_set_fixed_position_set:
8741 * @self: A #ClutterActor
8742 * @is_set: whether to use fixed position
8744 * Sets whether an actor has a fixed position set (and will thus be
8745 * unaffected by any layout manager).
8750 clutter_actor_set_fixed_position_set (ClutterActor *self,
8753 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8755 if (self->priv->position_set == (is_set != FALSE))
8758 self->priv->position_set = is_set != FALSE;
8759 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8761 clutter_actor_queue_relayout (self);
8765 * clutter_actor_move_by:
8766 * @self: A #ClutterActor
8767 * @dx: Distance to move Actor on X axis.
8768 * @dy: Distance to move Actor on Y axis.
8770 * Moves an actor by the specified distance relative to its current
8771 * position in pixels.
8773 * This function modifies the fixed position of an actor and thus removes
8774 * it from any layout management. Another way to move an actor is with an
8775 * anchor point, see clutter_actor_set_anchor_point().
8780 clutter_actor_move_by (ClutterActor *self,
8784 const ClutterLayoutInfo *info;
8787 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8789 info = _clutter_actor_get_layout_info_or_defaults (self);
8793 clutter_actor_set_position (self, x + dx, y + dy);
8797 clutter_actor_set_min_width (ClutterActor *self,
8800 ClutterActorPrivate *priv = self->priv;
8801 ClutterActorBox old = { 0, };
8802 ClutterLayoutInfo *info;
8804 /* if we are setting the size on a top-level actor and the
8805 * backend only supports static top-levels (e.g. framebuffers)
8806 * then we ignore the passed value and we override it with
8807 * the stage implementation's preferred size.
8809 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8810 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8813 info = _clutter_actor_get_layout_info (self);
8815 if (priv->min_width_set && min_width == info->min_width)
8818 g_object_freeze_notify (G_OBJECT (self));
8820 clutter_actor_store_old_geometry (self, &old);
8822 info->min_width = min_width;
8823 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8824 clutter_actor_set_min_width_set (self, TRUE);
8826 clutter_actor_notify_if_geometry_changed (self, &old);
8828 g_object_thaw_notify (G_OBJECT (self));
8830 clutter_actor_queue_relayout (self);
8834 clutter_actor_set_min_height (ClutterActor *self,
8838 ClutterActorPrivate *priv = self->priv;
8839 ClutterActorBox old = { 0, };
8840 ClutterLayoutInfo *info;
8842 /* if we are setting the size on a top-level actor and the
8843 * backend only supports static top-levels (e.g. framebuffers)
8844 * then we ignore the passed value and we override it with
8845 * the stage implementation's preferred size.
8847 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8848 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8851 info = _clutter_actor_get_layout_info (self);
8853 if (priv->min_height_set && min_height == info->min_height)
8856 g_object_freeze_notify (G_OBJECT (self));
8858 clutter_actor_store_old_geometry (self, &old);
8860 info->min_height = min_height;
8861 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8862 clutter_actor_set_min_height_set (self, TRUE);
8864 clutter_actor_notify_if_geometry_changed (self, &old);
8866 g_object_thaw_notify (G_OBJECT (self));
8868 clutter_actor_queue_relayout (self);
8872 clutter_actor_set_natural_width (ClutterActor *self,
8873 gfloat natural_width)
8875 ClutterActorPrivate *priv = self->priv;
8876 ClutterActorBox old = { 0, };
8877 ClutterLayoutInfo *info;
8879 /* if we are setting the size on a top-level actor and the
8880 * backend only supports static top-levels (e.g. framebuffers)
8881 * then we ignore the passed value and we override it with
8882 * the stage implementation's preferred size.
8884 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8885 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8888 info = _clutter_actor_get_layout_info (self);
8890 if (priv->natural_width_set && natural_width == info->natural_width)
8893 g_object_freeze_notify (G_OBJECT (self));
8895 clutter_actor_store_old_geometry (self, &old);
8897 info->natural_width = natural_width;
8898 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8899 clutter_actor_set_natural_width_set (self, TRUE);
8901 clutter_actor_notify_if_geometry_changed (self, &old);
8903 g_object_thaw_notify (G_OBJECT (self));
8905 clutter_actor_queue_relayout (self);
8909 clutter_actor_set_natural_height (ClutterActor *self,
8910 gfloat natural_height)
8912 ClutterActorPrivate *priv = self->priv;
8913 ClutterActorBox old = { 0, };
8914 ClutterLayoutInfo *info;
8916 /* if we are setting the size on a top-level actor and the
8917 * backend only supports static top-levels (e.g. framebuffers)
8918 * then we ignore the passed value and we override it with
8919 * the stage implementation's preferred size.
8921 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8922 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8925 info = _clutter_actor_get_layout_info (self);
8927 if (priv->natural_height_set && natural_height == info->natural_height)
8930 g_object_freeze_notify (G_OBJECT (self));
8932 clutter_actor_store_old_geometry (self, &old);
8934 info->natural_height = natural_height;
8935 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8936 clutter_actor_set_natural_height_set (self, TRUE);
8938 clutter_actor_notify_if_geometry_changed (self, &old);
8940 g_object_thaw_notify (G_OBJECT (self));
8942 clutter_actor_queue_relayout (self);
8946 clutter_actor_set_min_width_set (ClutterActor *self,
8947 gboolean use_min_width)
8949 ClutterActorPrivate *priv = self->priv;
8950 ClutterActorBox old = { 0, };
8952 if (priv->min_width_set == (use_min_width != FALSE))
8955 clutter_actor_store_old_geometry (self, &old);
8957 priv->min_width_set = use_min_width != FALSE;
8958 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8960 clutter_actor_notify_if_geometry_changed (self, &old);
8962 clutter_actor_queue_relayout (self);
8966 clutter_actor_set_min_height_set (ClutterActor *self,
8967 gboolean use_min_height)
8969 ClutterActorPrivate *priv = self->priv;
8970 ClutterActorBox old = { 0, };
8972 if (priv->min_height_set == (use_min_height != FALSE))
8975 clutter_actor_store_old_geometry (self, &old);
8977 priv->min_height_set = use_min_height != FALSE;
8978 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8980 clutter_actor_notify_if_geometry_changed (self, &old);
8982 clutter_actor_queue_relayout (self);
8986 clutter_actor_set_natural_width_set (ClutterActor *self,
8987 gboolean use_natural_width)
8989 ClutterActorPrivate *priv = self->priv;
8990 ClutterActorBox old = { 0, };
8992 if (priv->natural_width_set == (use_natural_width != FALSE))
8995 clutter_actor_store_old_geometry (self, &old);
8997 priv->natural_width_set = use_natural_width != FALSE;
8998 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9000 clutter_actor_notify_if_geometry_changed (self, &old);
9002 clutter_actor_queue_relayout (self);
9006 clutter_actor_set_natural_height_set (ClutterActor *self,
9007 gboolean use_natural_height)
9009 ClutterActorPrivate *priv = self->priv;
9010 ClutterActorBox old = { 0, };
9012 if (priv->natural_height_set == (use_natural_height != FALSE))
9015 clutter_actor_store_old_geometry (self, &old);
9017 priv->natural_height_set = use_natural_height != FALSE;
9018 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9020 clutter_actor_notify_if_geometry_changed (self, &old);
9022 clutter_actor_queue_relayout (self);
9026 * clutter_actor_set_request_mode:
9027 * @self: a #ClutterActor
9028 * @mode: the request mode
9030 * Sets the geometry request mode of @self.
9032 * The @mode determines the order for invoking
9033 * clutter_actor_get_preferred_width() and
9034 * clutter_actor_get_preferred_height()
9039 clutter_actor_set_request_mode (ClutterActor *self,
9040 ClutterRequestMode mode)
9042 ClutterActorPrivate *priv;
9044 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9048 if (priv->request_mode == mode)
9051 priv->request_mode = mode;
9053 priv->needs_width_request = TRUE;
9054 priv->needs_height_request = TRUE;
9056 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9058 clutter_actor_queue_relayout (self);
9062 * clutter_actor_get_request_mode:
9063 * @self: a #ClutterActor
9065 * Retrieves the geometry request mode of @self
9067 * Return value: the request mode for the actor
9072 clutter_actor_get_request_mode (ClutterActor *self)
9074 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9075 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9077 return self->priv->request_mode;
9080 /* variant of set_width() without checks and without notification
9081 * freeze+thaw, for internal usage only
9084 clutter_actor_set_width_internal (ClutterActor *self,
9089 /* the Stage will use the :min-width to control the minimum
9090 * width to be resized to, so we should not be setting it
9091 * along with the :natural-width
9093 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9094 clutter_actor_set_min_width (self, width);
9096 clutter_actor_set_natural_width (self, width);
9100 /* we only unset the :natural-width for the Stage */
9101 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9102 clutter_actor_set_min_width_set (self, FALSE);
9104 clutter_actor_set_natural_width_set (self, FALSE);
9108 /* variant of set_height() without checks and without notification
9109 * freeze+thaw, for internal usage only
9112 clutter_actor_set_height_internal (ClutterActor *self,
9117 /* see the comment above in set_width_internal() */
9118 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9119 clutter_actor_set_min_height (self, height);
9121 clutter_actor_set_natural_height (self, height);
9125 /* see the comment above in set_width_internal() */
9126 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9127 clutter_actor_set_min_height_set (self, FALSE);
9129 clutter_actor_set_natural_height_set (self, FALSE);
9134 * clutter_actor_set_size:
9135 * @self: A #ClutterActor
9136 * @width: New width of actor in pixels, or -1
9137 * @height: New height of actor in pixels, or -1
9139 * Sets the actor's size request in pixels. This overrides any
9140 * "normal" size request the actor would have. For example
9141 * a text actor might normally request the size of the text;
9142 * this function would force a specific size instead.
9144 * If @width and/or @height are -1 the actor will use its
9145 * "normal" size request instead of overriding it, i.e.
9146 * you can "unset" the size with -1.
9148 * This function sets or unsets both the minimum and natural size.
9151 clutter_actor_set_size (ClutterActor *self,
9155 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9157 g_object_freeze_notify (G_OBJECT (self));
9159 clutter_actor_set_width (self, width);
9160 clutter_actor_set_height (self, height);
9162 g_object_thaw_notify (G_OBJECT (self));
9166 * clutter_actor_get_size:
9167 * @self: A #ClutterActor
9168 * @width: (out) (allow-none): return location for the width, or %NULL.
9169 * @height: (out) (allow-none): return location for the height, or %NULL.
9171 * This function tries to "do what you mean" and return
9172 * the size an actor will have. If the actor has a valid
9173 * allocation, the allocation will be returned; otherwise,
9174 * the actors natural size request will be returned.
9176 * If you care whether you get the request vs. the allocation, you
9177 * should probably call a different function like
9178 * clutter_actor_get_allocation_box() or
9179 * clutter_actor_get_preferred_width().
9184 clutter_actor_get_size (ClutterActor *self,
9188 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9191 *width = clutter_actor_get_width (self);
9194 *height = clutter_actor_get_height (self);
9198 * clutter_actor_get_position:
9199 * @self: a #ClutterActor
9200 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9201 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9203 * This function tries to "do what you mean" and tell you where the
9204 * actor is, prior to any transformations. Retrieves the fixed
9205 * position of an actor in pixels, if one has been set; otherwise, if
9206 * the allocation is valid, returns the actor's allocated position;
9207 * otherwise, returns 0,0.
9209 * The returned position is in pixels.
9214 clutter_actor_get_position (ClutterActor *self,
9218 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9221 *x = clutter_actor_get_x (self);
9224 *y = clutter_actor_get_y (self);
9228 * clutter_actor_get_transformed_position:
9229 * @self: A #ClutterActor
9230 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9231 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9233 * Gets the absolute position of an actor, in pixels relative to the stage.
9238 clutter_actor_get_transformed_position (ClutterActor *self,
9245 v1.x = v1.y = v1.z = 0;
9246 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9256 * clutter_actor_get_transformed_size:
9257 * @self: A #ClutterActor
9258 * @width: (out) (allow-none): return location for the width, or %NULL
9259 * @height: (out) (allow-none): return location for the height, or %NULL
9261 * Gets the absolute size of an actor in pixels, taking into account the
9264 * If the actor has a valid allocation, the allocated size will be used.
9265 * If the actor has not a valid allocation then the preferred size will
9266 * be transformed and returned.
9268 * If you want the transformed allocation, see
9269 * clutter_actor_get_abs_allocation_vertices() instead.
9271 * <note>When the actor (or one of its ancestors) is rotated around the
9272 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9273 * as a generic quadrangle; in that case this function returns the size
9274 * of the smallest rectangle that encapsulates the entire quad. Please
9275 * note that in this case no assumptions can be made about the relative
9276 * position of this envelope to the absolute position of the actor, as
9277 * returned by clutter_actor_get_transformed_position(); if you need this
9278 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9279 * to get the coords of the actual quadrangle.</note>
9284 clutter_actor_get_transformed_size (ClutterActor *self,
9288 ClutterActorPrivate *priv;
9290 gfloat x_min, x_max, y_min, y_max;
9293 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9297 /* if the actor hasn't been allocated yet, get the preferred
9298 * size and transform that
9300 if (priv->needs_allocation)
9302 gfloat natural_width, natural_height;
9303 ClutterActorBox box;
9305 /* Make a fake allocation to transform.
9307 * NB: _clutter_actor_transform_and_project_box expects a box in
9308 * the actor's coordinate space... */
9313 natural_width = natural_height = 0;
9314 clutter_actor_get_preferred_size (self, NULL, NULL,
9318 box.x2 = natural_width;
9319 box.y2 = natural_height;
9321 _clutter_actor_transform_and_project_box (self, &box, v);
9324 clutter_actor_get_abs_allocation_vertices (self, v);
9326 x_min = x_max = v[0].x;
9327 y_min = y_max = v[0].y;
9329 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9345 *width = x_max - x_min;
9348 *height = y_max - y_min;
9352 * clutter_actor_get_width:
9353 * @self: A #ClutterActor
9355 * Retrieves the width of a #ClutterActor.
9357 * If the actor has a valid allocation, this function will return the
9358 * width of the allocated area given to the actor.
9360 * If the actor does not have a valid allocation, this function will
9361 * return the actor's natural width, that is the preferred width of
9364 * If you care whether you get the preferred width or the width that
9365 * has been assigned to the actor, you should probably call a different
9366 * function like clutter_actor_get_allocation_box() to retrieve the
9367 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9370 * If an actor has a fixed width, for instance a width that has been
9371 * assigned using clutter_actor_set_width(), the width returned will
9372 * be the same value.
9374 * Return value: the width of the actor, in pixels
9377 clutter_actor_get_width (ClutterActor *self)
9379 ClutterActorPrivate *priv;
9381 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9385 if (priv->needs_allocation)
9387 gfloat natural_width = 0;
9389 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9390 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9393 gfloat natural_height = 0;
9395 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9396 clutter_actor_get_preferred_width (self, natural_height,
9401 return natural_width;
9404 return priv->allocation.x2 - priv->allocation.x1;
9408 * clutter_actor_get_height:
9409 * @self: A #ClutterActor
9411 * Retrieves the height of a #ClutterActor.
9413 * If the actor has a valid allocation, this function will return the
9414 * height of the allocated area given to the actor.
9416 * If the actor does not have a valid allocation, this function will
9417 * return the actor's natural height, that is the preferred height of
9420 * If you care whether you get the preferred height or the height that
9421 * has been assigned to the actor, you should probably call a different
9422 * function like clutter_actor_get_allocation_box() to retrieve the
9423 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9426 * If an actor has a fixed height, for instance a height that has been
9427 * assigned using clutter_actor_set_height(), the height returned will
9428 * be the same value.
9430 * Return value: the height of the actor, in pixels
9433 clutter_actor_get_height (ClutterActor *self)
9435 ClutterActorPrivate *priv;
9437 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9441 if (priv->needs_allocation)
9443 gfloat natural_height = 0;
9445 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9447 gfloat natural_width = 0;
9449 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9450 clutter_actor_get_preferred_height (self, natural_width,
9451 NULL, &natural_height);
9454 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9456 return natural_height;
9459 return priv->allocation.y2 - priv->allocation.y1;
9463 * clutter_actor_set_width:
9464 * @self: A #ClutterActor
9465 * @width: Requested new width for the actor, in pixels, or -1
9467 * Forces a width on an actor, causing the actor's preferred width
9468 * and height (if any) to be ignored.
9470 * If @width is -1 the actor will use its preferred width request
9471 * instead of overriding it, i.e. you can "unset" the width with -1.
9473 * This function sets both the minimum and natural size of the actor.
9478 clutter_actor_set_width (ClutterActor *self,
9481 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9483 if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9487 /* minor optimization: if we don't have a duration
9488 * then we can skip the get_width() below, to avoid
9489 * the chance of going through get_preferred_width()
9490 * just to jump to a new desired width.
9492 if (clutter_actor_get_easing_duration (self) == 0)
9494 g_object_freeze_notify (G_OBJECT (self));
9496 clutter_actor_set_width_internal (self, width);
9498 g_object_thaw_notify (G_OBJECT (self));
9503 cur_size = clutter_actor_get_width (self);
9505 _clutter_actor_create_transition (self,
9506 obj_props[PROP_WIDTH],
9511 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9513 clutter_actor_queue_relayout (self);
9517 * clutter_actor_set_height:
9518 * @self: A #ClutterActor
9519 * @height: Requested new height for the actor, in pixels, or -1
9521 * Forces a height on an actor, causing the actor's preferred width
9522 * and height (if any) to be ignored.
9524 * If @height is -1 the actor will use its preferred height instead of
9525 * overriding it, i.e. you can "unset" the height with -1.
9527 * This function sets both the minimum and natural size of the actor.
9532 clutter_actor_set_height (ClutterActor *self,
9535 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9537 if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9541 /* see the comment in clutter_actor_set_width() above */
9542 if (clutter_actor_get_easing_duration (self) == 0)
9544 g_object_freeze_notify (G_OBJECT (self));
9546 clutter_actor_set_height_internal (self, height);
9548 g_object_thaw_notify (G_OBJECT (self));
9553 cur_size = clutter_actor_get_height (self);
9555 _clutter_actor_create_transition (self,
9556 obj_props[PROP_HEIGHT],
9561 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9563 clutter_actor_queue_relayout (self);
9567 clutter_actor_set_x_internal (ClutterActor *self,
9570 ClutterActorPrivate *priv = self->priv;
9571 ClutterLayoutInfo *linfo;
9572 ClutterActorBox old = { 0, };
9574 linfo = _clutter_actor_get_layout_info (self);
9576 if (priv->position_set && linfo->fixed_x == x)
9579 clutter_actor_store_old_geometry (self, &old);
9582 clutter_actor_set_fixed_position_set (self, TRUE);
9584 clutter_actor_notify_if_geometry_changed (self, &old);
9586 clutter_actor_queue_relayout (self);
9590 clutter_actor_set_y_internal (ClutterActor *self,
9593 ClutterActorPrivate *priv = self->priv;
9594 ClutterLayoutInfo *linfo;
9595 ClutterActorBox old = { 0, };
9597 linfo = _clutter_actor_get_layout_info (self);
9599 if (priv->position_set && linfo->fixed_y == y)
9602 clutter_actor_store_old_geometry (self, &old);
9605 clutter_actor_set_fixed_position_set (self, TRUE);
9607 clutter_actor_notify_if_geometry_changed (self, &old);
9609 clutter_actor_queue_relayout (self);
9613 * clutter_actor_set_x:
9614 * @self: a #ClutterActor
9615 * @x: the actor's position on the X axis
9617 * Sets the actor's X coordinate, relative to its parent, in pixels.
9619 * Overrides any layout manager and forces a fixed position for
9622 * The #ClutterActor:x property is animatable.
9627 clutter_actor_set_x (ClutterActor *self,
9630 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9632 if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9634 float cur_position = clutter_actor_get_x (self);
9636 _clutter_actor_create_transition (self, obj_props[PROP_X],
9641 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9643 clutter_actor_queue_relayout (self);
9647 * clutter_actor_set_y:
9648 * @self: a #ClutterActor
9649 * @y: the actor's position on the Y axis
9651 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9653 * Overrides any layout manager and forces a fixed position for
9656 * The #ClutterActor:y property is animatable.
9661 clutter_actor_set_y (ClutterActor *self,
9664 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9666 if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9668 float cur_position = clutter_actor_get_y (self);
9670 _clutter_actor_create_transition (self, obj_props[PROP_Y],
9675 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9677 clutter_actor_queue_relayout (self);
9681 * clutter_actor_get_x:
9682 * @self: A #ClutterActor
9684 * Retrieves the X coordinate of a #ClutterActor.
9686 * This function tries to "do what you mean", by returning the
9687 * correct value depending on the actor's state.
9689 * If the actor has a valid allocation, this function will return
9690 * the X coordinate of the origin of the allocation box.
9692 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9693 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9694 * function will return that coordinate.
9696 * If both the allocation and a fixed position are missing, this function
9699 * Return value: the X coordinate, in pixels, ignoring any
9700 * transformation (i.e. scaling, rotation)
9703 clutter_actor_get_x (ClutterActor *self)
9705 ClutterActorPrivate *priv;
9707 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9711 if (priv->needs_allocation)
9713 if (priv->position_set)
9715 const ClutterLayoutInfo *info;
9717 info = _clutter_actor_get_layout_info_or_defaults (self);
9719 return info->fixed_x;
9725 return priv->allocation.x1;
9729 * clutter_actor_get_y:
9730 * @self: A #ClutterActor
9732 * Retrieves the Y coordinate of a #ClutterActor.
9734 * This function tries to "do what you mean", by returning the
9735 * correct value depending on the actor's state.
9737 * If the actor has a valid allocation, this function will return
9738 * the Y coordinate of the origin of the allocation box.
9740 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9741 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9742 * function will return that coordinate.
9744 * If both the allocation and a fixed position are missing, this function
9747 * Return value: the Y coordinate, in pixels, ignoring any
9748 * transformation (i.e. scaling, rotation)
9751 clutter_actor_get_y (ClutterActor *self)
9753 ClutterActorPrivate *priv;
9755 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9759 if (priv->needs_allocation)
9761 if (priv->position_set)
9763 const ClutterLayoutInfo *info;
9765 info = _clutter_actor_get_layout_info_or_defaults (self);
9767 return info->fixed_y;
9773 return priv->allocation.y1;
9777 * clutter_actor_set_scale:
9778 * @self: A #ClutterActor
9779 * @scale_x: double factor to scale actor by horizontally.
9780 * @scale_y: double factor to scale actor by vertically.
9782 * Scales an actor with the given factors. The scaling is relative to
9783 * the scale center and the anchor point. The scale center is
9784 * unchanged by this function and defaults to 0,0.
9786 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9792 clutter_actor_set_scale (ClutterActor *self,
9796 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9798 g_object_freeze_notify (G_OBJECT (self));
9800 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9801 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9803 g_object_thaw_notify (G_OBJECT (self));
9807 * clutter_actor_set_scale_full:
9808 * @self: A #ClutterActor
9809 * @scale_x: double factor to scale actor by horizontally.
9810 * @scale_y: double factor to scale actor by vertically.
9811 * @center_x: X coordinate of the center of the scale.
9812 * @center_y: Y coordinate of the center of the scale
9814 * Scales an actor with the given factors around the given center
9815 * point. The center point is specified in pixels relative to the
9816 * anchor point (usually the top left corner of the actor).
9818 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9824 clutter_actor_set_scale_full (ClutterActor *self,
9830 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9832 g_object_freeze_notify (G_OBJECT (self));
9834 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9835 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9836 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9837 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9839 g_object_thaw_notify (G_OBJECT (self));
9843 * clutter_actor_set_scale_with_gravity:
9844 * @self: A #ClutterActor
9845 * @scale_x: double factor to scale actor by horizontally.
9846 * @scale_y: double factor to scale actor by vertically.
9847 * @gravity: the location of the scale center expressed as a compass
9850 * Scales an actor with the given factors around the given
9851 * center point. The center point is specified as one of the compass
9852 * directions in #ClutterGravity. For example, setting it to north
9853 * will cause the top of the actor to remain unchanged and the rest of
9854 * the actor to expand left, right and downwards.
9856 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9862 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9865 ClutterGravity gravity)
9867 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9869 g_object_freeze_notify (G_OBJECT (self));
9871 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9872 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9873 clutter_actor_set_scale_gravity (self, gravity);
9875 g_object_thaw_notify (G_OBJECT (self));
9879 * clutter_actor_get_scale:
9880 * @self: A #ClutterActor
9881 * @scale_x: (out) (allow-none): Location to store horizonal
9882 * scale factor, or %NULL.
9883 * @scale_y: (out) (allow-none): Location to store vertical
9884 * scale factor, or %NULL.
9886 * Retrieves an actors scale factors.
9891 clutter_actor_get_scale (ClutterActor *self,
9895 const ClutterTransformInfo *info;
9897 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9899 info = _clutter_actor_get_transform_info_or_defaults (self);
9902 *scale_x = info->scale_x;
9905 *scale_y = info->scale_y;
9909 * clutter_actor_get_scale_center:
9910 * @self: A #ClutterActor
9911 * @center_x: (out) (allow-none): Location to store the X position
9912 * of the scale center, or %NULL.
9913 * @center_y: (out) (allow-none): Location to store the Y position
9914 * of the scale center, or %NULL.
9916 * Retrieves the scale center coordinate in pixels relative to the top
9917 * left corner of the actor. If the scale center was specified using a
9918 * #ClutterGravity this will calculate the pixel offset using the
9919 * current size of the actor.
9924 clutter_actor_get_scale_center (ClutterActor *self,
9928 const ClutterTransformInfo *info;
9930 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9932 info = _clutter_actor_get_transform_info_or_defaults (self);
9934 clutter_anchor_coord_get_units (self, &info->scale_center,
9941 * clutter_actor_get_scale_gravity:
9942 * @self: A #ClutterActor
9944 * Retrieves the scale center as a compass direction. If the scale
9945 * center was specified in pixels or units this will return
9946 * %CLUTTER_GRAVITY_NONE.
9948 * Return value: the scale gravity
9953 clutter_actor_get_scale_gravity (ClutterActor *self)
9955 const ClutterTransformInfo *info;
9957 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9959 info = _clutter_actor_get_transform_info_or_defaults (self);
9961 return clutter_anchor_coord_get_gravity (&info->scale_center);
9965 clutter_actor_set_opacity_internal (ClutterActor *self,
9968 ClutterActorPrivate *priv = self->priv;
9970 if (priv->opacity != opacity)
9972 priv->opacity = opacity;
9974 /* Queue a redraw from the flatten effect so that it can use
9975 its cached image if available instead of having to redraw the
9976 actual actor. If it doesn't end up using the FBO then the
9977 effect is still able to continue the paint anyway. If there
9978 is no flatten effect yet then this is equivalent to queueing
9980 _clutter_actor_queue_redraw_full (self,
9983 priv->flatten_effect);
9985 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9990 * clutter_actor_set_opacity:
9991 * @self: A #ClutterActor
9992 * @opacity: New opacity value for the actor.
9994 * Sets the actor's opacity, with zero being completely transparent and
9995 * 255 (0xff) being fully opaque.
9997 * The #ClutterActor:opacity property is animatable.
10000 clutter_actor_set_opacity (ClutterActor *self,
10003 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10005 if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10007 _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10008 self->priv->opacity,
10012 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10016 * clutter_actor_get_paint_opacity_internal:
10017 * @self: a #ClutterActor
10019 * Retrieves the absolute opacity of the actor, as it appears on the stage
10021 * This function does not do type checks
10023 * Return value: the absolute opacity of the actor
10026 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10028 ClutterActorPrivate *priv = self->priv;
10029 ClutterActor *parent;
10031 /* override the top-level opacity to always be 255; even in
10032 * case of ClutterStage:use-alpha being TRUE we want the rest
10033 * of the scene to be painted
10035 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10038 if (priv->opacity_override >= 0)
10039 return priv->opacity_override;
10041 parent = priv->parent;
10043 /* Factor in the actual actors opacity with parents */
10044 if (parent != NULL)
10046 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10048 if (opacity != 0xff)
10049 return (opacity * priv->opacity) / 0xff;
10052 return priv->opacity;
10057 * clutter_actor_get_paint_opacity:
10058 * @self: A #ClutterActor
10060 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10062 * This function traverses the hierarchy chain and composites the opacity of
10063 * the actor with that of its parents.
10065 * This function is intended for subclasses to use in the paint virtual
10066 * function, to paint themselves with the correct opacity.
10068 * Return value: The actor opacity value.
10073 clutter_actor_get_paint_opacity (ClutterActor *self)
10075 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10077 return clutter_actor_get_paint_opacity_internal (self);
10081 * clutter_actor_get_opacity:
10082 * @self: a #ClutterActor
10084 * Retrieves the opacity value of an actor, as set by
10085 * clutter_actor_set_opacity().
10087 * For retrieving the absolute opacity of the actor inside a paint
10088 * virtual function, see clutter_actor_get_paint_opacity().
10090 * Return value: the opacity of the actor
10093 clutter_actor_get_opacity (ClutterActor *self)
10095 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10097 return self->priv->opacity;
10101 * clutter_actor_set_offscreen_redirect:
10102 * @self: A #ClutterActor
10103 * @redirect: New offscreen redirect flags for the actor.
10105 * Defines the circumstances where the actor should be redirected into
10106 * an offscreen image. The offscreen image is used to flatten the
10107 * actor into a single image while painting for two main reasons.
10108 * Firstly, when the actor is painted a second time without any of its
10109 * contents changing it can simply repaint the cached image without
10110 * descending further down the actor hierarchy. Secondly, it will make
10111 * the opacity look correct even if there are overlapping primitives
10114 * Caching the actor could in some cases be a performance win and in
10115 * some cases be a performance lose so it is important to determine
10116 * which value is right for an actor before modifying this value. For
10117 * example, there is never any reason to flatten an actor that is just
10118 * a single texture (such as a #ClutterTexture) because it is
10119 * effectively already cached in an image so the offscreen would be
10120 * redundant. Also if the actor contains primitives that are far apart
10121 * with a large transparent area in the middle (such as a large
10122 * CluterGroup with a small actor in the top left and a small actor in
10123 * the bottom right) then the cached image will contain the entire
10124 * image of the large area and the paint will waste time blending all
10125 * of the transparent pixels in the middle.
10127 * The default method of implementing opacity on a container simply
10128 * forwards on the opacity to all of the children. If the children are
10129 * overlapping then it will appear as if they are two separate glassy
10130 * objects and there will be a break in the color where they
10131 * overlap. By redirecting to an offscreen buffer it will be as if the
10132 * two opaque objects are combined into one and then made transparent
10133 * which is usually what is expected.
10135 * The image below demonstrates the difference between redirecting and
10136 * not. The image shows two Clutter groups, each containing a red and
10137 * a green rectangle which overlap. The opacity on the group is set to
10138 * 128 (which is 50%). When the offscreen redirect is not used, the
10139 * red rectangle can be seen through the blue rectangle as if the two
10140 * rectangles were separately transparent. When the redirect is used
10141 * the group as a whole is transparent instead so the red rectangle is
10142 * not visible where they overlap.
10144 * <figure id="offscreen-redirect">
10145 * <title>Sample of using an offscreen redirect for transparency</title>
10146 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10149 * The default value for this property is 0, so we effectively will
10150 * never redirect an actor offscreen by default. This means that there
10151 * are times that transparent actors may look glassy as described
10152 * above. The reason this is the default is because there is a
10153 * performance trade off between quality and performance here. In many
10154 * cases the default form of glassy opacity looks good enough, but if
10155 * it's not you will need to set the
10156 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10157 * redirection for opacity.
10159 * Custom actors that don't contain any overlapping primitives are
10160 * recommended to override the has_overlaps() virtual to return %FALSE
10161 * for maximum efficiency.
10166 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10167 ClutterOffscreenRedirect redirect)
10169 ClutterActorPrivate *priv;
10171 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10175 if (priv->offscreen_redirect != redirect)
10177 priv->offscreen_redirect = redirect;
10179 /* Queue a redraw from the effect so that it can use its cached
10180 image if available instead of having to redraw the actual
10181 actor. If it doesn't end up using the FBO then the effect is
10182 still able to continue the paint anyway. If there is no
10183 effect then this is equivalent to queuing a full redraw */
10184 _clutter_actor_queue_redraw_full (self,
10187 priv->flatten_effect);
10189 g_object_notify_by_pspec (G_OBJECT (self),
10190 obj_props[PROP_OFFSCREEN_REDIRECT]);
10195 * clutter_actor_get_offscreen_redirect:
10196 * @self: a #ClutterActor
10198 * Retrieves whether to redirect the actor to an offscreen buffer, as
10199 * set by clutter_actor_set_offscreen_redirect().
10201 * Return value: the value of the offscreen-redirect property of the actor
10205 ClutterOffscreenRedirect
10206 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10208 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10210 return self->priv->offscreen_redirect;
10214 * clutter_actor_set_name:
10215 * @self: A #ClutterActor
10216 * @name: Textual tag to apply to actor
10218 * Sets the given name to @self. The name can be used to identify
10222 clutter_actor_set_name (ClutterActor *self,
10225 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10227 g_free (self->priv->name);
10228 self->priv->name = g_strdup (name);
10230 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10234 * clutter_actor_get_name:
10235 * @self: A #ClutterActor
10237 * Retrieves the name of @self.
10239 * Return value: the name of the actor, or %NULL. The returned string is
10240 * owned by the actor and should not be modified or freed.
10243 clutter_actor_get_name (ClutterActor *self)
10245 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10247 return self->priv->name;
10251 * clutter_actor_get_gid:
10252 * @self: A #ClutterActor
10254 * Retrieves the unique id for @self.
10256 * Return value: Globally unique value for this object instance.
10260 * Deprecated: 1.8: The id is not used any longer.
10263 clutter_actor_get_gid (ClutterActor *self)
10265 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10267 return self->priv->id;
10271 clutter_actor_set_depth_internal (ClutterActor *self,
10274 ClutterTransformInfo *info;
10276 info = _clutter_actor_get_transform_info (self);
10278 if (info->depth != depth)
10280 /* Sets Z value - XXX 2.0: should we invert? */
10281 info->depth = depth;
10283 self->priv->transform_valid = FALSE;
10285 /* FIXME - remove this crap; sadly, there are still containers
10286 * in Clutter that depend on this utter brain damage
10288 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10290 clutter_actor_queue_redraw (self);
10292 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10297 * clutter_actor_set_depth:
10298 * @self: a #ClutterActor
10301 * Sets the Z coordinate of @self to @depth.
10303 * The unit used by @depth is dependant on the perspective setup. See
10304 * also clutter_stage_set_perspective().
10307 clutter_actor_set_depth (ClutterActor *self,
10310 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10312 if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10314 const ClutterTransformInfo *info;
10316 info = _clutter_actor_get_transform_info_or_defaults (self);
10318 _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10323 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10325 clutter_actor_queue_redraw (self);
10329 * clutter_actor_get_depth:
10330 * @self: a #ClutterActor
10332 * Retrieves the depth of @self.
10334 * Return value: the depth of the actor
10337 clutter_actor_get_depth (ClutterActor *self)
10339 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10341 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10345 * clutter_actor_set_rotation:
10346 * @self: a #ClutterActor
10347 * @axis: the axis of rotation
10348 * @angle: the angle of rotation
10349 * @x: X coordinate of the rotation center
10350 * @y: Y coordinate of the rotation center
10351 * @z: Z coordinate of the rotation center
10353 * Sets the rotation angle of @self around the given axis.
10355 * The rotation center coordinates used depend on the value of @axis:
10357 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10358 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10359 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10362 * The rotation coordinates are relative to the anchor point of the
10363 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10364 * point is set, the upper left corner is assumed as the origin.
10369 clutter_actor_set_rotation (ClutterActor *self,
10370 ClutterRotateAxis axis,
10378 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10384 g_object_freeze_notify (G_OBJECT (self));
10386 clutter_actor_set_rotation_angle (self, axis, angle);
10387 clutter_actor_set_rotation_center_internal (self, axis, &v);
10389 g_object_thaw_notify (G_OBJECT (self));
10393 * clutter_actor_set_z_rotation_from_gravity:
10394 * @self: a #ClutterActor
10395 * @angle: the angle of rotation
10396 * @gravity: the center point of the rotation
10398 * Sets the rotation angle of @self around the Z axis using the center
10399 * point specified as a compass point. For example to rotate such that
10400 * the center of the actor remains static you can use
10401 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10402 * will move accordingly.
10407 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10409 ClutterGravity gravity)
10411 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10413 if (gravity == CLUTTER_GRAVITY_NONE)
10414 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10417 GObject *obj = G_OBJECT (self);
10418 ClutterTransformInfo *info;
10420 info = _clutter_actor_get_transform_info (self);
10422 g_object_freeze_notify (obj);
10424 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10426 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10427 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10428 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10430 g_object_thaw_notify (obj);
10435 * clutter_actor_get_rotation:
10436 * @self: a #ClutterActor
10437 * @axis: the axis of rotation
10438 * @x: (out): return value for the X coordinate of the center of rotation
10439 * @y: (out): return value for the Y coordinate of the center of rotation
10440 * @z: (out): return value for the Z coordinate of the center of rotation
10442 * Retrieves the angle and center of rotation on the given axis,
10443 * set using clutter_actor_set_rotation().
10445 * Return value: the angle of rotation
10450 clutter_actor_get_rotation (ClutterActor *self,
10451 ClutterRotateAxis axis,
10456 const ClutterTransformInfo *info;
10457 const AnchorCoord *anchor_coord;
10458 gdouble retval = 0;
10460 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10462 info = _clutter_actor_get_transform_info_or_defaults (self);
10466 case CLUTTER_X_AXIS:
10467 anchor_coord = &info->rx_center;
10468 retval = info->rx_angle;
10471 case CLUTTER_Y_AXIS:
10472 anchor_coord = &info->ry_center;
10473 retval = info->ry_angle;
10476 case CLUTTER_Z_AXIS:
10477 anchor_coord = &info->rz_center;
10478 retval = info->rz_angle;
10482 anchor_coord = NULL;
10487 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10493 * clutter_actor_get_z_rotation_gravity:
10494 * @self: A #ClutterActor
10496 * Retrieves the center for the rotation around the Z axis as a
10497 * compass direction. If the center was specified in pixels or units
10498 * this will return %CLUTTER_GRAVITY_NONE.
10500 * Return value: the Z rotation center
10505 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10507 const ClutterTransformInfo *info;
10509 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10511 info = _clutter_actor_get_transform_info_or_defaults (self);
10513 return clutter_anchor_coord_get_gravity (&info->rz_center);
10517 * clutter_actor_set_clip:
10518 * @self: A #ClutterActor
10519 * @xoff: X offset of the clip rectangle
10520 * @yoff: Y offset of the clip rectangle
10521 * @width: Width of the clip rectangle
10522 * @height: Height of the clip rectangle
10524 * Sets clip area for @self. The clip area is always computed from the
10525 * upper left corner of the actor, even if the anchor point is set
10531 clutter_actor_set_clip (ClutterActor *self,
10537 ClutterActorPrivate *priv;
10539 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10543 if (priv->has_clip &&
10544 priv->clip.x == xoff &&
10545 priv->clip.y == yoff &&
10546 priv->clip.width == width &&
10547 priv->clip.height == height)
10550 priv->clip.x = xoff;
10551 priv->clip.y = yoff;
10552 priv->clip.width = width;
10553 priv->clip.height = height;
10555 priv->has_clip = TRUE;
10557 clutter_actor_queue_redraw (self);
10559 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10560 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10564 * clutter_actor_remove_clip:
10565 * @self: A #ClutterActor
10567 * Removes clip area from @self.
10570 clutter_actor_remove_clip (ClutterActor *self)
10572 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10574 if (!self->priv->has_clip)
10577 self->priv->has_clip = FALSE;
10579 clutter_actor_queue_redraw (self);
10581 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10585 * clutter_actor_has_clip:
10586 * @self: a #ClutterActor
10588 * Determines whether the actor has a clip area set or not.
10590 * Return value: %TRUE if the actor has a clip area set.
10595 clutter_actor_has_clip (ClutterActor *self)
10597 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10599 return self->priv->has_clip;
10603 * clutter_actor_get_clip:
10604 * @self: a #ClutterActor
10605 * @xoff: (out) (allow-none): return location for the X offset of
10606 * the clip rectangle, or %NULL
10607 * @yoff: (out) (allow-none): return location for the Y offset of
10608 * the clip rectangle, or %NULL
10609 * @width: (out) (allow-none): return location for the width of
10610 * the clip rectangle, or %NULL
10611 * @height: (out) (allow-none): return location for the height of
10612 * the clip rectangle, or %NULL
10614 * Gets the clip area for @self, if any is set
10619 clutter_actor_get_clip (ClutterActor *self,
10625 ClutterActorPrivate *priv;
10627 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10631 if (!priv->has_clip)
10635 *xoff = priv->clip.x;
10638 *yoff = priv->clip.y;
10641 *width = priv->clip.width;
10643 if (height != NULL)
10644 *height = priv->clip.height;
10648 * clutter_actor_get_children:
10649 * @self: a #ClutterActor
10651 * Retrieves the list of children of @self.
10653 * Return value: (transfer container) (element-type ClutterActor): A newly
10654 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10660 clutter_actor_get_children (ClutterActor *self)
10662 ClutterActor *iter;
10665 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10667 /* we walk the list backward so that we can use prepend(),
10670 for (iter = self->priv->last_child, res = NULL;
10672 iter = iter->priv->prev_sibling)
10674 res = g_list_prepend (res, iter);
10681 * insert_child_at_depth:
10682 * @self: a #ClutterActor
10683 * @child: a #ClutterActor
10685 * Inserts @child inside the list of children held by @self, using
10686 * the depth as the insertion criteria.
10688 * This sadly makes the insertion not O(1), but we can keep the
10689 * list sorted so that the painters algorithm we use for painting
10690 * the children will work correctly.
10693 insert_child_at_depth (ClutterActor *self,
10694 ClutterActor *child,
10695 gpointer dummy G_GNUC_UNUSED)
10697 ClutterActor *iter;
10700 child->priv->parent = self;
10703 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10705 /* special-case the first child */
10706 if (self->priv->n_children == 0)
10708 self->priv->first_child = child;
10709 self->priv->last_child = child;
10711 child->priv->next_sibling = NULL;
10712 child->priv->prev_sibling = NULL;
10717 /* Find the right place to insert the child so that it will still be
10718 sorted and the child will be after all of the actors at the same
10720 for (iter = self->priv->first_child;
10722 iter = iter->priv->next_sibling)
10727 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10729 if (iter_depth > child_depth)
10735 ClutterActor *tmp = iter->priv->prev_sibling;
10738 tmp->priv->next_sibling = child;
10740 /* Insert the node before the found one */
10741 child->priv->prev_sibling = iter->priv->prev_sibling;
10742 child->priv->next_sibling = iter;
10743 iter->priv->prev_sibling = child;
10747 ClutterActor *tmp = self->priv->last_child;
10750 tmp->priv->next_sibling = child;
10752 /* insert the node at the end of the list */
10753 child->priv->prev_sibling = self->priv->last_child;
10754 child->priv->next_sibling = NULL;
10757 if (child->priv->prev_sibling == NULL)
10758 self->priv->first_child = child;
10760 if (child->priv->next_sibling == NULL)
10761 self->priv->last_child = child;
10765 insert_child_at_index (ClutterActor *self,
10766 ClutterActor *child,
10769 gint index_ = GPOINTER_TO_INT (data_);
10771 child->priv->parent = self;
10775 ClutterActor *tmp = self->priv->first_child;
10778 tmp->priv->prev_sibling = child;
10780 child->priv->prev_sibling = NULL;
10781 child->priv->next_sibling = tmp;
10783 else if (index_ < 0 || index_ >= self->priv->n_children)
10785 ClutterActor *tmp = self->priv->last_child;
10788 tmp->priv->next_sibling = child;
10790 child->priv->prev_sibling = tmp;
10791 child->priv->next_sibling = NULL;
10795 ClutterActor *iter;
10798 for (iter = self->priv->first_child, i = 0;
10800 iter = iter->priv->next_sibling, i += 1)
10804 ClutterActor *tmp = iter->priv->prev_sibling;
10806 child->priv->prev_sibling = tmp;
10807 child->priv->next_sibling = iter;
10809 iter->priv->prev_sibling = child;
10812 tmp->priv->next_sibling = child;
10819 if (child->priv->prev_sibling == NULL)
10820 self->priv->first_child = child;
10822 if (child->priv->next_sibling == NULL)
10823 self->priv->last_child = child;
10827 insert_child_above (ClutterActor *self,
10828 ClutterActor *child,
10831 ClutterActor *sibling = data;
10833 child->priv->parent = self;
10835 if (sibling == NULL)
10836 sibling = self->priv->last_child;
10838 child->priv->prev_sibling = sibling;
10840 if (sibling != NULL)
10842 ClutterActor *tmp = sibling->priv->next_sibling;
10844 child->priv->next_sibling = tmp;
10847 tmp->priv->prev_sibling = child;
10849 sibling->priv->next_sibling = child;
10852 child->priv->next_sibling = NULL;
10854 if (child->priv->prev_sibling == NULL)
10855 self->priv->first_child = child;
10857 if (child->priv->next_sibling == NULL)
10858 self->priv->last_child = child;
10862 insert_child_below (ClutterActor *self,
10863 ClutterActor *child,
10866 ClutterActor *sibling = data;
10868 child->priv->parent = self;
10870 if (sibling == NULL)
10871 sibling = self->priv->first_child;
10873 child->priv->next_sibling = sibling;
10875 if (sibling != NULL)
10877 ClutterActor *tmp = sibling->priv->prev_sibling;
10879 child->priv->prev_sibling = tmp;
10882 tmp->priv->next_sibling = child;
10884 sibling->priv->prev_sibling = child;
10887 child->priv->prev_sibling = NULL;
10889 if (child->priv->prev_sibling == NULL)
10890 self->priv->first_child = child;
10892 if (child->priv->next_sibling == NULL)
10893 self->priv->last_child = child;
10896 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10897 ClutterActor *child,
10901 ADD_CHILD_CREATE_META = 1 << 0,
10902 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10903 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10904 ADD_CHILD_CHECK_STATE = 1 << 3,
10905 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10907 /* default flags for public API */
10908 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10909 ADD_CHILD_EMIT_PARENT_SET |
10910 ADD_CHILD_EMIT_ACTOR_ADDED |
10911 ADD_CHILD_CHECK_STATE |
10912 ADD_CHILD_NOTIFY_FIRST_LAST,
10914 /* flags for legacy/deprecated API */
10915 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10916 ADD_CHILD_CHECK_STATE |
10917 ADD_CHILD_NOTIFY_FIRST_LAST
10918 } ClutterActorAddChildFlags;
10921 * clutter_actor_add_child_internal:
10922 * @self: a #ClutterActor
10923 * @child: a #ClutterActor
10924 * @flags: control flags for actions
10925 * @add_func: delegate function
10926 * @data: (closure): data to pass to @add_func
10928 * Adds @child to the list of children of @self.
10930 * The actual insertion inside the list is delegated to @add_func: this
10931 * function will just set up the state, perform basic checks, and emit
10934 * The @flags argument is used to perform additional operations.
10937 clutter_actor_add_child_internal (ClutterActor *self,
10938 ClutterActor *child,
10939 ClutterActorAddChildFlags flags,
10940 ClutterActorAddChildFunc add_func,
10943 ClutterTextDirection text_dir;
10944 gboolean create_meta;
10945 gboolean emit_parent_set, emit_actor_added;
10946 gboolean check_state;
10947 gboolean notify_first_last;
10948 ClutterActor *old_first_child, *old_last_child;
10950 if (child->priv->parent != NULL)
10952 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10953 "use clutter_actor_remove_child() first.",
10954 _clutter_actor_get_debug_name (child),
10955 _clutter_actor_get_debug_name (child->priv->parent));
10959 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10961 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10962 "a child of another actor.",
10963 _clutter_actor_get_debug_name (child));
10968 /* XXX - this check disallows calling methods that change the stacking
10969 * order within the destruction sequence, by triggering a critical
10970 * warning first, and leaving the actor in an undefined state, which
10971 * then ends up being caught by an assertion.
10973 * the reproducible sequence is:
10975 * - actor gets destroyed;
10976 * - another actor, linked to the first, will try to change the
10977 * stacking order of the first actor;
10978 * - changing the stacking order is a composite operation composed
10979 * by the following steps:
10980 * 1. ref() the child;
10981 * 2. remove_child_internal(), which removes the reference;
10982 * 3. add_child_internal(), which adds a reference;
10983 * - the state of the actor is not changed between (2) and (3), as
10984 * it could be an expensive recomputation;
10985 * - if (3) bails out, then the actor is in an undefined state, but
10987 * - the destruction sequence terminates, but the actor is unparented
10988 * while its state indicates being parented instead.
10989 * - assertion failure.
10991 * the obvious fix would be to decompose each set_child_*_sibling()
10992 * method into proper remove_child()/add_child(), with state validation;
10993 * this may cause excessive work, though, and trigger a cascade of other
10994 * bugs in code that assumes that a change in the stacking order is an
10995 * atomic operation.
10997 * another potential fix is to just remove this check here, and let
10998 * code doing stacking order changes inside the destruction sequence
10999 * of an actor continue doing the work.
11001 * the third fix is to silently bail out early from every
11002 * set_child_*_sibling() and set_child_at_index() method, and avoid
11005 * I have a preference for the second solution, since it involves the
11006 * least amount of work, and the least amount of code duplication.
11008 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11010 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11012 g_warning ("The actor '%s' is currently being destroyed, and "
11013 "cannot be added as a child of another actor.",
11014 _clutter_actor_get_debug_name (child));
11019 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11020 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11021 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11022 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11023 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11025 old_first_child = self->priv->first_child;
11026 old_last_child = self->priv->last_child;
11028 g_object_freeze_notify (G_OBJECT (self));
11031 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11033 g_object_ref_sink (child);
11034 child->priv->parent = NULL;
11035 child->priv->next_sibling = NULL;
11036 child->priv->prev_sibling = NULL;
11038 /* delegate the actual insertion */
11039 add_func (self, child, data);
11041 g_assert (child->priv->parent == self);
11043 self->priv->n_children += 1;
11045 self->priv->age += 1;
11047 /* if push_internal() has been called then we automatically set
11048 * the flag on the actor
11050 if (self->priv->internal_child)
11051 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11053 /* clutter_actor_reparent() will emit ::parent-set for us */
11054 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11055 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11059 /* If parent is mapped or realized, we need to also be mapped or
11060 * realized once we're inside the parent.
11062 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11064 /* propagate the parent's text direction to the child */
11065 text_dir = clutter_actor_get_text_direction (self);
11066 clutter_actor_set_text_direction (child, text_dir);
11069 if (child->priv->show_on_set_parent)
11070 clutter_actor_show (child);
11072 if (CLUTTER_ACTOR_IS_MAPPED (child))
11073 clutter_actor_queue_redraw (child);
11075 /* maintain the invariant that if an actor needs layout,
11076 * its parents do as well
11078 if (child->priv->needs_width_request ||
11079 child->priv->needs_height_request ||
11080 child->priv->needs_allocation)
11082 /* we work around the short-circuiting we do
11083 * in clutter_actor_queue_relayout() since we
11084 * want to force a relayout
11086 child->priv->needs_width_request = TRUE;
11087 child->priv->needs_height_request = TRUE;
11088 child->priv->needs_allocation = TRUE;
11090 clutter_actor_queue_relayout (child->priv->parent);
11093 if (emit_actor_added)
11094 g_signal_emit_by_name (self, "actor-added", child);
11096 if (notify_first_last)
11098 if (old_first_child != self->priv->first_child)
11099 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11101 if (old_last_child != self->priv->last_child)
11102 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11105 g_object_thaw_notify (G_OBJECT (self));
11109 * clutter_actor_add_child:
11110 * @self: a #ClutterActor
11111 * @child: a #ClutterActor
11113 * Adds @child to the children of @self.
11115 * This function will acquire a reference on @child that will only
11116 * be released when calling clutter_actor_remove_child().
11118 * This function will take into consideration the #ClutterActor:depth
11119 * of @child, and will keep the list of children sorted.
11121 * This function will emit the #ClutterContainer::actor-added signal
11127 clutter_actor_add_child (ClutterActor *self,
11128 ClutterActor *child)
11130 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11131 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11132 g_return_if_fail (self != child);
11133 g_return_if_fail (child->priv->parent == NULL);
11135 clutter_actor_add_child_internal (self, child,
11136 ADD_CHILD_DEFAULT_FLAGS,
11137 insert_child_at_depth,
11142 * clutter_actor_insert_child_at_index:
11143 * @self: a #ClutterActor
11144 * @child: a #ClutterActor
11145 * @index_: the index
11147 * Inserts @child into the list of children of @self, using the
11148 * given @index_. If @index_ is greater than the number of children
11149 * in @self, or is less than 0, then the new child is added at the end.
11151 * This function will acquire a reference on @child that will only
11152 * be released when calling clutter_actor_remove_child().
11154 * This function will not take into consideration the #ClutterActor:depth
11157 * This function will emit the #ClutterContainer::actor-added signal
11163 clutter_actor_insert_child_at_index (ClutterActor *self,
11164 ClutterActor *child,
11167 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11168 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11169 g_return_if_fail (self != child);
11170 g_return_if_fail (child->priv->parent == NULL);
11172 clutter_actor_add_child_internal (self, child,
11173 ADD_CHILD_DEFAULT_FLAGS,
11174 insert_child_at_index,
11175 GINT_TO_POINTER (index_));
11179 * clutter_actor_insert_child_above:
11180 * @self: a #ClutterActor
11181 * @child: a #ClutterActor
11182 * @sibling: (allow-none): a child of @self, or %NULL
11184 * Inserts @child into the list of children of @self, above another
11185 * child of @self or, if @sibling is %NULL, above all the children
11188 * This function will acquire a reference on @child that will only
11189 * be released when calling clutter_actor_remove_child().
11191 * This function will not take into consideration the #ClutterActor:depth
11194 * This function will emit the #ClutterContainer::actor-added signal
11200 clutter_actor_insert_child_above (ClutterActor *self,
11201 ClutterActor *child,
11202 ClutterActor *sibling)
11204 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11205 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11206 g_return_if_fail (self != child);
11207 g_return_if_fail (child != sibling);
11208 g_return_if_fail (child->priv->parent == NULL);
11209 g_return_if_fail (sibling == NULL ||
11210 (CLUTTER_IS_ACTOR (sibling) &&
11211 sibling->priv->parent == self));
11213 clutter_actor_add_child_internal (self, child,
11214 ADD_CHILD_DEFAULT_FLAGS,
11215 insert_child_above,
11220 * clutter_actor_insert_child_below:
11221 * @self: a #ClutterActor
11222 * @child: a #ClutterActor
11223 * @sibling: (allow-none): a child of @self, or %NULL
11225 * Inserts @child into the list of children of @self, below another
11226 * child of @self or, if @sibling is %NULL, below all the children
11229 * This function will acquire a reference on @child that will only
11230 * be released when calling clutter_actor_remove_child().
11232 * This function will not take into consideration the #ClutterActor:depth
11235 * This function will emit the #ClutterContainer::actor-added signal
11241 clutter_actor_insert_child_below (ClutterActor *self,
11242 ClutterActor *child,
11243 ClutterActor *sibling)
11245 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11246 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11247 g_return_if_fail (self != child);
11248 g_return_if_fail (child != sibling);
11249 g_return_if_fail (child->priv->parent == NULL);
11250 g_return_if_fail (sibling == NULL ||
11251 (CLUTTER_IS_ACTOR (sibling) &&
11252 sibling->priv->parent == self));
11254 clutter_actor_add_child_internal (self, child,
11255 ADD_CHILD_DEFAULT_FLAGS,
11256 insert_child_below,
11261 * clutter_actor_set_parent:
11262 * @self: A #ClutterActor
11263 * @parent: A new #ClutterActor parent
11265 * Sets the parent of @self to @parent.
11267 * This function will result in @parent acquiring a reference on @self,
11268 * eventually by sinking its floating reference first. The reference
11269 * will be released by clutter_actor_unparent().
11271 * This function should only be called by legacy #ClutterActor<!-- -->s
11272 * implementing the #ClutterContainer interface.
11274 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11277 clutter_actor_set_parent (ClutterActor *self,
11278 ClutterActor *parent)
11280 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11281 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11282 g_return_if_fail (self != parent);
11283 g_return_if_fail (self->priv->parent == NULL);
11285 /* as this function will be called inside ClutterContainer::add
11286 * implementations or when building up a composite actor, we have
11287 * to preserve the old behaviour, and not create child meta or
11288 * emit the ::actor-added signal, to avoid recursion or double
11291 clutter_actor_add_child_internal (parent, self,
11292 ADD_CHILD_LEGACY_FLAGS,
11293 insert_child_at_depth,
11298 * clutter_actor_get_parent:
11299 * @self: A #ClutterActor
11301 * Retrieves the parent of @self.
11303 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11304 * if no parent is set
11307 clutter_actor_get_parent (ClutterActor *self)
11309 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11311 return self->priv->parent;
11315 * clutter_actor_get_paint_visibility:
11316 * @self: A #ClutterActor
11318 * Retrieves the 'paint' visibility of an actor recursively checking for non
11321 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11323 * Return Value: %TRUE if the actor is visibile and will be painted.
11328 clutter_actor_get_paint_visibility (ClutterActor *actor)
11330 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11332 return CLUTTER_ACTOR_IS_MAPPED (actor);
11336 * clutter_actor_remove_child:
11337 * @self: a #ClutterActor
11338 * @child: a #ClutterActor
11340 * Removes @child from the children of @self.
11342 * This function will release the reference added by
11343 * clutter_actor_add_child(), so if you want to keep using @child
11344 * you will have to acquire a referenced on it before calling this
11347 * This function will emit the #ClutterContainer::actor-removed
11353 clutter_actor_remove_child (ClutterActor *self,
11354 ClutterActor *child)
11356 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11357 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11358 g_return_if_fail (self != child);
11359 g_return_if_fail (child->priv->parent != NULL);
11360 g_return_if_fail (child->priv->parent == self);
11362 clutter_actor_remove_child_internal (self, child,
11363 REMOVE_CHILD_DEFAULT_FLAGS);
11367 * clutter_actor_remove_all_children:
11368 * @self: a #ClutterActor
11370 * Removes all children of @self.
11372 * This function releases the reference added by inserting a child actor
11373 * in the list of children of @self.
11375 * If the reference count of a child drops to zero, the child will be
11376 * destroyed. If you want to ensure the destruction of all the children
11377 * of @self, use clutter_actor_destroy_all_children().
11382 clutter_actor_remove_all_children (ClutterActor *self)
11384 ClutterActorIter iter;
11386 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11388 if (self->priv->n_children == 0)
11391 g_object_freeze_notify (G_OBJECT (self));
11393 clutter_actor_iter_init (&iter, self);
11394 while (clutter_actor_iter_next (&iter, NULL))
11395 clutter_actor_iter_remove (&iter);
11397 g_object_thaw_notify (G_OBJECT (self));
11400 g_assert (self->priv->first_child == NULL);
11401 g_assert (self->priv->last_child == NULL);
11402 g_assert (self->priv->n_children == 0);
11406 * clutter_actor_destroy_all_children:
11407 * @self: a #ClutterActor
11409 * Destroys all children of @self.
11411 * This function releases the reference added by inserting a child
11412 * actor in the list of children of @self, and ensures that the
11413 * #ClutterActor::destroy signal is emitted on each child of the
11416 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11417 * when its reference count drops to 0; the default handler of the
11418 * #ClutterActor::destroy signal will destroy all the children of an
11419 * actor. This function ensures that all children are destroyed, instead
11420 * of just removed from @self, unlike clutter_actor_remove_all_children()
11421 * which will merely release the reference and remove each child.
11423 * Unless you acquired an additional reference on each child of @self
11424 * prior to calling clutter_actor_remove_all_children() and want to reuse
11425 * the actors, you should use clutter_actor_destroy_all_children() in
11426 * order to make sure that children are destroyed and signal handlers
11427 * are disconnected even in cases where circular references prevent this
11428 * from automatically happening through reference counting alone.
11433 clutter_actor_destroy_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_destroy (&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);
11456 typedef struct _InsertBetweenData {
11457 ClutterActor *prev_sibling;
11458 ClutterActor *next_sibling;
11459 } InsertBetweenData;
11462 insert_child_between (ClutterActor *self,
11463 ClutterActor *child,
11466 InsertBetweenData *data = data_;
11467 ClutterActor *prev_sibling = data->prev_sibling;
11468 ClutterActor *next_sibling = data->next_sibling;
11470 child->priv->parent = self;
11471 child->priv->prev_sibling = prev_sibling;
11472 child->priv->next_sibling = next_sibling;
11474 if (prev_sibling != NULL)
11475 prev_sibling->priv->next_sibling = child;
11477 if (next_sibling != NULL)
11478 next_sibling->priv->prev_sibling = child;
11480 if (child->priv->prev_sibling == NULL)
11481 self->priv->first_child = child;
11483 if (child->priv->next_sibling == NULL)
11484 self->priv->last_child = child;
11488 * clutter_actor_replace_child:
11489 * @self: a #ClutterActor
11490 * @old_child: the child of @self to replace
11491 * @new_child: the #ClutterActor to replace @old_child
11493 * Replaces @old_child with @new_child in the list of children of @self.
11498 clutter_actor_replace_child (ClutterActor *self,
11499 ClutterActor *old_child,
11500 ClutterActor *new_child)
11502 ClutterActor *prev_sibling, *next_sibling;
11503 InsertBetweenData clos;
11505 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11506 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11507 g_return_if_fail (old_child->priv->parent == self);
11508 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11509 g_return_if_fail (old_child != new_child);
11510 g_return_if_fail (new_child != self);
11511 g_return_if_fail (new_child->priv->parent == NULL);
11513 prev_sibling = old_child->priv->prev_sibling;
11514 next_sibling = old_child->priv->next_sibling;
11515 clutter_actor_remove_child_internal (self, old_child,
11516 REMOVE_CHILD_DEFAULT_FLAGS);
11518 clos.prev_sibling = prev_sibling;
11519 clos.next_sibling = next_sibling;
11520 clutter_actor_add_child_internal (self, new_child,
11521 ADD_CHILD_DEFAULT_FLAGS,
11522 insert_child_between,
11527 * clutter_actor_unparent:
11528 * @self: a #ClutterActor
11530 * Removes the parent of @self.
11532 * This will cause the parent of @self to release the reference
11533 * acquired when calling clutter_actor_set_parent(), so if you
11534 * want to keep @self you will have to acquire a reference of
11535 * your own, through g_object_ref().
11537 * This function should only be called by legacy #ClutterActor<!-- -->s
11538 * implementing the #ClutterContainer interface.
11542 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11545 clutter_actor_unparent (ClutterActor *self)
11547 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11549 if (self->priv->parent == NULL)
11552 clutter_actor_remove_child_internal (self->priv->parent, self,
11553 REMOVE_CHILD_LEGACY_FLAGS);
11557 * clutter_actor_reparent:
11558 * @self: a #ClutterActor
11559 * @new_parent: the new #ClutterActor parent
11561 * Resets the parent actor of @self.
11563 * This function is logically equivalent to calling clutter_actor_unparent()
11564 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11565 * ensures the child is not finalized when unparented, and emits the
11566 * #ClutterActor::parent-set signal only once.
11568 * In reality, calling this function is less useful than it sounds, as some
11569 * application code may rely on changes in the intermediate state between
11570 * removal and addition of the actor from its old parent to the @new_parent.
11571 * Thus, it is strongly encouraged to avoid using this function in application
11576 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11577 * clutter_actor_add_child() instead; remember to take a reference on
11578 * the actor being removed before calling clutter_actor_remove_child()
11579 * to avoid the reference count dropping to zero and the actor being
11583 clutter_actor_reparent (ClutterActor *self,
11584 ClutterActor *new_parent)
11586 ClutterActorPrivate *priv;
11588 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11589 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11590 g_return_if_fail (self != new_parent);
11592 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11594 g_warning ("Cannot set a parent on a toplevel actor");
11598 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11600 g_warning ("Cannot set a parent currently being destroyed");
11606 if (priv->parent != new_parent)
11608 ClutterActor *old_parent;
11610 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11612 old_parent = priv->parent;
11614 g_object_ref (self);
11616 if (old_parent != NULL)
11618 /* go through the Container implementation if this is a regular
11619 * child and not an internal one
11621 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11623 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11625 /* this will have to call unparent() */
11626 clutter_container_remove_actor (parent, self);
11629 clutter_actor_remove_child_internal (old_parent, self,
11630 REMOVE_CHILD_LEGACY_FLAGS);
11633 /* Note, will call set_parent() */
11634 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11635 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11637 clutter_actor_add_child_internal (new_parent, self,
11638 ADD_CHILD_LEGACY_FLAGS,
11639 insert_child_at_depth,
11642 /* we emit the ::parent-set signal once */
11643 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11645 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11647 /* the IN_REPARENT flag suspends state updates */
11648 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11650 g_object_unref (self);
11655 * clutter_actor_contains:
11656 * @self: A #ClutterActor
11657 * @descendant: A #ClutterActor, possibly contained in @self
11659 * Determines if @descendant is contained inside @self (either as an
11660 * immediate child, or as a deeper descendant). If @self and
11661 * @descendant point to the same actor then it will also return %TRUE.
11663 * Return value: whether @descendent is contained within @self
11668 clutter_actor_contains (ClutterActor *self,
11669 ClutterActor *descendant)
11671 ClutterActor *actor;
11673 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11674 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11676 for (actor = descendant; actor; actor = actor->priv->parent)
11684 * clutter_actor_set_child_above_sibling:
11685 * @self: a #ClutterActor
11686 * @child: a #ClutterActor child of @self
11687 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11689 * Sets @child to be above @sibling in the list of children of @self.
11691 * If @sibling is %NULL, @child will be the new last child of @self.
11693 * This function is logically equivalent to removing @child and using
11694 * clutter_actor_insert_child_above(), but it will not emit signals
11695 * or change state on @child.
11700 clutter_actor_set_child_above_sibling (ClutterActor *self,
11701 ClutterActor *child,
11702 ClutterActor *sibling)
11704 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11705 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11706 g_return_if_fail (child->priv->parent == self);
11707 g_return_if_fail (child != sibling);
11708 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11710 if (sibling != NULL)
11711 g_return_if_fail (sibling->priv->parent == self);
11713 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11714 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11715 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11718 /* we don't want to change the state of child, or emit signals, or
11719 * regenerate ChildMeta instances here, but we still want to follow
11720 * the correct sequence of steps encoded in remove_child() and
11721 * add_child(), so that correctness is ensured, and we only go
11722 * through one known code path.
11724 g_object_ref (child);
11725 clutter_actor_remove_child_internal (self, child, 0);
11726 clutter_actor_add_child_internal (self, child,
11727 ADD_CHILD_NOTIFY_FIRST_LAST,
11728 insert_child_above,
11731 clutter_actor_queue_relayout (self);
11735 * clutter_actor_set_child_below_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 below @sibling in the list of children of @self.
11742 * If @sibling is %NULL, @child will be the new first child of @self.
11744 * This function is logically equivalent to removing @self and using
11745 * clutter_actor_insert_child_below(), but it will not emit signals
11746 * or change state on @child.
11751 clutter_actor_set_child_below_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 /* see the comment in set_child_above_sibling() */
11770 g_object_ref (child);
11771 clutter_actor_remove_child_internal (self, child, 0);
11772 clutter_actor_add_child_internal (self, child,
11773 ADD_CHILD_NOTIFY_FIRST_LAST,
11774 insert_child_below,
11777 clutter_actor_queue_relayout (self);
11781 * clutter_actor_set_child_at_index:
11782 * @self: a #ClutterActor
11783 * @child: a #ClutterActor child of @self
11784 * @index_: the new index for @child
11786 * Changes the index of @child in the list of children of @self.
11788 * This function is logically equivalent to removing @child and
11789 * calling clutter_actor_insert_child_at_index(), but it will not
11790 * emit signals or change state on @child.
11795 clutter_actor_set_child_at_index (ClutterActor *self,
11796 ClutterActor *child,
11799 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11800 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11801 g_return_if_fail (child->priv->parent == self);
11802 g_return_if_fail (index_ <= self->priv->n_children);
11804 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11805 CLUTTER_ACTOR_IN_DESTRUCTION (child))
11808 g_object_ref (child);
11809 clutter_actor_remove_child_internal (self, child, 0);
11810 clutter_actor_add_child_internal (self, child,
11811 ADD_CHILD_NOTIFY_FIRST_LAST,
11812 insert_child_at_index,
11813 GINT_TO_POINTER (index_));
11815 clutter_actor_queue_relayout (self);
11819 * clutter_actor_raise:
11820 * @self: A #ClutterActor
11821 * @below: (allow-none): A #ClutterActor to raise above.
11823 * Puts @self above @below.
11825 * Both actors must have the same parent, and the parent must implement
11826 * the #ClutterContainer interface
11828 * This function calls clutter_container_raise_child() internally.
11830 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11833 clutter_actor_raise (ClutterActor *self,
11834 ClutterActor *below)
11836 ClutterActor *parent;
11838 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11840 parent = clutter_actor_get_parent (self);
11841 if (parent == NULL)
11843 g_warning ("%s: Actor '%s' is not inside a container",
11845 _clutter_actor_get_debug_name (self));
11851 if (parent != clutter_actor_get_parent (below))
11853 g_warning ("%s Actor '%s' is not in the same container as "
11856 _clutter_actor_get_debug_name (self),
11857 _clutter_actor_get_debug_name (below));
11862 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11866 * clutter_actor_lower:
11867 * @self: A #ClutterActor
11868 * @above: (allow-none): A #ClutterActor to lower below
11870 * Puts @self below @above.
11872 * Both actors must have the same parent, and the parent must implement
11873 * the #ClutterContainer interface.
11875 * This function calls clutter_container_lower_child() internally.
11877 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11880 clutter_actor_lower (ClutterActor *self,
11881 ClutterActor *above)
11883 ClutterActor *parent;
11885 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11887 parent = clutter_actor_get_parent (self);
11888 if (parent == NULL)
11890 g_warning ("%s: Actor of type %s is not inside a container",
11892 _clutter_actor_get_debug_name (self));
11898 if (parent != clutter_actor_get_parent (above))
11900 g_warning ("%s: Actor '%s' is not in the same container as "
11903 _clutter_actor_get_debug_name (self),
11904 _clutter_actor_get_debug_name (above));
11909 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11913 * clutter_actor_raise_top:
11914 * @self: A #ClutterActor
11916 * Raises @self to the top.
11918 * This function calls clutter_actor_raise() internally.
11920 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11921 * a %NULL sibling, instead.
11924 clutter_actor_raise_top (ClutterActor *self)
11926 clutter_actor_raise (self, NULL);
11930 * clutter_actor_lower_bottom:
11931 * @self: A #ClutterActor
11933 * Lowers @self to the bottom.
11935 * This function calls clutter_actor_lower() internally.
11937 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11938 * a %NULL sibling, instead.
11941 clutter_actor_lower_bottom (ClutterActor *self)
11943 clutter_actor_lower (self, NULL);
11951 * clutter_actor_event:
11952 * @actor: a #ClutterActor
11953 * @event: a #ClutterEvent
11954 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11956 * This function is used to emit an event on the main stage.
11957 * You should rarely need to use this function, except for
11958 * synthetising events.
11960 * Return value: the return value from the signal emission: %TRUE
11961 * if the actor handled the event, or %FALSE if the event was
11967 clutter_actor_event (ClutterActor *actor,
11968 ClutterEvent *event,
11971 gboolean retval = FALSE;
11972 gint signal_num = -1;
11974 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11975 g_return_val_if_fail (event != NULL, FALSE);
11977 g_object_ref (actor);
11981 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11987 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11991 switch (event->type)
11993 case CLUTTER_NOTHING:
11995 case CLUTTER_BUTTON_PRESS:
11996 signal_num = BUTTON_PRESS_EVENT;
11998 case CLUTTER_BUTTON_RELEASE:
11999 signal_num = BUTTON_RELEASE_EVENT;
12001 case CLUTTER_SCROLL:
12002 signal_num = SCROLL_EVENT;
12004 case CLUTTER_KEY_PRESS:
12005 signal_num = KEY_PRESS_EVENT;
12007 case CLUTTER_KEY_RELEASE:
12008 signal_num = KEY_RELEASE_EVENT;
12010 case CLUTTER_MOTION:
12011 signal_num = MOTION_EVENT;
12013 case CLUTTER_ENTER:
12014 signal_num = ENTER_EVENT;
12016 case CLUTTER_LEAVE:
12017 signal_num = LEAVE_EVENT;
12019 case CLUTTER_DELETE:
12020 case CLUTTER_DESTROY_NOTIFY:
12021 case CLUTTER_CLIENT_MESSAGE:
12027 if (signal_num != -1)
12028 g_signal_emit (actor, actor_signals[signal_num], 0,
12033 g_object_unref (actor);
12039 * clutter_actor_set_reactive:
12040 * @actor: a #ClutterActor
12041 * @reactive: whether the actor should be reactive to events
12043 * Sets @actor as reactive. Reactive actors will receive events.
12048 clutter_actor_set_reactive (ClutterActor *actor,
12051 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12053 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12057 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12059 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12061 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12065 * clutter_actor_get_reactive:
12066 * @actor: a #ClutterActor
12068 * Checks whether @actor is marked as reactive.
12070 * Return value: %TRUE if the actor is reactive
12075 clutter_actor_get_reactive (ClutterActor *actor)
12077 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12079 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12083 * clutter_actor_get_anchor_point:
12084 * @self: a #ClutterActor
12085 * @anchor_x: (out): return location for the X coordinate of the anchor point
12086 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12088 * Gets the current anchor point of the @actor in pixels.
12093 clutter_actor_get_anchor_point (ClutterActor *self,
12097 const ClutterTransformInfo *info;
12099 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12101 info = _clutter_actor_get_transform_info_or_defaults (self);
12102 clutter_anchor_coord_get_units (self, &info->anchor,
12109 * clutter_actor_set_anchor_point:
12110 * @self: a #ClutterActor
12111 * @anchor_x: X coordinate of the anchor point
12112 * @anchor_y: Y coordinate of the anchor point
12114 * Sets an anchor point for @self. The anchor point is a point in the
12115 * coordinate space of an actor to which the actor position within its
12116 * parent is relative; the default is (0, 0), i.e. the top-left corner
12122 clutter_actor_set_anchor_point (ClutterActor *self,
12126 ClutterTransformInfo *info;
12127 ClutterActorPrivate *priv;
12128 gboolean changed = FALSE;
12129 gfloat old_anchor_x, old_anchor_y;
12132 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12134 obj = G_OBJECT (self);
12136 info = _clutter_actor_get_transform_info (self);
12138 g_object_freeze_notify (obj);
12140 clutter_anchor_coord_get_units (self, &info->anchor,
12145 if (info->anchor.is_fractional)
12146 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12148 if (old_anchor_x != anchor_x)
12150 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12154 if (old_anchor_y != anchor_y)
12156 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12160 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12164 priv->transform_valid = FALSE;
12165 clutter_actor_queue_redraw (self);
12168 g_object_thaw_notify (obj);
12172 * clutter_actor_get_anchor_point_gravity:
12173 * @self: a #ClutterActor
12175 * Retrieves the anchor position expressed as a #ClutterGravity. If
12176 * the anchor point was specified using pixels or units this will
12177 * return %CLUTTER_GRAVITY_NONE.
12179 * Return value: the #ClutterGravity used by the anchor point
12184 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12186 const ClutterTransformInfo *info;
12188 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12190 info = _clutter_actor_get_transform_info_or_defaults (self);
12192 return clutter_anchor_coord_get_gravity (&info->anchor);
12196 * clutter_actor_move_anchor_point:
12197 * @self: a #ClutterActor
12198 * @anchor_x: X coordinate of the anchor point
12199 * @anchor_y: Y coordinate of the anchor point
12201 * Sets an anchor point for the actor, and adjusts the actor postion so that
12202 * the relative position of the actor toward its parent remains the same.
12207 clutter_actor_move_anchor_point (ClutterActor *self,
12211 gfloat old_anchor_x, old_anchor_y;
12212 const ClutterTransformInfo *info;
12214 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12216 info = _clutter_actor_get_transform_info (self);
12217 clutter_anchor_coord_get_units (self, &info->anchor,
12222 g_object_freeze_notify (G_OBJECT (self));
12224 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12226 if (self->priv->position_set)
12227 clutter_actor_move_by (self,
12228 anchor_x - old_anchor_x,
12229 anchor_y - old_anchor_y);
12231 g_object_thaw_notify (G_OBJECT (self));
12235 * clutter_actor_move_anchor_point_from_gravity:
12236 * @self: a #ClutterActor
12237 * @gravity: #ClutterGravity.
12239 * Sets an anchor point on the actor based on the given gravity, adjusting the
12240 * actor postion so that its relative position within its parent remains
12243 * Since version 1.0 the anchor point will be stored as a gravity so
12244 * that if the actor changes size then the anchor point will move. For
12245 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12246 * and later double the size of the actor, the anchor point will move
12247 * to the bottom right.
12252 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12253 ClutterGravity gravity)
12255 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12256 const ClutterTransformInfo *info;
12257 ClutterActorPrivate *priv;
12259 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12262 info = _clutter_actor_get_transform_info (self);
12264 g_object_freeze_notify (G_OBJECT (self));
12266 clutter_anchor_coord_get_units (self, &info->anchor,
12270 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12271 clutter_anchor_coord_get_units (self, &info->anchor,
12276 if (priv->position_set)
12277 clutter_actor_move_by (self,
12278 new_anchor_x - old_anchor_x,
12279 new_anchor_y - old_anchor_y);
12281 g_object_thaw_notify (G_OBJECT (self));
12285 * clutter_actor_set_anchor_point_from_gravity:
12286 * @self: a #ClutterActor
12287 * @gravity: #ClutterGravity.
12289 * Sets an anchor point on the actor, based on the given gravity (this is a
12290 * convenience function wrapping clutter_actor_set_anchor_point()).
12292 * Since version 1.0 the anchor point will be stored as a gravity so
12293 * that if the actor changes size then the anchor point will move. For
12294 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12295 * and later double the size of the actor, the anchor point will move
12296 * to the bottom right.
12301 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12302 ClutterGravity gravity)
12304 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12306 if (gravity == CLUTTER_GRAVITY_NONE)
12307 clutter_actor_set_anchor_point (self, 0, 0);
12310 GObject *obj = G_OBJECT (self);
12311 ClutterTransformInfo *info;
12313 g_object_freeze_notify (obj);
12315 info = _clutter_actor_get_transform_info (self);
12316 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12318 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12319 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12320 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12322 self->priv->transform_valid = FALSE;
12324 clutter_actor_queue_redraw (self);
12326 g_object_thaw_notify (obj);
12331 clutter_actor_store_content_box (ClutterActor *self,
12332 const ClutterActorBox *box)
12336 self->priv->content_box = *box;
12337 self->priv->content_box_valid = TRUE;
12340 self->priv->content_box_valid = FALSE;
12342 clutter_actor_queue_redraw (self);
12344 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12348 clutter_container_iface_init (ClutterContainerIface *iface)
12350 /* we don't override anything, as ClutterContainer already has a default
12351 * implementation that we can use, and which calls into our own API.
12366 parse_units (ClutterActor *self,
12367 ParseDimension dimension,
12370 GValue value = G_VALUE_INIT;
12373 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12376 json_node_get_value (node, &value);
12378 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12380 retval = (gfloat) g_value_get_int64 (&value);
12382 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12384 retval = g_value_get_double (&value);
12386 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12388 ClutterUnits units;
12391 res = clutter_units_from_string (&units, g_value_get_string (&value));
12393 retval = clutter_units_to_pixels (&units);
12396 g_warning ("Invalid value '%s': integers, strings or floating point "
12397 "values can be used for the x, y, width and height "
12398 "properties. Valid modifiers for strings are 'px', 'mm', "
12400 g_value_get_string (&value));
12406 g_warning ("Invalid value of type '%s': integers, strings of floating "
12407 "point values can be used for the x, y, width, height "
12408 "anchor-x and anchor-y properties.",
12409 g_type_name (G_VALUE_TYPE (&value)));
12412 g_value_unset (&value);
12418 ClutterRotateAxis axis;
12427 static inline gboolean
12428 parse_rotation_array (ClutterActor *actor,
12430 RotationInfo *info)
12434 if (json_array_get_length (array) != 2)
12438 element = json_array_get_element (array, 0);
12439 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12440 info->angle = json_node_get_double (element);
12445 element = json_array_get_element (array, 1);
12446 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12448 JsonArray *center = json_node_get_array (element);
12450 if (json_array_get_length (center) != 2)
12453 switch (info->axis)
12455 case CLUTTER_X_AXIS:
12456 info->center_y = parse_units (actor, PARSE_Y,
12457 json_array_get_element (center, 0));
12458 info->center_z = parse_units (actor, PARSE_Y,
12459 json_array_get_element (center, 1));
12462 case CLUTTER_Y_AXIS:
12463 info->center_x = parse_units (actor, PARSE_X,
12464 json_array_get_element (center, 0));
12465 info->center_z = parse_units (actor, PARSE_X,
12466 json_array_get_element (center, 1));
12469 case CLUTTER_Z_AXIS:
12470 info->center_x = parse_units (actor, PARSE_X,
12471 json_array_get_element (center, 0));
12472 info->center_y = parse_units (actor, PARSE_Y,
12473 json_array_get_element (center, 1));
12482 parse_rotation (ClutterActor *actor,
12484 RotationInfo *info)
12488 gboolean retval = FALSE;
12490 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12492 g_warning ("Invalid node of type '%s' found, expecting an array",
12493 json_node_type_name (node));
12497 array = json_node_get_array (node);
12498 len = json_array_get_length (array);
12500 for (i = 0; i < len; i++)
12502 JsonNode *element = json_array_get_element (array, i);
12503 JsonObject *object;
12506 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12508 g_warning ("Invalid node of type '%s' found, expecting an object",
12509 json_node_type_name (element));
12513 object = json_node_get_object (element);
12515 if (json_object_has_member (object, "x-axis"))
12517 member = json_object_get_member (object, "x-axis");
12519 info->axis = CLUTTER_X_AXIS;
12521 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12523 info->angle = json_node_get_double (member);
12526 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12527 retval = parse_rotation_array (actor,
12528 json_node_get_array (member),
12533 else if (json_object_has_member (object, "y-axis"))
12535 member = json_object_get_member (object, "y-axis");
12537 info->axis = CLUTTER_Y_AXIS;
12539 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12541 info->angle = json_node_get_double (member);
12544 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12545 retval = parse_rotation_array (actor,
12546 json_node_get_array (member),
12551 else if (json_object_has_member (object, "z-axis"))
12553 member = json_object_get_member (object, "z-axis");
12555 info->axis = CLUTTER_Z_AXIS;
12557 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12559 info->angle = json_node_get_double (member);
12562 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12563 retval = parse_rotation_array (actor,
12564 json_node_get_array (member),
12575 parse_actor_metas (ClutterScript *script,
12576 ClutterActor *actor,
12579 GList *elements, *l;
12580 GSList *retval = NULL;
12582 if (!JSON_NODE_HOLDS_ARRAY (node))
12585 elements = json_array_get_elements (json_node_get_array (node));
12587 for (l = elements; l != NULL; l = l->next)
12589 JsonNode *element = l->data;
12590 const gchar *id_ = _clutter_script_get_id_from_node (element);
12593 if (id_ == NULL || *id_ == '\0')
12596 meta = clutter_script_get_object (script, id_);
12600 retval = g_slist_prepend (retval, meta);
12603 g_list_free (elements);
12605 return g_slist_reverse (retval);
12609 parse_behaviours (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);
12625 GObject *behaviour;
12627 if (id_ == NULL || *id_ == '\0')
12630 behaviour = clutter_script_get_object (script, id_);
12631 if (behaviour == NULL)
12634 retval = g_slist_prepend (retval, behaviour);
12637 g_list_free (elements);
12639 return g_slist_reverse (retval);
12643 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12644 ClutterScript *script,
12649 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12650 gboolean retval = FALSE;
12652 if ((name[0] == 'x' && name[1] == '\0') ||
12653 (name[0] == 'y' && name[1] == '\0') ||
12654 (strcmp (name, "width") == 0) ||
12655 (strcmp (name, "height") == 0) ||
12656 (strcmp (name, "anchor_x") == 0) ||
12657 (strcmp (name, "anchor_y") == 0))
12659 ParseDimension dimension;
12662 if (name[0] == 'x')
12663 dimension = PARSE_X;
12664 else if (name[0] == 'y')
12665 dimension = PARSE_Y;
12666 else if (name[0] == 'w')
12667 dimension = PARSE_WIDTH;
12668 else if (name[0] == 'h')
12669 dimension = PARSE_HEIGHT;
12670 else if (name[0] == 'a' && name[7] == 'x')
12671 dimension = PARSE_ANCHOR_X;
12672 else if (name[0] == 'a' && name[7] == 'y')
12673 dimension = PARSE_ANCHOR_Y;
12677 units = parse_units (actor, dimension, node);
12679 /* convert back to pixels: all properties are pixel-based */
12680 g_value_init (value, G_TYPE_FLOAT);
12681 g_value_set_float (value, units);
12685 else if (strcmp (name, "rotation") == 0)
12687 RotationInfo *info;
12689 info = g_slice_new0 (RotationInfo);
12690 retval = parse_rotation (actor, node, info);
12694 g_value_init (value, G_TYPE_POINTER);
12695 g_value_set_pointer (value, info);
12698 g_slice_free (RotationInfo, info);
12700 else if (strcmp (name, "behaviours") == 0)
12704 #ifdef CLUTTER_ENABLE_DEBUG
12705 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12706 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12707 "and it should not be used in newly "
12708 "written ClutterScript definitions.");
12711 l = parse_behaviours (script, actor, node);
12713 g_value_init (value, G_TYPE_POINTER);
12714 g_value_set_pointer (value, l);
12718 else if (strcmp (name, "actions") == 0 ||
12719 strcmp (name, "constraints") == 0 ||
12720 strcmp (name, "effects") == 0)
12724 l = parse_actor_metas (script, actor, node);
12726 g_value_init (value, G_TYPE_POINTER);
12727 g_value_set_pointer (value, l);
12736 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12737 ClutterScript *script,
12739 const GValue *value)
12741 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12743 #ifdef CLUTTER_ENABLE_DEBUG
12744 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12746 gchar *tmp = g_strdup_value_contents (value);
12748 CLUTTER_NOTE (SCRIPT,
12749 "in ClutterActor::set_custom_property('%s') = %s",
12755 #endif /* CLUTTER_ENABLE_DEBUG */
12757 if (strcmp (name, "rotation") == 0)
12759 RotationInfo *info;
12761 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12764 info = g_value_get_pointer (value);
12766 clutter_actor_set_rotation (actor,
12767 info->axis, info->angle,
12772 g_slice_free (RotationInfo, info);
12777 if (strcmp (name, "behaviours") == 0)
12779 GSList *behaviours, *l;
12781 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12784 behaviours = g_value_get_pointer (value);
12785 for (l = behaviours; l != NULL; l = l->next)
12787 ClutterBehaviour *behaviour = l->data;
12789 clutter_behaviour_apply (behaviour, actor);
12792 g_slist_free (behaviours);
12797 if (strcmp (name, "actions") == 0 ||
12798 strcmp (name, "constraints") == 0 ||
12799 strcmp (name, "effects") == 0)
12803 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12806 metas = g_value_get_pointer (value);
12807 for (l = metas; l != NULL; l = l->next)
12809 if (name[0] == 'a')
12810 clutter_actor_add_action (actor, l->data);
12812 if (name[0] == 'c')
12813 clutter_actor_add_constraint (actor, l->data);
12815 if (name[0] == 'e')
12816 clutter_actor_add_effect (actor, l->data);
12819 g_slist_free (metas);
12824 g_object_set_property (G_OBJECT (scriptable), name, value);
12828 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12830 iface->parse_custom_node = clutter_actor_parse_custom_node;
12831 iface->set_custom_property = clutter_actor_set_custom_property;
12834 static ClutterActorMeta *
12835 get_meta_from_animation_property (ClutterActor *actor,
12839 ClutterActorPrivate *priv = actor->priv;
12840 ClutterActorMeta *meta = NULL;
12843 /* if this is not a special property, fall through */
12844 if (name[0] != '@')
12847 /* detect the properties named using the following spec:
12849 * @<section>.<meta-name>.<property-name>
12851 * where <section> can be one of the following:
12857 * and <meta-name> is the name set on a specific ActorMeta
12860 tokens = g_strsplit (name + 1, ".", -1);
12861 if (tokens == NULL || g_strv_length (tokens) != 3)
12863 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12865 g_strfreev (tokens);
12869 if (strcmp (tokens[0], "actions") == 0)
12870 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12872 if (strcmp (tokens[0], "constraints") == 0)
12873 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12875 if (strcmp (tokens[0], "effects") == 0)
12876 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12878 if (name_p != NULL)
12879 *name_p = g_strdup (tokens[2]);
12881 CLUTTER_NOTE (ANIMATION,
12882 "Looking for property '%s' of object '%s' in section '%s'",
12887 g_strfreev (tokens);
12892 static GParamSpec *
12893 clutter_actor_find_property (ClutterAnimatable *animatable,
12894 const gchar *property_name)
12896 ClutterActorMeta *meta = NULL;
12897 GObjectClass *klass = NULL;
12898 GParamSpec *pspec = NULL;
12899 gchar *p_name = NULL;
12901 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12907 klass = G_OBJECT_GET_CLASS (meta);
12909 pspec = g_object_class_find_property (klass, p_name);
12913 klass = G_OBJECT_GET_CLASS (animatable);
12915 pspec = g_object_class_find_property (klass, property_name);
12924 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12925 const gchar *property_name,
12928 ClutterActorMeta *meta = NULL;
12929 gchar *p_name = NULL;
12931 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12936 g_object_get_property (G_OBJECT (meta), p_name, initial);
12938 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12944 * clutter_actor_set_animatable_property:
12945 * @actor: a #ClutterActor
12946 * @prop_id: the paramspec id
12947 * @value: the value to set
12948 * @pspec: the paramspec
12950 * Sets values of animatable properties.
12952 * This is a variant of clutter_actor_set_property() that gets called
12953 * by the #ClutterAnimatable implementation of #ClutterActor for the
12954 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12957 * Unlike the implementation of #GObjectClass.set_property(), this
12958 * function will not update the interval if a transition involving an
12959 * animatable property is in progress - this avoids cycles with the
12960 * transition API calling the public API.
12963 clutter_actor_set_animatable_property (ClutterActor *actor,
12965 const GValue *value,
12968 GObject *obj = G_OBJECT (actor);
12970 g_object_freeze_notify (obj);
12975 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12979 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12983 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12987 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12991 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12995 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12998 case PROP_BACKGROUND_COLOR:
12999 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13003 clutter_actor_set_scale_factor_internal (actor,
13004 g_value_get_double (value),
13009 clutter_actor_set_scale_factor_internal (actor,
13010 g_value_get_double (value),
13014 case PROP_ROTATION_ANGLE_X:
13015 clutter_actor_set_rotation_angle_internal (actor,
13017 g_value_get_double (value));
13020 case PROP_ROTATION_ANGLE_Y:
13021 clutter_actor_set_rotation_angle_internal (actor,
13023 g_value_get_double (value));
13026 case PROP_ROTATION_ANGLE_Z:
13027 clutter_actor_set_rotation_angle_internal (actor,
13029 g_value_get_double (value));
13032 case PROP_CONTENT_BOX:
13033 clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13037 g_object_set_property (obj, pspec->name, value);
13041 g_object_thaw_notify (obj);
13045 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13046 const gchar *property_name,
13047 const GValue *final)
13049 ClutterActor *actor = CLUTTER_ACTOR (animatable);
13050 ClutterActorMeta *meta = NULL;
13051 gchar *p_name = NULL;
13053 meta = get_meta_from_animation_property (actor,
13057 g_object_set_property (G_OBJECT (meta), p_name, final);
13060 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13063 pspec = g_object_class_find_property (obj_class, property_name);
13065 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13067 /* XXX - I'm going to the special hell for this */
13068 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13071 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13078 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13080 iface->find_property = clutter_actor_find_property;
13081 iface->get_initial_state = clutter_actor_get_initial_state;
13082 iface->set_final_state = clutter_actor_set_final_state;
13086 * clutter_actor_transform_stage_point:
13087 * @self: A #ClutterActor
13088 * @x: (in): x screen coordinate of the point to unproject
13089 * @y: (in): y screen coordinate of the point to unproject
13090 * @x_out: (out): return location for the unprojected x coordinance
13091 * @y_out: (out): return location for the unprojected y coordinance
13093 * This function translates screen coordinates (@x, @y) to
13094 * coordinates relative to the actor. For example, it can be used to translate
13095 * screen events from global screen coordinates into actor-local coordinates.
13097 * The conversion can fail, notably if the transform stack results in the
13098 * actor being projected on the screen as a mere line.
13100 * The conversion should not be expected to be pixel-perfect due to the
13101 * nature of the operation. In general the error grows when the skewing
13102 * of the actor rectangle on screen increases.
13104 * <note><para>This function can be computationally intensive.</para></note>
13106 * <note><para>This function only works when the allocation is up-to-date,
13107 * i.e. inside of paint().</para></note>
13109 * Return value: %TRUE if conversion was successful.
13114 clutter_actor_transform_stage_point (ClutterActor *self,
13120 ClutterVertex v[4];
13123 int du, dv, xi, yi;
13125 float xf, yf, wf, det;
13126 ClutterActorPrivate *priv;
13128 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13132 /* This implementation is based on the quad -> quad projection algorithm
13133 * described by Paul Heckbert in:
13135 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13137 * and the sample implementation at:
13139 * http://www.cs.cmu.edu/~ph/src/texfund/
13141 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13142 * quad to rectangle only, which significantly simplifies things; the
13143 * function calls have been unrolled, and most of the math is done in fixed
13147 clutter_actor_get_abs_allocation_vertices (self, v);
13149 /* Keeping these as ints simplifies the multiplication (no significant
13150 * loss of precision here).
13152 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13153 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13158 #define UX2FP(x) (x)
13159 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13161 /* First, find mapping from unit uv square to xy quadrilateral; this
13162 * equivalent to the pmap_square_quad() functions in the sample
13163 * implementation, which we can simplify, since our target is always
13166 px = v[0].x - v[1].x + v[3].x - v[2].x;
13167 py = v[0].y - v[1].y + v[3].y - v[2].y;
13171 /* affine transform */
13172 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13173 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13174 RQ[2][0] = UX2FP (v[0].x);
13175 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13176 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13177 RQ[2][1] = UX2FP (v[0].y);
13184 /* projective transform */
13185 double dx1, dx2, dy1, dy2, del;
13187 dx1 = UX2FP (v[1].x - v[3].x);
13188 dx2 = UX2FP (v[2].x - v[3].x);
13189 dy1 = UX2FP (v[1].y - v[3].y);
13190 dy2 = UX2FP (v[2].y - v[3].y);
13192 del = DET2FP (dx1, dx2, dy1, dy2);
13197 * The division here needs to be done in floating point for
13198 * precisions reasons.
13200 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13201 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13202 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13204 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13205 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13206 RQ[2][0] = UX2FP (v[0].x);
13207 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13208 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13209 RQ[2][1] = UX2FP (v[0].y);
13213 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13214 * square. Since our rectangle is based at 0,0 we only need to scale.
13224 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13227 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13228 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13229 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13230 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13231 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13232 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13233 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13234 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13235 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13238 * Check the resulting matrix is OK.
13240 det = (RQ[0][0] * ST[0][0])
13241 + (RQ[0][1] * ST[0][1])
13242 + (RQ[0][2] * ST[0][2]);
13247 * Now transform our point with the ST matrix; the notional w
13248 * coordinate is 1, hence the last part is simply added.
13253 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13254 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13255 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13273 static ClutterGeometry*
13274 clutter_geometry_copy (const ClutterGeometry *geometry)
13276 return g_slice_dup (ClutterGeometry, geometry);
13280 clutter_geometry_free (ClutterGeometry *geometry)
13282 if (G_LIKELY (geometry != NULL))
13283 g_slice_free (ClutterGeometry, geometry);
13287 * clutter_geometry_union:
13288 * @geometry_a: a #ClutterGeometry
13289 * @geometry_b: another #ClutterGeometry
13290 * @result: (out): location to store the result
13292 * Find the union of two rectangles represented as #ClutterGeometry.
13297 clutter_geometry_union (const ClutterGeometry *geometry_a,
13298 const ClutterGeometry *geometry_b,
13299 ClutterGeometry *result)
13301 /* We don't try to handle rectangles that can't be represented
13302 * as a signed integer box */
13303 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13304 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13305 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13306 geometry_b->x + (gint)geometry_b->width);
13307 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13308 geometry_b->y + (gint)geometry_b->height);
13311 result->width = x_2 - x_1;
13312 result->height = y_2 - y_1;
13316 * clutter_geometry_intersects:
13317 * @geometry0: The first geometry to test
13318 * @geometry1: The second geometry to test
13320 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13321 * they do else %FALSE.
13323 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13329 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13330 const ClutterGeometry *geometry1)
13332 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13333 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13334 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13335 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13342 clutter_geometry_progress (const GValue *a,
13347 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13348 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13349 ClutterGeometry res = { 0, };
13350 gint a_width = a_geom->width;
13351 gint b_width = b_geom->width;
13352 gint a_height = a_geom->height;
13353 gint b_height = b_geom->height;
13355 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13356 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13358 res.width = a_width + (b_width - a_width) * progress;
13359 res.height = a_height + (b_height - a_height) * progress;
13361 g_value_set_boxed (retval, &res);
13366 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13367 clutter_geometry_copy,
13368 clutter_geometry_free,
13369 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13376 * clutter_vertex_new:
13381 * Creates a new #ClutterVertex for the point in 3D space
13382 * identified by the 3 coordinates @x, @y, @z
13384 * Return value: the newly allocate #ClutterVertex. Use
13385 * clutter_vertex_free() to free the resources
13390 clutter_vertex_new (gfloat x,
13394 ClutterVertex *vertex;
13396 vertex = g_slice_new (ClutterVertex);
13397 clutter_vertex_init (vertex, x, y, z);
13403 * clutter_vertex_init:
13404 * @vertex: a #ClutterVertex
13409 * Initializes @vertex with the given coordinates.
13414 clutter_vertex_init (ClutterVertex *vertex,
13419 g_return_if_fail (vertex != NULL);
13427 * clutter_vertex_copy:
13428 * @vertex: a #ClutterVertex
13432 * Return value: a newly allocated copy of #ClutterVertex. Use
13433 * clutter_vertex_free() to free the allocated resources
13438 clutter_vertex_copy (const ClutterVertex *vertex)
13440 if (G_LIKELY (vertex != NULL))
13441 return g_slice_dup (ClutterVertex, vertex);
13447 * clutter_vertex_free:
13448 * @vertex: a #ClutterVertex
13450 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13455 clutter_vertex_free (ClutterVertex *vertex)
13457 if (G_UNLIKELY (vertex != NULL))
13458 g_slice_free (ClutterVertex, vertex);
13462 * clutter_vertex_equal:
13463 * @vertex_a: a #ClutterVertex
13464 * @vertex_b: a #ClutterVertex
13466 * Compares @vertex_a and @vertex_b for equality
13468 * Return value: %TRUE if the passed #ClutterVertex are equal
13473 clutter_vertex_equal (const ClutterVertex *vertex_a,
13474 const ClutterVertex *vertex_b)
13476 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13478 if (vertex_a == vertex_b)
13481 return vertex_a->x == vertex_b->x &&
13482 vertex_a->y == vertex_b->y &&
13483 vertex_a->z == vertex_b->z;
13487 clutter_vertex_progress (const GValue *a,
13492 const ClutterVertex *av = g_value_get_boxed (a);
13493 const ClutterVertex *bv = g_value_get_boxed (b);
13494 ClutterVertex res = { 0, };
13496 res.x = av->x + (bv->x - av->x) * progress;
13497 res.y = av->y + (bv->y - av->y) * progress;
13498 res.z = av->z + (bv->z - av->z) * progress;
13500 g_value_set_boxed (retval, &res);
13505 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13506 clutter_vertex_copy,
13507 clutter_vertex_free,
13508 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13511 * clutter_actor_is_rotated:
13512 * @self: a #ClutterActor
13514 * Checks whether any rotation is applied to the actor.
13516 * Return value: %TRUE if the actor is rotated.
13521 clutter_actor_is_rotated (ClutterActor *self)
13523 const ClutterTransformInfo *info;
13525 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13527 info = _clutter_actor_get_transform_info_or_defaults (self);
13529 if (info->rx_angle || info->ry_angle || info->rz_angle)
13536 * clutter_actor_is_scaled:
13537 * @self: a #ClutterActor
13539 * Checks whether the actor is scaled in either dimension.
13541 * Return value: %TRUE if the actor is scaled.
13546 clutter_actor_is_scaled (ClutterActor *self)
13548 const ClutterTransformInfo *info;
13550 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13552 info = _clutter_actor_get_transform_info_or_defaults (self);
13554 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13561 _clutter_actor_get_stage_internal (ClutterActor *actor)
13563 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13564 actor = actor->priv->parent;
13570 * clutter_actor_get_stage:
13571 * @actor: a #ClutterActor
13573 * Retrieves the #ClutterStage where @actor is contained.
13575 * Return value: (transfer none) (type Clutter.Stage): the stage
13576 * containing the actor, or %NULL
13581 clutter_actor_get_stage (ClutterActor *actor)
13583 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13585 return _clutter_actor_get_stage_internal (actor);
13589 * clutter_actor_allocate_available_size:
13590 * @self: a #ClutterActor
13591 * @x: the actor's X coordinate
13592 * @y: the actor's Y coordinate
13593 * @available_width: the maximum available width, or -1 to use the
13594 * actor's natural width
13595 * @available_height: the maximum available height, or -1 to use the
13596 * actor's natural height
13597 * @flags: flags controlling the allocation
13599 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13600 * preferred size, but limiting it to the maximum available width
13601 * and height provided.
13603 * This function will do the right thing when dealing with the
13604 * actor's request mode.
13606 * The implementation of this function is equivalent to:
13609 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13611 * clutter_actor_get_preferred_width (self, available_height,
13613 * &natural_width);
13614 * width = CLAMP (natural_width, min_width, available_width);
13616 * clutter_actor_get_preferred_height (self, width,
13618 * &natural_height);
13619 * height = CLAMP (natural_height, min_height, available_height);
13623 * clutter_actor_get_preferred_height (self, available_width,
13625 * &natural_height);
13626 * height = CLAMP (natural_height, min_height, available_height);
13628 * clutter_actor_get_preferred_width (self, height,
13630 * &natural_width);
13631 * width = CLAMP (natural_width, min_width, available_width);
13634 * box.x1 = x; box.y1 = y;
13635 * box.x2 = box.x1 + available_width;
13636 * box.y2 = box.y1 + available_height;
13637 * clutter_actor_allocate (self, &box, flags);
13640 * This function can be used by fluid layout managers to allocate
13641 * an actor's preferred size without making it bigger than the area
13642 * available for the container.
13647 clutter_actor_allocate_available_size (ClutterActor *self,
13650 gfloat available_width,
13651 gfloat available_height,
13652 ClutterAllocationFlags flags)
13654 ClutterActorPrivate *priv;
13655 gfloat width, height;
13656 gfloat min_width, min_height;
13657 gfloat natural_width, natural_height;
13658 ClutterActorBox box;
13660 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13664 width = height = 0.0;
13666 switch (priv->request_mode)
13668 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13669 clutter_actor_get_preferred_width (self, available_height,
13672 width = CLAMP (natural_width, min_width, available_width);
13674 clutter_actor_get_preferred_height (self, width,
13677 height = CLAMP (natural_height, min_height, available_height);
13680 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13681 clutter_actor_get_preferred_height (self, available_width,
13684 height = CLAMP (natural_height, min_height, available_height);
13686 clutter_actor_get_preferred_width (self, height,
13689 width = CLAMP (natural_width, min_width, available_width);
13696 box.x2 = box.x1 + width;
13697 box.y2 = box.y1 + height;
13698 clutter_actor_allocate (self, &box, flags);
13702 * clutter_actor_allocate_preferred_size:
13703 * @self: a #ClutterActor
13704 * @flags: flags controlling the allocation
13706 * Allocates the natural size of @self.
13708 * This function is a utility call for #ClutterActor implementations
13709 * that allocates the actor's preferred natural size. It can be used
13710 * by fixed layout managers (like #ClutterGroup or so called
13711 * 'composite actors') inside the ClutterActor::allocate
13712 * implementation to give each child exactly how much space it
13715 * This function is not meant to be used by applications. It is also
13716 * not meant to be used outside the implementation of the
13717 * ClutterActor::allocate virtual function.
13722 clutter_actor_allocate_preferred_size (ClutterActor *self,
13723 ClutterAllocationFlags flags)
13725 gfloat actor_x, actor_y;
13726 gfloat natural_width, natural_height;
13727 ClutterActorBox actor_box;
13729 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13731 actor_x = clutter_actor_get_x (self);
13732 actor_y = clutter_actor_get_y (self);
13734 clutter_actor_get_preferred_size (self,
13739 actor_box.x1 = actor_x;
13740 actor_box.y1 = actor_y;
13741 actor_box.x2 = actor_box.x1 + natural_width;
13742 actor_box.y2 = actor_box.y1 + natural_height;
13744 clutter_actor_allocate (self, &actor_box, flags);
13748 * clutter_actor_allocate_align_fill:
13749 * @self: a #ClutterActor
13750 * @box: a #ClutterActorBox, containing the available width and height
13751 * @x_align: the horizontal alignment, between 0 and 1
13752 * @y_align: the vertical alignment, between 0 and 1
13753 * @x_fill: whether the actor should fill horizontally
13754 * @y_fill: whether the actor should fill vertically
13755 * @flags: allocation flags to be passed to clutter_actor_allocate()
13757 * Allocates @self by taking into consideration the available allocation
13758 * area; an alignment factor on either axis; and whether the actor should
13759 * fill the allocation on either axis.
13761 * The @box should contain the available allocation width and height;
13762 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13763 * allocation will be offset by their value.
13765 * This function takes into consideration the geometry request specified by
13766 * the #ClutterActor:request-mode property, and the text direction.
13768 * This function is useful for fluid layout managers, like #ClutterBinLayout
13769 * or #ClutterTableLayout
13774 clutter_actor_allocate_align_fill (ClutterActor *self,
13775 const ClutterActorBox *box,
13780 ClutterAllocationFlags flags)
13782 ClutterActorPrivate *priv;
13783 ClutterActorBox allocation = { 0, };
13784 gfloat x_offset, y_offset;
13785 gfloat available_width, available_height;
13786 gfloat child_width, child_height;
13788 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13789 g_return_if_fail (box != NULL);
13790 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13791 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13795 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13796 clutter_actor_box_get_size (box, &available_width, &available_height);
13798 if (available_width < 0)
13799 available_width = 0;
13801 if (available_height < 0)
13802 available_height = 0;
13806 allocation.x1 = x_offset;
13807 allocation.x2 = allocation.x1 + available_width;
13812 allocation.y1 = y_offset;
13813 allocation.y2 = allocation.y1 + available_height;
13816 /* if we are filling horizontally and vertically then we're done */
13817 if (x_fill && y_fill)
13820 child_width = child_height = 0.0f;
13822 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13824 gfloat min_width, natural_width;
13825 gfloat min_height, natural_height;
13827 clutter_actor_get_preferred_width (self, available_height,
13831 child_width = CLAMP (natural_width, min_width, available_width);
13835 clutter_actor_get_preferred_height (self, child_width,
13839 child_height = CLAMP (natural_height, min_height, available_height);
13844 gfloat min_width, natural_width;
13845 gfloat min_height, natural_height;
13847 clutter_actor_get_preferred_height (self, available_width,
13851 child_height = CLAMP (natural_height, min_height, available_height);
13855 clutter_actor_get_preferred_width (self, child_height,
13859 child_width = CLAMP (natural_width, min_width, available_width);
13863 /* invert the horizontal alignment for RTL languages */
13864 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13865 x_align = 1.0 - x_align;
13869 allocation.x1 = x_offset
13870 + ((available_width - child_width) * x_align);
13871 allocation.x2 = allocation.x1 + child_width;
13876 allocation.y1 = y_offset
13877 + ((available_height - child_height) * y_align);
13878 allocation.y2 = allocation.y1 + child_height;
13882 clutter_actor_box_clamp_to_pixel (&allocation);
13883 clutter_actor_allocate (self, &allocation, flags);
13887 * clutter_actor_grab_key_focus:
13888 * @self: a #ClutterActor
13890 * Sets the key focus of the #ClutterStage including @self
13891 * to this #ClutterActor.
13896 clutter_actor_grab_key_focus (ClutterActor *self)
13898 ClutterActor *stage;
13900 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13902 stage = _clutter_actor_get_stage_internal (self);
13904 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13908 * clutter_actor_get_pango_context:
13909 * @self: a #ClutterActor
13911 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13912 * is already configured using the appropriate font map, resolution
13913 * and font options.
13915 * Unlike clutter_actor_create_pango_context(), this context is owend
13916 * by the #ClutterActor and it will be updated each time the options
13917 * stored by the #ClutterBackend change.
13919 * You can use the returned #PangoContext to create a #PangoLayout
13920 * and render text using cogl_pango_render_layout() to reuse the
13921 * glyphs cache also used by Clutter.
13923 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13924 * The returned #PangoContext is owned by the actor and should not be
13925 * unreferenced by the application code
13930 clutter_actor_get_pango_context (ClutterActor *self)
13932 ClutterActorPrivate *priv;
13934 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13938 if (priv->pango_context != NULL)
13939 return priv->pango_context;
13941 priv->pango_context = _clutter_context_get_pango_context ();
13942 g_object_ref (priv->pango_context);
13944 return priv->pango_context;
13948 * clutter_actor_create_pango_context:
13949 * @self: a #ClutterActor
13951 * Creates a #PangoContext for the given actor. The #PangoContext
13952 * is already configured using the appropriate font map, resolution
13953 * and font options.
13955 * See also clutter_actor_get_pango_context().
13957 * Return value: (transfer full): the newly created #PangoContext.
13958 * Use g_object_unref() on the returned value to deallocate its
13964 clutter_actor_create_pango_context (ClutterActor *self)
13966 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13968 return _clutter_context_create_pango_context ();
13972 * clutter_actor_create_pango_layout:
13973 * @self: a #ClutterActor
13974 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13976 * Creates a new #PangoLayout from the same #PangoContext used
13977 * by the #ClutterActor. The #PangoLayout is already configured
13978 * with the font map, resolution and font options, and the
13981 * If you want to keep around a #PangoLayout created by this
13982 * function you will have to connect to the #ClutterBackend::font-changed
13983 * and #ClutterBackend::resolution-changed signals, and call
13984 * pango_layout_context_changed() in response to them.
13986 * Return value: (transfer full): the newly created #PangoLayout.
13987 * Use g_object_unref() when done
13992 clutter_actor_create_pango_layout (ClutterActor *self,
13995 PangoContext *context;
13996 PangoLayout *layout;
13998 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14000 context = clutter_actor_get_pango_context (self);
14001 layout = pango_layout_new (context);
14004 pango_layout_set_text (layout, text, -1);
14009 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14010 * ClutterOffscreenEffect.
14013 _clutter_actor_set_opacity_override (ClutterActor *self,
14016 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14018 self->priv->opacity_override = opacity;
14022 _clutter_actor_get_opacity_override (ClutterActor *self)
14024 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14026 return self->priv->opacity_override;
14029 /* Allows you to disable applying the actors model view transform during
14030 * a paint. Used by ClutterClone. */
14032 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14035 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14037 self->priv->enable_model_view_transform = enable;
14041 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14044 ClutterActorPrivate *priv;
14046 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14050 priv->enable_paint_unmapped = enable;
14052 if (priv->enable_paint_unmapped)
14054 /* Make sure that the parents of the widget are realized first;
14055 * otherwise checks in clutter_actor_update_map_state() will
14058 clutter_actor_realize (self);
14060 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14064 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14069 clutter_anchor_coord_get_units (ClutterActor *self,
14070 const AnchorCoord *coord,
14075 if (coord->is_fractional)
14077 gfloat actor_width, actor_height;
14079 clutter_actor_get_size (self, &actor_width, &actor_height);
14082 *x = actor_width * coord->v.fraction.x;
14085 *y = actor_height * coord->v.fraction.y;
14093 *x = coord->v.units.x;
14096 *y = coord->v.units.y;
14099 *z = coord->v.units.z;
14104 clutter_anchor_coord_set_units (AnchorCoord *coord,
14109 coord->is_fractional = FALSE;
14110 coord->v.units.x = x;
14111 coord->v.units.y = y;
14112 coord->v.units.z = z;
14115 static ClutterGravity
14116 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14118 if (coord->is_fractional)
14120 if (coord->v.fraction.x == 0.0)
14122 if (coord->v.fraction.y == 0.0)
14123 return CLUTTER_GRAVITY_NORTH_WEST;
14124 else if (coord->v.fraction.y == 0.5)
14125 return CLUTTER_GRAVITY_WEST;
14126 else if (coord->v.fraction.y == 1.0)
14127 return CLUTTER_GRAVITY_SOUTH_WEST;
14129 return CLUTTER_GRAVITY_NONE;
14131 else if (coord->v.fraction.x == 0.5)
14133 if (coord->v.fraction.y == 0.0)
14134 return CLUTTER_GRAVITY_NORTH;
14135 else if (coord->v.fraction.y == 0.5)
14136 return CLUTTER_GRAVITY_CENTER;
14137 else if (coord->v.fraction.y == 1.0)
14138 return CLUTTER_GRAVITY_SOUTH;
14140 return CLUTTER_GRAVITY_NONE;
14142 else if (coord->v.fraction.x == 1.0)
14144 if (coord->v.fraction.y == 0.0)
14145 return CLUTTER_GRAVITY_NORTH_EAST;
14146 else if (coord->v.fraction.y == 0.5)
14147 return CLUTTER_GRAVITY_EAST;
14148 else if (coord->v.fraction.y == 1.0)
14149 return CLUTTER_GRAVITY_SOUTH_EAST;
14151 return CLUTTER_GRAVITY_NONE;
14154 return CLUTTER_GRAVITY_NONE;
14157 return CLUTTER_GRAVITY_NONE;
14161 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14162 ClutterGravity gravity)
14166 case CLUTTER_GRAVITY_NORTH:
14167 coord->v.fraction.x = 0.5;
14168 coord->v.fraction.y = 0.0;
14171 case CLUTTER_GRAVITY_NORTH_EAST:
14172 coord->v.fraction.x = 1.0;
14173 coord->v.fraction.y = 0.0;
14176 case CLUTTER_GRAVITY_EAST:
14177 coord->v.fraction.x = 1.0;
14178 coord->v.fraction.y = 0.5;
14181 case CLUTTER_GRAVITY_SOUTH_EAST:
14182 coord->v.fraction.x = 1.0;
14183 coord->v.fraction.y = 1.0;
14186 case CLUTTER_GRAVITY_SOUTH:
14187 coord->v.fraction.x = 0.5;
14188 coord->v.fraction.y = 1.0;
14191 case CLUTTER_GRAVITY_SOUTH_WEST:
14192 coord->v.fraction.x = 0.0;
14193 coord->v.fraction.y = 1.0;
14196 case CLUTTER_GRAVITY_WEST:
14197 coord->v.fraction.x = 0.0;
14198 coord->v.fraction.y = 0.5;
14201 case CLUTTER_GRAVITY_NORTH_WEST:
14202 coord->v.fraction.x = 0.0;
14203 coord->v.fraction.y = 0.0;
14206 case CLUTTER_GRAVITY_CENTER:
14207 coord->v.fraction.x = 0.5;
14208 coord->v.fraction.y = 0.5;
14212 coord->v.fraction.x = 0.0;
14213 coord->v.fraction.y = 0.0;
14217 coord->is_fractional = TRUE;
14221 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14223 if (coord->is_fractional)
14224 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14226 return (coord->v.units.x == 0.0
14227 && coord->v.units.y == 0.0
14228 && coord->v.units.z == 0.0);
14232 * clutter_actor_get_flags:
14233 * @self: a #ClutterActor
14235 * Retrieves the flags set on @self
14237 * Return value: a bitwise or of #ClutterActorFlags or 0
14242 clutter_actor_get_flags (ClutterActor *self)
14244 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14246 return self->flags;
14250 * clutter_actor_set_flags:
14251 * @self: a #ClutterActor
14252 * @flags: the flags to set
14254 * Sets @flags on @self
14256 * This function will emit notifications for the changed properties
14261 clutter_actor_set_flags (ClutterActor *self,
14262 ClutterActorFlags flags)
14264 ClutterActorFlags old_flags;
14266 gboolean was_reactive_set, reactive_set;
14267 gboolean was_realized_set, realized_set;
14268 gboolean was_mapped_set, mapped_set;
14269 gboolean was_visible_set, visible_set;
14271 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14273 if (self->flags == flags)
14276 obj = G_OBJECT (self);
14277 g_object_ref (obj);
14278 g_object_freeze_notify (obj);
14280 old_flags = self->flags;
14282 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14283 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14284 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14285 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14287 self->flags |= flags;
14289 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14290 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14291 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14292 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14294 if (reactive_set != was_reactive_set)
14295 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14297 if (realized_set != was_realized_set)
14298 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14300 if (mapped_set != was_mapped_set)
14301 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14303 if (visible_set != was_visible_set)
14304 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14306 g_object_thaw_notify (obj);
14307 g_object_unref (obj);
14311 * clutter_actor_unset_flags:
14312 * @self: a #ClutterActor
14313 * @flags: the flags to unset
14315 * Unsets @flags on @self
14317 * This function will emit notifications for the changed properties
14322 clutter_actor_unset_flags (ClutterActor *self,
14323 ClutterActorFlags flags)
14325 ClutterActorFlags old_flags;
14327 gboolean was_reactive_set, reactive_set;
14328 gboolean was_realized_set, realized_set;
14329 gboolean was_mapped_set, mapped_set;
14330 gboolean was_visible_set, visible_set;
14332 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14334 obj = G_OBJECT (self);
14335 g_object_freeze_notify (obj);
14337 old_flags = self->flags;
14339 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14340 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14341 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14342 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14344 self->flags &= ~flags;
14346 if (self->flags == old_flags)
14349 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14350 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14351 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14352 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14354 if (reactive_set != was_reactive_set)
14355 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14357 if (realized_set != was_realized_set)
14358 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14360 if (mapped_set != was_mapped_set)
14361 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14363 if (visible_set != was_visible_set)
14364 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14366 g_object_thaw_notify (obj);
14370 * clutter_actor_get_transformation_matrix:
14371 * @self: a #ClutterActor
14372 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14374 * Retrieves the transformations applied to @self relative to its
14380 clutter_actor_get_transformation_matrix (ClutterActor *self,
14381 CoglMatrix *matrix)
14383 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14385 cogl_matrix_init_identity (matrix);
14387 _clutter_actor_apply_modelview_transform (self, matrix);
14391 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14392 gboolean is_in_clone_paint)
14394 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14395 self->priv->in_clone_paint = is_in_clone_paint;
14399 * clutter_actor_is_in_clone_paint:
14400 * @self: a #ClutterActor
14402 * Checks whether @self is being currently painted by a #ClutterClone
14404 * This function is useful only inside the ::paint virtual function
14405 * implementations or within handlers for the #ClutterActor::paint
14408 * This function should not be used by applications
14410 * Return value: %TRUE if the #ClutterActor is currently being painted
14411 * by a #ClutterClone, and %FALSE otherwise
14416 clutter_actor_is_in_clone_paint (ClutterActor *self)
14418 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14420 return self->priv->in_clone_paint;
14424 set_direction_recursive (ClutterActor *actor,
14425 gpointer user_data)
14427 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14429 clutter_actor_set_text_direction (actor, text_dir);
14435 * clutter_actor_set_text_direction:
14436 * @self: a #ClutterActor
14437 * @text_dir: the text direction for @self
14439 * Sets the #ClutterTextDirection for an actor
14441 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14443 * If @self implements #ClutterContainer then this function will recurse
14444 * inside all the children of @self (including the internal ones).
14446 * Composite actors not implementing #ClutterContainer, or actors requiring
14447 * special handling when the text direction changes, should connect to
14448 * the #GObject::notify signal for the #ClutterActor:text-direction property
14453 clutter_actor_set_text_direction (ClutterActor *self,
14454 ClutterTextDirection text_dir)
14456 ClutterActorPrivate *priv;
14458 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14459 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14463 if (priv->text_direction != text_dir)
14465 priv->text_direction = text_dir;
14467 /* we need to emit the notify::text-direction first, so that
14468 * the sub-classes can catch that and do specific handling of
14469 * the text direction; see clutter_text_direction_changed_cb()
14470 * inside clutter-text.c
14472 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14474 _clutter_actor_foreach_child (self, set_direction_recursive,
14475 GINT_TO_POINTER (text_dir));
14477 clutter_actor_queue_relayout (self);
14482 _clutter_actor_set_has_pointer (ClutterActor *self,
14483 gboolean has_pointer)
14485 ClutterActorPrivate *priv = self->priv;
14487 if (priv->has_pointer != has_pointer)
14489 priv->has_pointer = has_pointer;
14491 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14496 * clutter_actor_get_text_direction:
14497 * @self: a #ClutterActor
14499 * Retrieves the value set using clutter_actor_set_text_direction()
14501 * If no text direction has been previously set, the default text
14502 * direction, as returned by clutter_get_default_text_direction(), will
14503 * be returned instead
14505 * Return value: the #ClutterTextDirection for the actor
14509 ClutterTextDirection
14510 clutter_actor_get_text_direction (ClutterActor *self)
14512 ClutterActorPrivate *priv;
14514 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14515 CLUTTER_TEXT_DIRECTION_LTR);
14519 /* if no direction has been set yet use the default */
14520 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14521 priv->text_direction = clutter_get_default_text_direction ();
14523 return priv->text_direction;
14527 * clutter_actor_push_internal:
14528 * @self: a #ClutterActor
14530 * Should be used by actors implementing the #ClutterContainer and with
14531 * internal children added through clutter_actor_set_parent(), for instance:
14535 * my_actor_init (MyActor *self)
14537 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14539 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14541 * /* calling clutter_actor_set_parent() now will result in
14542 * * the internal flag being set on a child of MyActor
14545 * /* internal child - a background texture */
14546 * self->priv->background_tex = clutter_texture_new ();
14547 * clutter_actor_set_parent (self->priv->background_tex,
14548 * CLUTTER_ACTOR (self));
14550 * /* internal child - a label */
14551 * self->priv->label = clutter_text_new ();
14552 * clutter_actor_set_parent (self->priv->label,
14553 * CLUTTER_ACTOR (self));
14555 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14557 * /* calling clutter_actor_set_parent() now will not result in
14558 * * the internal flag being set on a child of MyActor
14563 * This function will be used by Clutter to toggle an "internal child"
14564 * flag whenever clutter_actor_set_parent() is called; internal children
14565 * are handled differently by Clutter, specifically when destroying their
14568 * Call clutter_actor_pop_internal() when you finished adding internal
14571 * Nested calls to clutter_actor_push_internal() are allowed, but each
14572 * one must by followed by a clutter_actor_pop_internal() call.
14576 * Deprecated: 1.10: All children of an actor are accessible through
14577 * the #ClutterActor API, and #ClutterActor implements the
14578 * #ClutterContainer interface, so this function is only useful
14579 * for legacy containers overriding the default implementation.
14582 clutter_actor_push_internal (ClutterActor *self)
14584 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14586 self->priv->internal_child += 1;
14590 * clutter_actor_pop_internal:
14591 * @self: a #ClutterActor
14593 * Disables the effects of clutter_actor_push_internal().
14597 * Deprecated: 1.10: All children of an actor are accessible through
14598 * the #ClutterActor API. This function is only useful for legacy
14599 * containers overriding the default implementation of the
14600 * #ClutterContainer interface.
14603 clutter_actor_pop_internal (ClutterActor *self)
14605 ClutterActorPrivate *priv;
14607 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14611 if (priv->internal_child == 0)
14613 g_warning ("Mismatched %s: you need to call "
14614 "clutter_actor_push_composite() at least once before "
14615 "calling this function", G_STRFUNC);
14619 priv->internal_child -= 1;
14623 * clutter_actor_has_pointer:
14624 * @self: a #ClutterActor
14626 * Checks whether an actor contains the pointer of a
14627 * #ClutterInputDevice
14629 * Return value: %TRUE if the actor contains the pointer, and
14635 clutter_actor_has_pointer (ClutterActor *self)
14637 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14639 return self->priv->has_pointer;
14642 /* XXX: This is a workaround for not being able to break the ABI of
14643 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14644 * clutter_actor_queue_clipped_redraw() for details.
14646 ClutterPaintVolume *
14647 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14649 return g_object_get_data (G_OBJECT (self),
14650 "-clutter-actor-queue-redraw-clip");
14654 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14655 ClutterPaintVolume *clip)
14657 g_object_set_data (G_OBJECT (self),
14658 "-clutter-actor-queue-redraw-clip",
14663 * clutter_actor_has_allocation:
14664 * @self: a #ClutterActor
14666 * Checks if the actor has an up-to-date allocation assigned to
14667 * it. This means that the actor should have an allocation: it's
14668 * visible and has a parent. It also means that there is no
14669 * outstanding relayout request in progress for the actor or its
14670 * children (There might be other outstanding layout requests in
14671 * progress that will cause the actor to get a new allocation
14672 * when the stage is laid out, however).
14674 * If this function returns %FALSE, then the actor will normally
14675 * be allocated before it is next drawn on the screen.
14677 * Return value: %TRUE if the actor has an up-to-date allocation
14682 clutter_actor_has_allocation (ClutterActor *self)
14684 ClutterActorPrivate *priv;
14686 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14690 return priv->parent != NULL &&
14691 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14692 !priv->needs_allocation;
14696 * clutter_actor_add_action:
14697 * @self: a #ClutterActor
14698 * @action: a #ClutterAction
14700 * Adds @action to the list of actions applied to @self
14702 * A #ClutterAction can only belong to one actor at a time
14704 * The #ClutterActor will hold a reference on @action until either
14705 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14711 clutter_actor_add_action (ClutterActor *self,
14712 ClutterAction *action)
14714 ClutterActorPrivate *priv;
14716 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14717 g_return_if_fail (CLUTTER_IS_ACTION (action));
14721 if (priv->actions == NULL)
14723 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14724 priv->actions->actor = self;
14727 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14729 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14733 * clutter_actor_add_action_with_name:
14734 * @self: a #ClutterActor
14735 * @name: the name to set on the action
14736 * @action: a #ClutterAction
14738 * A convenience function for setting the name of a #ClutterAction
14739 * while adding it to the list of actions applied to @self
14741 * This function is the logical equivalent of:
14744 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14745 * clutter_actor_add_action (self, action);
14751 clutter_actor_add_action_with_name (ClutterActor *self,
14753 ClutterAction *action)
14755 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14756 g_return_if_fail (name != NULL);
14757 g_return_if_fail (CLUTTER_IS_ACTION (action));
14759 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14760 clutter_actor_add_action (self, action);
14764 * clutter_actor_remove_action:
14765 * @self: a #ClutterActor
14766 * @action: a #ClutterAction
14768 * Removes @action from the list of actions applied to @self
14770 * The reference held by @self on the #ClutterAction will be released
14775 clutter_actor_remove_action (ClutterActor *self,
14776 ClutterAction *action)
14778 ClutterActorPrivate *priv;
14780 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14781 g_return_if_fail (CLUTTER_IS_ACTION (action));
14785 if (priv->actions == NULL)
14788 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14790 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14794 * clutter_actor_remove_action_by_name:
14795 * @self: a #ClutterActor
14796 * @name: the name of the action to remove
14798 * Removes the #ClutterAction with the given name from the list
14799 * of actions applied to @self
14804 clutter_actor_remove_action_by_name (ClutterActor *self,
14807 ClutterActorPrivate *priv;
14808 ClutterActorMeta *meta;
14810 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14811 g_return_if_fail (name != NULL);
14815 if (priv->actions == NULL)
14818 meta = _clutter_meta_group_get_meta (priv->actions, name);
14822 _clutter_meta_group_remove_meta (priv->actions, meta);
14824 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14828 * clutter_actor_get_actions:
14829 * @self: a #ClutterActor
14831 * Retrieves the list of actions applied to @self
14833 * Return value: (transfer container) (element-type Clutter.Action): a copy
14834 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14835 * owned by the #ClutterActor. Use g_list_free() to free the resources
14836 * allocated by the returned #GList
14841 clutter_actor_get_actions (ClutterActor *self)
14843 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14845 if (self->priv->actions == NULL)
14848 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14852 * clutter_actor_get_action:
14853 * @self: a #ClutterActor
14854 * @name: the name of the action to retrieve
14856 * Retrieves the #ClutterAction with the given name in the list
14857 * of actions applied to @self
14859 * Return value: (transfer none): a #ClutterAction for the given
14860 * name, or %NULL. The returned #ClutterAction is owned by the
14861 * actor and it should not be unreferenced directly
14866 clutter_actor_get_action (ClutterActor *self,
14869 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14870 g_return_val_if_fail (name != NULL, NULL);
14872 if (self->priv->actions == NULL)
14875 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14879 * clutter_actor_clear_actions:
14880 * @self: a #ClutterActor
14882 * Clears the list of actions applied to @self
14887 clutter_actor_clear_actions (ClutterActor *self)
14889 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14891 if (self->priv->actions == NULL)
14894 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14898 * clutter_actor_add_constraint:
14899 * @self: a #ClutterActor
14900 * @constraint: a #ClutterConstraint
14902 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14905 * The #ClutterActor will hold a reference on the @constraint until
14906 * either clutter_actor_remove_constraint() or
14907 * clutter_actor_clear_constraints() is called.
14912 clutter_actor_add_constraint (ClutterActor *self,
14913 ClutterConstraint *constraint)
14915 ClutterActorPrivate *priv;
14917 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14918 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14922 if (priv->constraints == NULL)
14924 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14925 priv->constraints->actor = self;
14928 _clutter_meta_group_add_meta (priv->constraints,
14929 CLUTTER_ACTOR_META (constraint));
14930 clutter_actor_queue_relayout (self);
14932 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14936 * clutter_actor_add_constraint_with_name:
14937 * @self: a #ClutterActor
14938 * @name: the name to set on the constraint
14939 * @constraint: a #ClutterConstraint
14941 * A convenience function for setting the name of a #ClutterConstraint
14942 * while adding it to the list of constraints applied to @self
14944 * This function is the logical equivalent of:
14947 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14948 * clutter_actor_add_constraint (self, constraint);
14954 clutter_actor_add_constraint_with_name (ClutterActor *self,
14956 ClutterConstraint *constraint)
14958 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14959 g_return_if_fail (name != NULL);
14960 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14962 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14963 clutter_actor_add_constraint (self, constraint);
14967 * clutter_actor_remove_constraint:
14968 * @self: a #ClutterActor
14969 * @constraint: a #ClutterConstraint
14971 * Removes @constraint from the list of constraints applied to @self
14973 * The reference held by @self on the #ClutterConstraint will be released
14978 clutter_actor_remove_constraint (ClutterActor *self,
14979 ClutterConstraint *constraint)
14981 ClutterActorPrivate *priv;
14983 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14984 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14988 if (priv->constraints == NULL)
14991 _clutter_meta_group_remove_meta (priv->constraints,
14992 CLUTTER_ACTOR_META (constraint));
14993 clutter_actor_queue_relayout (self);
14995 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14999 * clutter_actor_remove_constraint_by_name:
15000 * @self: a #ClutterActor
15001 * @name: the name of the constraint to remove
15003 * Removes the #ClutterConstraint with the given name from the list
15004 * of constraints applied to @self
15009 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15012 ClutterActorPrivate *priv;
15013 ClutterActorMeta *meta;
15015 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15016 g_return_if_fail (name != NULL);
15020 if (priv->constraints == NULL)
15023 meta = _clutter_meta_group_get_meta (priv->constraints, name);
15027 _clutter_meta_group_remove_meta (priv->constraints, meta);
15028 clutter_actor_queue_relayout (self);
15032 * clutter_actor_get_constraints:
15033 * @self: a #ClutterActor
15035 * Retrieves the list of constraints applied to @self
15037 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15038 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15039 * owned by the #ClutterActor. Use g_list_free() to free the resources
15040 * allocated by the returned #GList
15045 clutter_actor_get_constraints (ClutterActor *self)
15047 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15049 if (self->priv->constraints == NULL)
15052 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15056 * clutter_actor_get_constraint:
15057 * @self: a #ClutterActor
15058 * @name: the name of the constraint to retrieve
15060 * Retrieves the #ClutterConstraint with the given name in the list
15061 * of constraints applied to @self
15063 * Return value: (transfer none): a #ClutterConstraint for the given
15064 * name, or %NULL. The returned #ClutterConstraint is owned by the
15065 * actor and it should not be unreferenced directly
15069 ClutterConstraint *
15070 clutter_actor_get_constraint (ClutterActor *self,
15073 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15074 g_return_val_if_fail (name != NULL, NULL);
15076 if (self->priv->constraints == NULL)
15079 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15083 * clutter_actor_clear_constraints:
15084 * @self: a #ClutterActor
15086 * Clears the list of constraints applied to @self
15091 clutter_actor_clear_constraints (ClutterActor *self)
15093 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15095 if (self->priv->constraints == NULL)
15098 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15100 clutter_actor_queue_relayout (self);
15104 * clutter_actor_set_clip_to_allocation:
15105 * @self: a #ClutterActor
15106 * @clip_set: %TRUE to apply a clip tracking the allocation
15108 * Sets whether @self should be clipped to the same size as its
15114 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15117 ClutterActorPrivate *priv;
15119 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15121 clip_set = !!clip_set;
15125 if (priv->clip_to_allocation != clip_set)
15127 priv->clip_to_allocation = clip_set;
15129 clutter_actor_queue_redraw (self);
15131 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15136 * clutter_actor_get_clip_to_allocation:
15137 * @self: a #ClutterActor
15139 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15141 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15146 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15148 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15150 return self->priv->clip_to_allocation;
15154 * clutter_actor_add_effect:
15155 * @self: a #ClutterActor
15156 * @effect: a #ClutterEffect
15158 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15160 * The #ClutterActor will hold a reference on the @effect until either
15161 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15167 clutter_actor_add_effect (ClutterActor *self,
15168 ClutterEffect *effect)
15170 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15171 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15173 _clutter_actor_add_effect_internal (self, effect);
15175 clutter_actor_queue_redraw (self);
15177 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15181 * clutter_actor_add_effect_with_name:
15182 * @self: a #ClutterActor
15183 * @name: the name to set on the effect
15184 * @effect: a #ClutterEffect
15186 * A convenience function for setting the name of a #ClutterEffect
15187 * while adding it to the list of effectss applied to @self
15189 * This function is the logical equivalent of:
15192 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15193 * clutter_actor_add_effect (self, effect);
15199 clutter_actor_add_effect_with_name (ClutterActor *self,
15201 ClutterEffect *effect)
15203 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15204 g_return_if_fail (name != NULL);
15205 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15207 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15208 clutter_actor_add_effect (self, effect);
15212 * clutter_actor_remove_effect:
15213 * @self: a #ClutterActor
15214 * @effect: a #ClutterEffect
15216 * Removes @effect from the list of effects applied to @self
15218 * The reference held by @self on the #ClutterEffect will be released
15223 clutter_actor_remove_effect (ClutterActor *self,
15224 ClutterEffect *effect)
15226 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15227 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15229 _clutter_actor_remove_effect_internal (self, effect);
15231 clutter_actor_queue_redraw (self);
15233 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15237 * clutter_actor_remove_effect_by_name:
15238 * @self: a #ClutterActor
15239 * @name: the name of the effect to remove
15241 * Removes the #ClutterEffect with the given name from the list
15242 * of effects applied to @self
15247 clutter_actor_remove_effect_by_name (ClutterActor *self,
15250 ClutterActorPrivate *priv;
15251 ClutterActorMeta *meta;
15253 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15254 g_return_if_fail (name != NULL);
15258 if (priv->effects == NULL)
15261 meta = _clutter_meta_group_get_meta (priv->effects, name);
15265 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15269 * clutter_actor_get_effects:
15270 * @self: a #ClutterActor
15272 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15274 * Return value: (transfer container) (element-type Clutter.Effect): a list
15275 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15276 * list are owned by Clutter and they should not be freed. You should
15277 * free the returned list using g_list_free() when done
15282 clutter_actor_get_effects (ClutterActor *self)
15284 ClutterActorPrivate *priv;
15286 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15290 if (priv->effects == NULL)
15293 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15297 * clutter_actor_get_effect:
15298 * @self: a #ClutterActor
15299 * @name: the name of the effect to retrieve
15301 * Retrieves the #ClutterEffect with the given name in the list
15302 * of effects applied to @self
15304 * Return value: (transfer none): a #ClutterEffect for the given
15305 * name, or %NULL. The returned #ClutterEffect is owned by the
15306 * actor and it should not be unreferenced directly
15311 clutter_actor_get_effect (ClutterActor *self,
15314 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15315 g_return_val_if_fail (name != NULL, NULL);
15317 if (self->priv->effects == NULL)
15320 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15324 * clutter_actor_clear_effects:
15325 * @self: a #ClutterActor
15327 * Clears the list of effects applied to @self
15332 clutter_actor_clear_effects (ClutterActor *self)
15334 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15336 if (self->priv->effects == NULL)
15339 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15341 clutter_actor_queue_redraw (self);
15345 * clutter_actor_has_key_focus:
15346 * @self: a #ClutterActor
15348 * Checks whether @self is the #ClutterActor that has key focus
15350 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15355 clutter_actor_has_key_focus (ClutterActor *self)
15357 ClutterActor *stage;
15359 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15361 stage = _clutter_actor_get_stage_internal (self);
15365 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15369 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15370 ClutterPaintVolume *pv)
15372 ClutterActorPrivate *priv = self->priv;
15374 /* Actors are only expected to report a valid paint volume
15375 * while they have a valid allocation. */
15376 if (G_UNLIKELY (priv->needs_allocation))
15378 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15379 "Actor needs allocation",
15380 _clutter_actor_get_debug_name (self));
15384 /* Check if there are any handlers connected to the paint
15385 * signal. If there are then all bets are off for what the paint
15386 * volume for this actor might possibly be!
15388 * XXX: It's expected that this is going to end up being quite a
15389 * costly check to have to do here, but we haven't come up with
15390 * another solution that can reliably catch paint signal handlers at
15391 * the right time to either avoid artefacts due to invalid stage
15392 * clipping or due to incorrect culling.
15394 * Previously we checked in clutter_actor_paint(), but at that time
15395 * we may already be using a stage clip that could be derived from
15396 * an invalid paint-volume. We used to try and handle that by
15397 * queuing a follow up, unclipped, redraw but still the previous
15398 * checking wasn't enough to catch invalid volumes involved in
15399 * culling (considering that containers may derive their volume from
15400 * children that haven't yet been painted)
15402 * Longer term, improved solutions could be:
15403 * - Disallow painting in the paint signal, only allow using it
15404 * for tracking when paints happen. We can add another API that
15405 * allows monkey patching the paint of arbitrary actors but in a
15406 * more controlled way and that also supports modifying the
15408 * - If we could be notified somehow when signal handlers are
15409 * connected we wouldn't have to poll for handlers like this.
15411 if (g_signal_has_handler_pending (self,
15412 actor_signals[PAINT],
15416 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15417 "Actor has \"paint\" signal handlers",
15418 _clutter_actor_get_debug_name (self));
15422 _clutter_paint_volume_init_static (pv, self);
15424 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15426 clutter_paint_volume_free (pv);
15427 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15428 "Actor failed to report a volume",
15429 _clutter_actor_get_debug_name (self));
15433 /* since effects can modify the paint volume, we allow them to actually
15434 * do this by making get_paint_volume() "context sensitive"
15436 if (priv->effects != NULL)
15438 if (priv->current_effect != NULL)
15440 const GList *effects, *l;
15442 /* if we are being called from within the paint sequence of
15443 * an actor, get the paint volume up to the current effect
15445 effects = _clutter_meta_group_peek_metas (priv->effects);
15447 l != NULL || (l != NULL && l->data != priv->current_effect);
15450 if (!_clutter_effect_get_paint_volume (l->data, pv))
15452 clutter_paint_volume_free (pv);
15453 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15454 "Effect (%s) failed to report a volume",
15455 _clutter_actor_get_debug_name (self),
15456 _clutter_actor_meta_get_debug_name (l->data));
15463 const GList *effects, *l;
15465 /* otherwise, get the cumulative volume */
15466 effects = _clutter_meta_group_peek_metas (priv->effects);
15467 for (l = effects; l != NULL; l = l->next)
15468 if (!_clutter_effect_get_paint_volume (l->data, pv))
15470 clutter_paint_volume_free (pv);
15471 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15472 "Effect (%s) failed to report a volume",
15473 _clutter_actor_get_debug_name (self),
15474 _clutter_actor_meta_get_debug_name (l->data));
15483 /* The public clutter_actor_get_paint_volume API returns a const
15484 * pointer since we return a pointer directly to the cached
15485 * PaintVolume associated with the actor and don't want the user to
15486 * inadvertently modify it, but for internal uses we sometimes need
15487 * access to the same PaintVolume but need to apply some book-keeping
15488 * modifications to it so we don't want a const pointer.
15490 static ClutterPaintVolume *
15491 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15493 ClutterActorPrivate *priv;
15497 if (priv->paint_volume_valid)
15498 clutter_paint_volume_free (&priv->paint_volume);
15500 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15502 priv->paint_volume_valid = TRUE;
15503 return &priv->paint_volume;
15507 priv->paint_volume_valid = FALSE;
15513 * clutter_actor_get_paint_volume:
15514 * @self: a #ClutterActor
15516 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15517 * when a paint volume can't be determined.
15519 * The paint volume is defined as the 3D space occupied by an actor
15520 * when being painted.
15522 * This function will call the <function>get_paint_volume()</function>
15523 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15524 * should not usually care about overriding the default implementation,
15525 * unless they are, for instance: painting outside their allocation, or
15526 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15529 * <note>2D actors overriding <function>get_paint_volume()</function>
15530 * ensure their volume has a depth of 0. (This will be true so long as
15531 * you don't call clutter_paint_volume_set_depth().)</note>
15533 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15534 * or %NULL if no volume could be determined. The returned pointer
15535 * is not guaranteed to be valid across multiple frames; if you want
15536 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15540 const ClutterPaintVolume *
15541 clutter_actor_get_paint_volume (ClutterActor *self)
15543 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15545 return _clutter_actor_get_paint_volume_mutable (self);
15549 * clutter_actor_get_transformed_paint_volume:
15550 * @self: a #ClutterActor
15551 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15552 * (or %NULL for the stage)
15554 * Retrieves the 3D paint volume of an actor like
15555 * clutter_actor_get_paint_volume() does (Please refer to the
15556 * documentation of clutter_actor_get_paint_volume() for more
15557 * details.) and it additionally transforms the paint volume into the
15558 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15559 * is passed for @relative_to_ancestor)
15561 * This can be used by containers that base their paint volume on
15562 * the volume of their children. Such containers can query the
15563 * transformed paint volume of all of its children and union them
15564 * together using clutter_paint_volume_union().
15566 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15567 * or %NULL if no volume could be determined. The returned pointer is
15568 * not guaranteed to be valid across multiple frames; if you wish to
15569 * keep it, you will have to copy it using clutter_paint_volume_copy().
15573 const ClutterPaintVolume *
15574 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15575 ClutterActor *relative_to_ancestor)
15577 const ClutterPaintVolume *volume;
15578 ClutterActor *stage;
15579 ClutterPaintVolume *transformed_volume;
15581 stage = _clutter_actor_get_stage_internal (self);
15582 if (G_UNLIKELY (stage == NULL))
15585 if (relative_to_ancestor == NULL)
15586 relative_to_ancestor = stage;
15588 volume = clutter_actor_get_paint_volume (self);
15589 if (volume == NULL)
15592 transformed_volume =
15593 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15595 _clutter_paint_volume_copy_static (volume, transformed_volume);
15597 _clutter_paint_volume_transform_relative (transformed_volume,
15598 relative_to_ancestor);
15600 return transformed_volume;
15604 * clutter_actor_get_paint_box:
15605 * @self: a #ClutterActor
15606 * @box: (out): return location for a #ClutterActorBox
15608 * Retrieves the paint volume of the passed #ClutterActor, and
15609 * transforms it into a 2D bounding box in stage coordinates.
15611 * This function is useful to determine the on screen area occupied by
15612 * the actor. The box is only an approximation and may often be
15613 * considerably larger due to the optimizations used to calculate the
15614 * box. The box is never smaller though, so it can reliably be used
15617 * There are times when a 2D paint box can't be determined, e.g.
15618 * because the actor isn't yet parented under a stage or because
15619 * the actor is unable to determine a paint volume.
15621 * Return value: %TRUE if a 2D paint box could be determined, else
15627 clutter_actor_get_paint_box (ClutterActor *self,
15628 ClutterActorBox *box)
15630 ClutterActor *stage;
15631 ClutterPaintVolume *pv;
15633 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15634 g_return_val_if_fail (box != NULL, FALSE);
15636 stage = _clutter_actor_get_stage_internal (self);
15637 if (G_UNLIKELY (!stage))
15640 pv = _clutter_actor_get_paint_volume_mutable (self);
15641 if (G_UNLIKELY (!pv))
15644 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15650 * clutter_actor_has_overlaps:
15651 * @self: A #ClutterActor
15653 * Asks the actor's implementation whether it may contain overlapping
15656 * For example; Clutter may use this to determine whether the painting
15657 * should be redirected to an offscreen buffer to correctly implement
15658 * the opacity property.
15660 * Custom actors can override the default response by implementing the
15661 * #ClutterActor <function>has_overlaps</function> virtual function. See
15662 * clutter_actor_set_offscreen_redirect() for more information.
15664 * Return value: %TRUE if the actor may have overlapping primitives, and
15670 clutter_actor_has_overlaps (ClutterActor *self)
15672 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15674 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15678 * clutter_actor_has_effects:
15679 * @self: A #ClutterActor
15681 * Returns whether the actor has any effects applied.
15683 * Return value: %TRUE if the actor has any effects,
15689 clutter_actor_has_effects (ClutterActor *self)
15691 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15693 if (self->priv->effects == NULL)
15696 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15700 * clutter_actor_has_constraints:
15701 * @self: A #ClutterActor
15703 * Returns whether the actor has any constraints applied.
15705 * Return value: %TRUE if the actor has any constraints,
15711 clutter_actor_has_constraints (ClutterActor *self)
15713 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15715 return self->priv->constraints != NULL;
15719 * clutter_actor_has_actions:
15720 * @self: A #ClutterActor
15722 * Returns whether the actor has any actions applied.
15724 * Return value: %TRUE if the actor has any actions,
15730 clutter_actor_has_actions (ClutterActor *self)
15732 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15734 return self->priv->actions != NULL;
15738 * clutter_actor_get_n_children:
15739 * @self: a #ClutterActor
15741 * Retrieves the number of children of @self.
15743 * Return value: the number of children of an actor
15748 clutter_actor_get_n_children (ClutterActor *self)
15750 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15752 return self->priv->n_children;
15756 * clutter_actor_get_child_at_index:
15757 * @self: a #ClutterActor
15758 * @index_: the position in the list of children
15760 * Retrieves the actor at the given @index_ inside the list of
15761 * children of @self.
15763 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15768 clutter_actor_get_child_at_index (ClutterActor *self,
15771 ClutterActor *iter;
15774 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15775 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15777 for (iter = self->priv->first_child, i = 0;
15778 iter != NULL && i < index_;
15779 iter = iter->priv->next_sibling, i += 1)
15786 * _clutter_actor_foreach_child:
15787 * @actor: The actor whos children you want to iterate
15788 * @callback: The function to call for each child
15789 * @user_data: Private data to pass to @callback
15791 * Calls a given @callback once for each child of the specified @actor and
15792 * passing the @user_data pointer each time.
15794 * Return value: returns %TRUE if all children were iterated, else
15795 * %FALSE if a callback broke out of iteration early.
15798 _clutter_actor_foreach_child (ClutterActor *self,
15799 ClutterForeachCallback callback,
15800 gpointer user_data)
15802 ClutterActor *iter;
15805 if (self->priv->first_child == NULL)
15809 iter = self->priv->first_child;
15811 /* we use this form so that it's safe to change the children
15812 * list while iterating it
15814 while (cont && iter != NULL)
15816 ClutterActor *next = iter->priv->next_sibling;
15818 cont = callback (iter, user_data);
15827 /* For debugging purposes this gives us a simple way to print out
15828 * the scenegraph e.g in gdb using:
15830 * _clutter_actor_traverse (stage,
15832 * clutter_debug_print_actor_cb,
15837 static ClutterActorTraverseVisitFlags
15838 clutter_debug_print_actor_cb (ClutterActor *actor,
15842 g_print ("%*s%s:%p\n",
15844 _clutter_actor_get_debug_name (actor),
15847 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15852 _clutter_actor_traverse_breadth (ClutterActor *actor,
15853 ClutterTraverseCallback callback,
15854 gpointer user_data)
15856 GQueue *queue = g_queue_new ();
15857 ClutterActor dummy;
15858 int current_depth = 0;
15860 g_queue_push_tail (queue, actor);
15861 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15863 while ((actor = g_queue_pop_head (queue)))
15865 ClutterActorTraverseVisitFlags flags;
15867 if (actor == &dummy)
15870 g_queue_push_tail (queue, &dummy);
15874 flags = callback (actor, current_depth, user_data);
15875 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15877 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15879 ClutterActor *iter;
15881 for (iter = actor->priv->first_child;
15883 iter = iter->priv->next_sibling)
15885 g_queue_push_tail (queue, iter);
15890 g_queue_free (queue);
15893 static ClutterActorTraverseVisitFlags
15894 _clutter_actor_traverse_depth (ClutterActor *actor,
15895 ClutterTraverseCallback before_children_callback,
15896 ClutterTraverseCallback after_children_callback,
15898 gpointer user_data)
15900 ClutterActorTraverseVisitFlags flags;
15902 flags = before_children_callback (actor, current_depth, user_data);
15903 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15904 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15906 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15908 ClutterActor *iter;
15910 for (iter = actor->priv->first_child;
15912 iter = iter->priv->next_sibling)
15914 flags = _clutter_actor_traverse_depth (iter,
15915 before_children_callback,
15916 after_children_callback,
15920 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15921 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15925 if (after_children_callback)
15926 return after_children_callback (actor, current_depth, user_data);
15928 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15931 /* _clutter_actor_traverse:
15932 * @actor: The actor to start traversing the graph from
15933 * @flags: These flags may affect how the traversal is done
15934 * @before_children_callback: A function to call before visiting the
15935 * children of the current actor.
15936 * @after_children_callback: A function to call after visiting the
15937 * children of the current actor. (Ignored if
15938 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15939 * @user_data: The private data to pass to the callbacks
15941 * Traverses the scenegraph starting at the specified @actor and
15942 * descending through all its children and its children's children.
15943 * For each actor traversed @before_children_callback and
15944 * @after_children_callback are called with the specified
15945 * @user_data, before and after visiting that actor's children.
15947 * The callbacks can return flags that affect the ongoing traversal
15948 * such as by skipping over an actors children or bailing out of
15949 * any further traversing.
15952 _clutter_actor_traverse (ClutterActor *actor,
15953 ClutterActorTraverseFlags flags,
15954 ClutterTraverseCallback before_children_callback,
15955 ClutterTraverseCallback after_children_callback,
15956 gpointer user_data)
15958 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15959 _clutter_actor_traverse_breadth (actor,
15960 before_children_callback,
15962 else /* DEPTH_FIRST */
15963 _clutter_actor_traverse_depth (actor,
15964 before_children_callback,
15965 after_children_callback,
15966 0, /* start depth */
15971 on_layout_manager_changed (ClutterLayoutManager *manager,
15972 ClutterActor *self)
15974 clutter_actor_queue_relayout (self);
15978 * clutter_actor_set_layout_manager:
15979 * @self: a #ClutterActor
15980 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15982 * Sets the #ClutterLayoutManager delegate object that will be used to
15983 * lay out the children of @self.
15985 * The #ClutterActor will take a reference on the passed @manager which
15986 * will be released either when the layout manager is removed, or when
15987 * the actor is destroyed.
15992 clutter_actor_set_layout_manager (ClutterActor *self,
15993 ClutterLayoutManager *manager)
15995 ClutterActorPrivate *priv;
15997 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15998 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16002 if (priv->layout_manager != NULL)
16004 g_signal_handlers_disconnect_by_func (priv->layout_manager,
16005 G_CALLBACK (on_layout_manager_changed),
16007 clutter_layout_manager_set_container (priv->layout_manager, NULL);
16008 g_clear_object (&priv->layout_manager);
16011 priv->layout_manager = manager;
16013 if (priv->layout_manager != NULL)
16015 g_object_ref_sink (priv->layout_manager);
16016 clutter_layout_manager_set_container (priv->layout_manager,
16017 CLUTTER_CONTAINER (self));
16018 g_signal_connect (priv->layout_manager, "layout-changed",
16019 G_CALLBACK (on_layout_manager_changed),
16023 clutter_actor_queue_relayout (self);
16025 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16029 * clutter_actor_get_layout_manager:
16030 * @self: a #ClutterActor
16032 * Retrieves the #ClutterLayoutManager used by @self.
16034 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16039 ClutterLayoutManager *
16040 clutter_actor_get_layout_manager (ClutterActor *self)
16042 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16044 return self->priv->layout_manager;
16047 static const ClutterLayoutInfo default_layout_info = {
16050 { 0, 0, 0, 0 }, /* margin */
16051 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
16052 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
16053 0.f, 0.f, /* min_width, natural_width */
16054 0.f, 0.f, /* natual_width, natural_height */
16058 layout_info_free (gpointer data)
16060 if (G_LIKELY (data != NULL))
16061 g_slice_free (ClutterLayoutInfo, data);
16065 * _clutter_actor_get_layout_info:
16066 * @self: a #ClutterActor
16068 * Retrieves a pointer to the ClutterLayoutInfo structure.
16070 * If the actor does not have a ClutterLayoutInfo associated to it, one
16071 * will be created and initialized to the default values.
16073 * This function should be used for setters.
16075 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16078 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16080 ClutterLayoutInfo *
16081 _clutter_actor_get_layout_info (ClutterActor *self)
16083 ClutterLayoutInfo *retval;
16085 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16086 if (retval == NULL)
16088 retval = g_slice_new (ClutterLayoutInfo);
16090 *retval = default_layout_info;
16092 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16101 * _clutter_actor_get_layout_info_or_defaults:
16102 * @self: a #ClutterActor
16104 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16106 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16107 * then the default structure will be returned.
16109 * This function should only be used for getters.
16111 * Return value: a const pointer to the ClutterLayoutInfo structure
16113 const ClutterLayoutInfo *
16114 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16116 const ClutterLayoutInfo *info;
16118 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16120 return &default_layout_info;
16126 * clutter_actor_set_x_align:
16127 * @self: a #ClutterActor
16128 * @x_align: the horizontal alignment policy
16130 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16131 * actor received extra horizontal space.
16133 * See also the #ClutterActor:x-align property.
16138 clutter_actor_set_x_align (ClutterActor *self,
16139 ClutterActorAlign x_align)
16141 ClutterLayoutInfo *info;
16143 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16145 info = _clutter_actor_get_layout_info (self);
16147 if (info->x_align != x_align)
16149 info->x_align = x_align;
16151 clutter_actor_queue_relayout (self);
16153 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16158 * clutter_actor_get_x_align:
16159 * @self: a #ClutterActor
16161 * Retrieves the horizontal alignment policy set using
16162 * clutter_actor_set_x_align().
16164 * Return value: the horizontal alignment policy.
16169 clutter_actor_get_x_align (ClutterActor *self)
16171 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16173 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16177 * clutter_actor_set_y_align:
16178 * @self: a #ClutterActor
16179 * @y_align: the vertical alignment policy
16181 * Sets the vertical alignment policy of a #ClutterActor, in case the
16182 * actor received extra vertical space.
16184 * See also the #ClutterActor:y-align property.
16189 clutter_actor_set_y_align (ClutterActor *self,
16190 ClutterActorAlign y_align)
16192 ClutterLayoutInfo *info;
16194 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16196 info = _clutter_actor_get_layout_info (self);
16198 if (info->y_align != y_align)
16200 info->y_align = y_align;
16202 clutter_actor_queue_relayout (self);
16204 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16209 * clutter_actor_get_y_align:
16210 * @self: a #ClutterActor
16212 * Retrieves the vertical alignment policy set using
16213 * clutter_actor_set_y_align().
16215 * Return value: the vertical alignment policy.
16220 clutter_actor_get_y_align (ClutterActor *self)
16222 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16224 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16229 * clutter_margin_new:
16231 * Creates a new #ClutterMargin.
16233 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16234 * clutter_margin_free() to free the resources associated with it when
16240 clutter_margin_new (void)
16242 return g_slice_new0 (ClutterMargin);
16246 * clutter_margin_copy:
16247 * @margin_: a #ClutterMargin
16249 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16250 * the newly created structure.
16252 * Return value: (transfer full): a copy of the #ClutterMargin.
16257 clutter_margin_copy (const ClutterMargin *margin_)
16259 if (G_LIKELY (margin_ != NULL))
16260 return g_slice_dup (ClutterMargin, margin_);
16266 * clutter_margin_free:
16267 * @margin_: a #ClutterMargin
16269 * Frees the resources allocated by clutter_margin_new() and
16270 * clutter_margin_copy().
16275 clutter_margin_free (ClutterMargin *margin_)
16277 if (G_LIKELY (margin_ != NULL))
16278 g_slice_free (ClutterMargin, margin_);
16281 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16282 clutter_margin_copy,
16283 clutter_margin_free)
16286 * clutter_actor_set_margin:
16287 * @self: a #ClutterActor
16288 * @margin: a #ClutterMargin
16290 * Sets all the components of the margin of a #ClutterActor.
16295 clutter_actor_set_margin (ClutterActor *self,
16296 const ClutterMargin *margin)
16298 ClutterLayoutInfo *info;
16302 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16303 g_return_if_fail (margin != NULL);
16305 obj = G_OBJECT (self);
16308 g_object_freeze_notify (obj);
16310 info = _clutter_actor_get_layout_info (self);
16312 if (info->margin.top != margin->top)
16314 info->margin.top = margin->top;
16315 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16319 if (info->margin.right != margin->right)
16321 info->margin.right = margin->right;
16322 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16326 if (info->margin.bottom != margin->bottom)
16328 info->margin.bottom = margin->bottom;
16329 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16333 if (info->margin.left != margin->left)
16335 info->margin.left = margin->left;
16336 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16341 clutter_actor_queue_relayout (self);
16343 g_object_thaw_notify (obj);
16347 * clutter_actor_get_margin:
16348 * @self: a #ClutterActor
16349 * @margin: (out caller-allocates): return location for a #ClutterMargin
16351 * Retrieves all the components of the margin of a #ClutterActor.
16356 clutter_actor_get_margin (ClutterActor *self,
16357 ClutterMargin *margin)
16359 const ClutterLayoutInfo *info;
16361 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16362 g_return_if_fail (margin != NULL);
16364 info = _clutter_actor_get_layout_info_or_defaults (self);
16366 *margin = info->margin;
16370 * clutter_actor_set_margin_top:
16371 * @self: a #ClutterActor
16372 * @margin: the top margin
16374 * Sets the margin from the top of a #ClutterActor.
16379 clutter_actor_set_margin_top (ClutterActor *self,
16382 ClutterLayoutInfo *info;
16384 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16385 g_return_if_fail (margin >= 0.f);
16387 info = _clutter_actor_get_layout_info (self);
16389 if (info->margin.top == margin)
16392 info->margin.top = margin;
16394 clutter_actor_queue_relayout (self);
16396 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16400 * clutter_actor_get_margin_top:
16401 * @self: a #ClutterActor
16403 * Retrieves the top margin of a #ClutterActor.
16405 * Return value: the top margin
16410 clutter_actor_get_margin_top (ClutterActor *self)
16412 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16414 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16418 * clutter_actor_set_margin_bottom:
16419 * @self: a #ClutterActor
16420 * @margin: the bottom margin
16422 * Sets the margin from the bottom of a #ClutterActor.
16427 clutter_actor_set_margin_bottom (ClutterActor *self,
16430 ClutterLayoutInfo *info;
16432 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16433 g_return_if_fail (margin >= 0.f);
16435 info = _clutter_actor_get_layout_info (self);
16437 if (info->margin.bottom == margin)
16440 info->margin.bottom = margin;
16442 clutter_actor_queue_relayout (self);
16444 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16448 * clutter_actor_get_margin_bottom:
16449 * @self: a #ClutterActor
16451 * Retrieves the bottom margin of a #ClutterActor.
16453 * Return value: the bottom margin
16458 clutter_actor_get_margin_bottom (ClutterActor *self)
16460 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16462 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16466 * clutter_actor_set_margin_left:
16467 * @self: a #ClutterActor
16468 * @margin: the left margin
16470 * Sets the margin from the left of a #ClutterActor.
16475 clutter_actor_set_margin_left (ClutterActor *self,
16478 ClutterLayoutInfo *info;
16480 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16481 g_return_if_fail (margin >= 0.f);
16483 info = _clutter_actor_get_layout_info (self);
16485 if (info->margin.left == margin)
16488 info->margin.left = margin;
16490 clutter_actor_queue_relayout (self);
16492 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16496 * clutter_actor_get_margin_left:
16497 * @self: a #ClutterActor
16499 * Retrieves the left margin of a #ClutterActor.
16501 * Return value: the left margin
16506 clutter_actor_get_margin_left (ClutterActor *self)
16508 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16510 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16514 * clutter_actor_set_margin_right:
16515 * @self: a #ClutterActor
16516 * @margin: the right margin
16518 * Sets the margin from the right of a #ClutterActor.
16523 clutter_actor_set_margin_right (ClutterActor *self,
16526 ClutterLayoutInfo *info;
16528 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16529 g_return_if_fail (margin >= 0.f);
16531 info = _clutter_actor_get_layout_info (self);
16533 if (info->margin.right == margin)
16536 info->margin.right = margin;
16538 clutter_actor_queue_relayout (self);
16540 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16544 * clutter_actor_get_margin_right:
16545 * @self: a #ClutterActor
16547 * Retrieves the right margin of a #ClutterActor.
16549 * Return value: the right margin
16554 clutter_actor_get_margin_right (ClutterActor *self)
16556 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16558 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16562 clutter_actor_set_background_color_internal (ClutterActor *self,
16563 const ClutterColor *color)
16565 ClutterActorPrivate *priv = self->priv;
16568 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16571 obj = G_OBJECT (self);
16573 priv->bg_color = *color;
16574 priv->bg_color_set = TRUE;
16576 clutter_actor_queue_redraw (self);
16578 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16579 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16583 * clutter_actor_set_background_color:
16584 * @self: a #ClutterActor
16585 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16588 * Sets the background color of a #ClutterActor.
16590 * The background color will be used to cover the whole allocation of the
16591 * actor. The default background color of an actor is transparent.
16593 * To check whether an actor has a background color, you can use the
16594 * #ClutterActor:background-color-set actor property.
16596 * The #ClutterActor:background-color property is animatable.
16601 clutter_actor_set_background_color (ClutterActor *self,
16602 const ClutterColor *color)
16604 ClutterActorPrivate *priv;
16606 GParamSpec *bg_color_pspec;
16608 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16610 obj = G_OBJECT (self);
16616 priv->bg_color_set = FALSE;
16617 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16618 clutter_actor_queue_redraw (self);
16622 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16623 if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16625 _clutter_actor_create_transition (self, bg_color_pspec,
16630 _clutter_actor_update_transition (self, bg_color_pspec, color);
16632 clutter_actor_queue_redraw (self);
16636 * clutter_actor_get_background_color:
16637 * @self: a #ClutterActor
16638 * @color: (out caller-allocates): return location for a #ClutterColor
16640 * Retrieves the color set using clutter_actor_set_background_color().
16645 clutter_actor_get_background_color (ClutterActor *self,
16646 ClutterColor *color)
16648 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16649 g_return_if_fail (color != NULL);
16651 *color = self->priv->bg_color;
16655 * clutter_actor_get_previous_sibling:
16656 * @self: a #ClutterActor
16658 * Retrieves the sibling of @self that comes before it in the list
16659 * of children of @self's parent.
16661 * The returned pointer is only valid until the scene graph changes; it
16662 * is not safe to modify the list of children of @self while iterating
16665 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16670 clutter_actor_get_previous_sibling (ClutterActor *self)
16672 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16674 return self->priv->prev_sibling;
16678 * clutter_actor_get_next_sibling:
16679 * @self: a #ClutterActor
16681 * Retrieves the sibling of @self that comes after it in the list
16682 * of children of @self's parent.
16684 * The returned pointer is only valid until the scene graph changes; it
16685 * is not safe to modify the list of children of @self while iterating
16688 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16693 clutter_actor_get_next_sibling (ClutterActor *self)
16695 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16697 return self->priv->next_sibling;
16701 * clutter_actor_get_first_child:
16702 * @self: a #ClutterActor
16704 * Retrieves the first child of @self.
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_first_child (ClutterActor *self)
16717 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16719 return self->priv->first_child;
16723 * clutter_actor_get_last_child:
16724 * @self: a #ClutterActor
16726 * Retrieves the last 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_last_child (ClutterActor *self)
16739 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16741 return self->priv->last_child;
16744 /* easy way to have properly named fields instead of the dummy ones
16745 * we use in the public structure
16747 typedef struct _RealActorIter
16749 ClutterActor *root; /* dummy1 */
16750 ClutterActor *current; /* dummy2 */
16751 gpointer padding_1; /* dummy3 */
16752 gint age; /* dummy4 */
16753 gpointer padding_2; /* dummy5 */
16757 * clutter_actor_iter_init:
16758 * @iter: a #ClutterActorIter
16759 * @root: a #ClutterActor
16761 * Initializes a #ClutterActorIter, which can then be used to iterate
16762 * efficiently over a section of the scene graph, and associates it
16765 * Modifying the scene graph section that contains @root will invalidate
16769 * ClutterActorIter iter;
16770 * ClutterActor *child;
16772 * clutter_actor_iter_init (&iter, container);
16773 * while (clutter_actor_iter_next (&iter, &child))
16775 * /* do something with child */
16782 clutter_actor_iter_init (ClutterActorIter *iter,
16783 ClutterActor *root)
16785 RealActorIter *ri = (RealActorIter *) iter;
16787 g_return_if_fail (iter != NULL);
16788 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16791 ri->current = NULL;
16792 ri->age = root->priv->age;
16796 * clutter_actor_iter_next:
16797 * @iter: a #ClutterActorIter
16798 * @child: (out): return location for a #ClutterActor
16800 * Advances the @iter and retrieves the next child of the root #ClutterActor
16801 * that was used to initialize the #ClutterActorIterator.
16803 * If the iterator can advance, this function returns %TRUE and sets the
16806 * If the iterator cannot advance, this function returns %FALSE, and
16807 * the contents of @child are undefined.
16809 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16814 clutter_actor_iter_next (ClutterActorIter *iter,
16815 ClutterActor **child)
16817 RealActorIter *ri = (RealActorIter *) iter;
16819 g_return_val_if_fail (iter != NULL, FALSE);
16820 g_return_val_if_fail (ri->root != NULL, FALSE);
16821 #ifndef G_DISABLE_ASSERT
16822 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16825 if (ri->current == NULL)
16826 ri->current = ri->root->priv->first_child;
16828 ri->current = ri->current->priv->next_sibling;
16831 *child = ri->current;
16833 return ri->current != NULL;
16837 * clutter_actor_iter_prev:
16838 * @iter: a #ClutterActorIter
16839 * @child: (out): return location for a #ClutterActor
16841 * Advances the @iter and retrieves the previous child of the root
16842 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16844 * If the iterator can advance, this function returns %TRUE and sets the
16847 * If the iterator cannot advance, this function returns %FALSE, and
16848 * the contents of @child are undefined.
16850 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16855 clutter_actor_iter_prev (ClutterActorIter *iter,
16856 ClutterActor **child)
16858 RealActorIter *ri = (RealActorIter *) iter;
16860 g_return_val_if_fail (iter != NULL, FALSE);
16861 g_return_val_if_fail (ri->root != NULL, FALSE);
16862 #ifndef G_DISABLE_ASSERT
16863 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16866 if (ri->current == NULL)
16867 ri->current = ri->root->priv->last_child;
16869 ri->current = ri->current->priv->prev_sibling;
16872 *child = ri->current;
16874 return ri->current != NULL;
16878 * clutter_actor_iter_remove:
16879 * @iter: a #ClutterActorIter
16881 * Safely removes the #ClutterActor currently pointer to by the iterator
16884 * This function can only be called after clutter_actor_iter_next() or
16885 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16886 * than once for the same actor.
16888 * This function will call clutter_actor_remove_child() internally.
16893 clutter_actor_iter_remove (ClutterActorIter *iter)
16895 RealActorIter *ri = (RealActorIter *) iter;
16898 g_return_if_fail (iter != NULL);
16899 g_return_if_fail (ri->root != NULL);
16900 #ifndef G_DISABLE_ASSERT
16901 g_return_if_fail (ri->age == ri->root->priv->age);
16903 g_return_if_fail (ri->current != NULL);
16909 ri->current = cur->priv->prev_sibling;
16911 clutter_actor_remove_child_internal (ri->root, cur,
16912 REMOVE_CHILD_DEFAULT_FLAGS);
16919 * clutter_actor_iter_destroy:
16920 * @iter: a #ClutterActorIter
16922 * Safely destroys the #ClutterActor currently pointer to by the iterator
16925 * This function can only be called after clutter_actor_iter_next() or
16926 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16927 * than once for the same actor.
16929 * This function will call clutter_actor_destroy() internally.
16934 clutter_actor_iter_destroy (ClutterActorIter *iter)
16936 RealActorIter *ri = (RealActorIter *) iter;
16939 g_return_if_fail (iter != NULL);
16940 g_return_if_fail (ri->root != NULL);
16941 #ifndef G_DISABLE_ASSERT
16942 g_return_if_fail (ri->age == ri->root->priv->age);
16944 g_return_if_fail (ri->current != NULL);
16950 ri->current = cur->priv->prev_sibling;
16952 clutter_actor_destroy (cur);
16958 static const ClutterAnimationInfo default_animation_info = {
16959 NULL, /* transitions */
16961 NULL, /* cur_state */
16965 clutter_animation_info_free (gpointer data)
16969 ClutterAnimationInfo *info = data;
16971 if (info->transitions != NULL)
16972 g_hash_table_unref (info->transitions);
16974 if (info->states != NULL)
16975 g_array_unref (info->states);
16977 g_slice_free (ClutterAnimationInfo, info);
16981 const ClutterAnimationInfo *
16982 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16984 const ClutterAnimationInfo *res;
16985 GObject *obj = G_OBJECT (self);
16987 res = g_object_get_qdata (obj, quark_actor_animation_info);
16991 return &default_animation_info;
16994 ClutterAnimationInfo *
16995 _clutter_actor_get_animation_info (ClutterActor *self)
16997 GObject *obj = G_OBJECT (self);
16998 ClutterAnimationInfo *res;
17000 res = g_object_get_qdata (obj, quark_actor_animation_info);
17003 res = g_slice_new (ClutterAnimationInfo);
17005 *res = default_animation_info;
17007 g_object_set_qdata_full (obj, quark_actor_animation_info,
17009 clutter_animation_info_free);
17015 ClutterTransition *
17016 _clutter_actor_get_transition (ClutterActor *actor,
17019 const ClutterAnimationInfo *info;
17021 info = _clutter_actor_get_animation_info_or_defaults (actor);
17023 if (info->transitions == NULL)
17026 return g_hash_table_lookup (info->transitions, pspec->name);
17029 typedef struct _TransitionClosure
17031 ClutterActor *actor;
17032 ClutterTransition *transition;
17034 gulong completed_id;
17035 } TransitionClosure;
17038 transition_closure_free (gpointer data)
17040 if (G_LIKELY (data != NULL))
17042 TransitionClosure *clos = data;
17043 ClutterTimeline *timeline;
17045 timeline = CLUTTER_TIMELINE (clos->transition);
17047 if (clutter_timeline_is_playing (timeline))
17048 clutter_timeline_stop (timeline);
17050 g_signal_handler_disconnect (clos->transition, clos->completed_id);
17052 g_object_unref (clos->transition);
17053 g_free (clos->name);
17055 g_slice_free (TransitionClosure, clos);
17060 on_transition_completed (ClutterTransition *transition,
17061 TransitionClosure *clos)
17063 ClutterActor *actor = clos->actor;
17064 ClutterAnimationInfo *info;
17066 /* reset the caches used by animations */
17067 clutter_actor_store_content_box (actor, NULL);
17069 info = _clutter_actor_get_animation_info (actor);
17071 /* this will take care of cleaning clos for us */
17072 if (!clutter_transition_get_remove_on_complete (transition))
17074 /* we take a reference here because removing the closure
17075 * will release the reference on the transition, and we
17076 * want the transition to survive the signal emission;
17077 * the master clock will release the laste reference at
17078 * the end of the frame processing.
17080 g_object_ref (transition);
17081 g_hash_table_remove (info->transitions, clos->name);
17085 ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17086 gint n_repeats, cur_repeat;
17088 /* ensure that we remove the transition only at the end
17089 * of its run; we emit ::completed for every repeat
17092 n_repeats = clutter_timeline_get_repeat_count (timeline);
17093 cur_repeat = clutter_timeline_get_current_repeat (timeline);
17095 if (cur_repeat == n_repeats)
17097 /* see the comment above on why this ref() is necessary */
17098 g_object_ref (transition);
17099 g_hash_table_remove (info->transitions, clos->name);
17103 /* if it's the last transition then we clean up */
17104 if (g_hash_table_size (info->transitions) == 0)
17106 g_hash_table_unref (info->transitions);
17107 info->transitions = NULL;
17109 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17110 _clutter_actor_get_debug_name (actor));
17112 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17117 _clutter_actor_update_transition (ClutterActor *actor,
17121 TransitionClosure *clos;
17122 ClutterTimeline *timeline;
17123 ClutterInterval *interval;
17124 const ClutterAnimationInfo *info;
17127 GValue initial = G_VALUE_INIT;
17128 GValue final = G_VALUE_INIT;
17129 char *error = NULL;
17131 info = _clutter_actor_get_animation_info_or_defaults (actor);
17133 if (info->transitions == NULL)
17136 clos = g_hash_table_lookup (info->transitions, pspec->name);
17140 timeline = CLUTTER_TIMELINE (clos->transition);
17142 va_start (var_args, pspec);
17144 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17146 g_value_init (&initial, ptype);
17147 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17151 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17154 g_critical ("%s: %s", G_STRLOC, error);
17159 interval = clutter_transition_get_interval (clos->transition);
17160 clutter_interval_set_initial_value (interval, &initial);
17161 clutter_interval_set_final_value (interval, &final);
17163 /* if we're updating with an easing duration of zero milliseconds,
17164 * we just jump the timeline to the end and let it run its course
17166 if (info->cur_state != NULL &&
17167 info->cur_state->easing_duration != 0)
17169 guint cur_duration = clutter_timeline_get_duration (timeline);
17170 ClutterAnimationMode cur_mode =
17171 clutter_timeline_get_progress_mode (timeline);
17173 if (cur_duration != info->cur_state->easing_duration)
17174 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17176 if (cur_mode != info->cur_state->easing_mode)
17177 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17179 clutter_timeline_rewind (timeline);
17183 guint duration = clutter_timeline_get_duration (timeline);
17185 clutter_timeline_advance (timeline, duration);
17189 g_value_unset (&initial);
17190 g_value_unset (&final);
17196 * _clutter_actor_create_transition:
17197 * @actor: a #ClutterActor
17198 * @pspec: the property used for the transition
17199 * @...: initial and final state
17201 * Creates a #ClutterTransition for the property represented by @pspec.
17203 * Return value: a #ClutterTransition
17205 ClutterTransition *
17206 _clutter_actor_create_transition (ClutterActor *actor,
17210 ClutterAnimationInfo *info;
17211 ClutterTransition *res = NULL;
17212 gboolean call_restore = FALSE;
17213 TransitionClosure *clos;
17216 info = _clutter_actor_get_animation_info (actor);
17218 /* XXX - this will go away in 2.0
17220 * if no state has been pushed, we assume that the easing state is
17221 * in "compatibility mode": all transitions have a duration of 0
17222 * msecs, which means that they happen immediately. in Clutter 2.0
17223 * this will turn into a g_assert(info->states != NULL), as every
17224 * actor will start with a predefined easing state
17226 if (info->states == NULL)
17228 clutter_actor_save_easing_state (actor);
17229 clutter_actor_set_easing_duration (actor, 0);
17230 call_restore = TRUE;
17233 if (info->transitions == NULL)
17234 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17236 transition_closure_free);
17238 va_start (var_args, pspec);
17240 clos = g_hash_table_lookup (info->transitions, pspec->name);
17243 ClutterInterval *interval;
17244 GValue initial = G_VALUE_INIT;
17245 GValue final = G_VALUE_INIT;
17249 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17251 G_VALUE_COLLECT_INIT (&initial, ptype,
17256 g_critical ("%s: %s", G_STRLOC, error);
17261 G_VALUE_COLLECT_INIT (&final, ptype,
17267 g_critical ("%s: %s", G_STRLOC, error);
17268 g_value_unset (&initial);
17273 /* if the current easing state has a duration of 0, then we don't
17274 * bother to create the transition, and we just set the final value
17275 * directly on the actor; we don't go through the Animatable
17276 * interface because we know we got here through an animatable
17279 if (info->cur_state->easing_duration == 0)
17281 clutter_actor_set_animatable_property (actor,
17285 g_value_unset (&initial);
17286 g_value_unset (&final);
17291 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17293 g_value_unset (&initial);
17294 g_value_unset (&final);
17296 res = clutter_property_transition_new (pspec->name);
17298 clutter_transition_set_interval (res, interval);
17299 clutter_transition_set_remove_on_complete (res, TRUE);
17301 /* this will start the transition as well */
17302 clutter_actor_add_transition (actor, pspec->name, res);
17304 /* the actor now owns the transition */
17305 g_object_unref (res);
17308 res = clos->transition;
17312 clutter_actor_restore_easing_state (actor);
17320 * clutter_actor_add_transition:
17321 * @self: a #ClutterActor
17322 * @name: the name of the transition to add
17323 * @transition: the #ClutterTransition to add
17325 * Adds a @transition to the #ClutterActor's list of animations.
17327 * The @name string is a per-actor unique identifier of the @transition: only
17328 * one #ClutterTransition can be associated to the specified @name.
17330 * The @transition will be given the easing duration, mode, and delay
17331 * associated to the actor's current easing state; it is possible to modify
17332 * these values after calling clutter_actor_add_transition().
17334 * The @transition will be started once added.
17336 * This function will take a reference on the @transition.
17338 * This function is usually called implicitly when modifying an animatable
17344 clutter_actor_add_transition (ClutterActor *self,
17346 ClutterTransition *transition)
17348 ClutterTimeline *timeline;
17349 TransitionClosure *clos;
17350 ClutterAnimationInfo *info;
17352 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17353 g_return_if_fail (name != NULL);
17354 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17356 info = _clutter_actor_get_animation_info (self);
17358 if (info->cur_state == NULL)
17360 g_warning ("No easing state is defined for the actor '%s'; you "
17361 "must call clutter_actor_save_easing_state() before "
17362 "calling clutter_actor_add_transition().",
17363 _clutter_actor_get_debug_name (self));
17367 if (info->transitions == NULL)
17368 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17370 transition_closure_free);
17372 if (g_hash_table_lookup (info->transitions, name) != NULL)
17374 g_warning ("A transition with name '%s' already exists for "
17377 _clutter_actor_get_debug_name (self));
17381 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17383 timeline = CLUTTER_TIMELINE (transition);
17385 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17386 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17387 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17389 clos = g_slice_new (TransitionClosure);
17390 clos->actor = self;
17391 clos->transition = g_object_ref (transition);
17392 clos->name = g_strdup (name);
17393 clos->completed_id = g_signal_connect (timeline, "completed",
17394 G_CALLBACK (on_transition_completed),
17397 CLUTTER_NOTE (ANIMATION,
17398 "Adding transition '%s' [%p] to actor '%s'",
17401 _clutter_actor_get_debug_name (self));
17403 g_hash_table_insert (info->transitions, clos->name, clos);
17404 clutter_timeline_start (timeline);
17408 * clutter_actor_remove_transition:
17409 * @self: a #ClutterActor
17410 * @name: the name of the transition to remove
17412 * Removes the transition stored inside a #ClutterActor using @name
17415 * If the transition is currently in progress, it will be stopped.
17417 * This function releases the reference acquired when the transition
17418 * was added to the #ClutterActor.
17423 clutter_actor_remove_transition (ClutterActor *self,
17426 const ClutterAnimationInfo *info;
17428 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17429 g_return_if_fail (name != NULL);
17431 info = _clutter_actor_get_animation_info_or_defaults (self);
17433 if (info->transitions == NULL)
17436 g_hash_table_remove (info->transitions, name);
17440 * clutter_actor_remove_all_transitions:
17441 * @self: a #ClutterActor
17443 * Removes all transitions associated to @self.
17448 clutter_actor_remove_all_transitions (ClutterActor *self)
17450 const ClutterAnimationInfo *info;
17452 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17454 info = _clutter_actor_get_animation_info_or_defaults (self);
17455 if (info->transitions == NULL)
17458 g_hash_table_remove_all (info->transitions);
17462 * clutter_actor_set_easing_duration:
17463 * @self: a #ClutterActor
17464 * @msecs: the duration of the easing, or %NULL
17466 * Sets the duration of the tweening for animatable properties
17467 * of @self for the current easing state.
17472 clutter_actor_set_easing_duration (ClutterActor *self,
17475 ClutterAnimationInfo *info;
17477 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17479 info = _clutter_actor_get_animation_info (self);
17481 if (info->cur_state == NULL)
17483 g_warning ("You must call clutter_actor_save_easing_state() prior "
17484 "to calling clutter_actor_set_easing_duration().");
17488 if (info->cur_state->easing_duration != msecs)
17489 info->cur_state->easing_duration = msecs;
17493 * clutter_actor_get_easing_duration:
17494 * @self: a #ClutterActor
17496 * Retrieves the duration of the tweening for animatable
17497 * properties of @self for the current easing state.
17499 * Return value: the duration of the tweening, in milliseconds
17504 clutter_actor_get_easing_duration (ClutterActor *self)
17506 const ClutterAnimationInfo *info;
17508 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17510 info = _clutter_actor_get_animation_info_or_defaults (self);
17512 if (info->cur_state != NULL)
17513 return info->cur_state->easing_duration;
17519 * clutter_actor_set_easing_mode:
17520 * @self: a #ClutterActor
17521 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17523 * Sets the easing mode for the tweening of animatable properties
17529 clutter_actor_set_easing_mode (ClutterActor *self,
17530 ClutterAnimationMode mode)
17532 ClutterAnimationInfo *info;
17534 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17535 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17536 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17538 info = _clutter_actor_get_animation_info (self);
17540 if (info->cur_state == NULL)
17542 g_warning ("You must call clutter_actor_save_easing_state() prior "
17543 "to calling clutter_actor_set_easing_mode().");
17547 if (info->cur_state->easing_mode != mode)
17548 info->cur_state->easing_mode = mode;
17552 * clutter_actor_get_easing_mode:
17553 * @self: a #ClutterActor
17555 * Retrieves the easing mode for the tweening of animatable properties
17556 * of @self for the current easing state.
17558 * Return value: an easing mode
17562 ClutterAnimationMode
17563 clutter_actor_get_easing_mode (ClutterActor *self)
17565 const ClutterAnimationInfo *info;
17567 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17569 info = _clutter_actor_get_animation_info_or_defaults (self);
17571 if (info->cur_state != NULL)
17572 return info->cur_state->easing_mode;
17574 return CLUTTER_EASE_OUT_CUBIC;
17578 * clutter_actor_set_easing_delay:
17579 * @self: a #ClutterActor
17580 * @msecs: the delay before the start of the tweening, in milliseconds
17582 * Sets the delay that should be applied before tweening animatable
17588 clutter_actor_set_easing_delay (ClutterActor *self,
17591 ClutterAnimationInfo *info;
17593 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17595 info = _clutter_actor_get_animation_info (self);
17597 if (info->cur_state == NULL)
17599 g_warning ("You must call clutter_actor_save_easing_state() prior "
17600 "to calling clutter_actor_set_easing_delay().");
17604 if (info->cur_state->easing_delay != msecs)
17605 info->cur_state->easing_delay = msecs;
17609 * clutter_actor_get_easing_delay:
17610 * @self: a #ClutterActor
17612 * Retrieves the delay that should be applied when tweening animatable
17615 * Return value: a delay, in milliseconds
17620 clutter_actor_get_easing_delay (ClutterActor *self)
17622 const ClutterAnimationInfo *info;
17624 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17626 info = _clutter_actor_get_animation_info_or_defaults (self);
17628 if (info->cur_state != NULL)
17629 return info->cur_state->easing_delay;
17635 * clutter_actor_get_transition:
17636 * @self: a #ClutterActor
17637 * @name: the name of the transition
17639 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17640 * transition @name.
17642 * Transitions created for animatable properties use the name of the
17643 * property itself, for instance the code below:
17646 * clutter_actor_set_easing_duration (actor, 1000);
17647 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17649 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17650 * g_signal_connect (transition, "completed",
17651 * G_CALLBACK (on_transition_complete),
17655 * will call the <function>on_transition_complete</function> callback when
17656 * the transition is complete.
17658 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17659 * was found to match the passed name; the returned instance is owned
17660 * by Clutter and it should not be freed
17664 ClutterTransition *
17665 clutter_actor_get_transition (ClutterActor *self,
17668 TransitionClosure *clos;
17669 const ClutterAnimationInfo *info;
17671 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17672 g_return_val_if_fail (name != NULL, NULL);
17674 info = _clutter_actor_get_animation_info_or_defaults (self);
17675 if (info->transitions == NULL)
17678 clos = g_hash_table_lookup (info->transitions, name);
17682 return clos->transition;
17686 * clutter_actor_save_easing_state:
17687 * @self: a #ClutterActor
17689 * Saves the current easing state for animatable properties, and creates
17690 * a new state with the default values for easing mode and duration.
17695 clutter_actor_save_easing_state (ClutterActor *self)
17697 ClutterAnimationInfo *info;
17700 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17702 info = _clutter_actor_get_animation_info (self);
17704 if (info->states == NULL)
17705 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17707 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17708 new_state.easing_duration = 250;
17709 new_state.easing_delay = 0;
17711 g_array_append_val (info->states, new_state);
17713 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17717 * clutter_actor_restore_easing_state:
17718 * @self: a #ClutterActor
17720 * Restores the easing state as it was prior to a call to
17721 * clutter_actor_save_easing_state().
17726 clutter_actor_restore_easing_state (ClutterActor *self)
17728 ClutterAnimationInfo *info;
17730 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17732 info = _clutter_actor_get_animation_info (self);
17734 if (info->states == NULL)
17736 g_critical ("The function clutter_actor_restore_easing_state() has "
17737 "called without a previous call to "
17738 "clutter_actor_save_easing_state().");
17742 g_array_remove_index (info->states, info->states->len - 1);
17744 if (info->states->len > 0)
17745 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17748 g_array_unref (info->states);
17749 info->states = NULL;
17750 info->cur_state = NULL;
17755 * clutter_actor_set_content:
17756 * @self: a #ClutterActor
17757 * @content: (allow-none): a #ClutterContent, or %NULL
17759 * Sets the contents of a #ClutterActor.
17764 clutter_actor_set_content (ClutterActor *self,
17765 ClutterContent *content)
17767 ClutterActorPrivate *priv;
17769 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17770 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17774 if (priv->content != NULL)
17776 _clutter_content_detached (priv->content, self);
17777 g_clear_object (&priv->content);
17780 priv->content = content;
17782 if (priv->content != NULL)
17784 g_object_ref (priv->content);
17785 _clutter_content_attached (priv->content, self);
17788 /* given that the content is always painted within the allocation,
17789 * we only need to queue a redraw here
17791 clutter_actor_queue_redraw (self);
17793 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17795 /* if the content gravity is not resize-fill, and the new content has a
17796 * different preferred size than the previous one, then the content box
17797 * may have been changed. since we compute that lazily, we just notify
17798 * here, and let whomever watches :content-box do whatever they need to
17801 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17802 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17806 * clutter_actor_get_content:
17807 * @self: a #ClutterActor
17809 * Retrieves the contents of @self.
17811 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17812 * or %NULL if none was set
17817 clutter_actor_get_content (ClutterActor *self)
17819 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17821 return self->priv->content;
17825 * clutter_actor_set_content_gravity:
17826 * @self: a #ClutterActor
17827 * @gravity: the #ClutterContentGravity
17829 * Sets the gravity of the #ClutterContent used by @self.
17831 * See the description of the #ClutterActor:content-gravity property for
17832 * more information.
17834 * The #ClutterActor:content-gravity property is animatable.
17839 clutter_actor_set_content_gravity (ClutterActor *self,
17840 ClutterContentGravity gravity)
17842 ClutterActorPrivate *priv;
17844 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17848 if (priv->content_gravity == gravity)
17851 priv->content_box_valid = FALSE;
17853 if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17855 ClutterActorBox from_box, to_box;
17857 clutter_actor_get_content_box (self, &from_box);
17859 priv->content_gravity = gravity;
17861 clutter_actor_get_content_box (self, &to_box);
17863 _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17869 ClutterActorBox to_box;
17871 priv->content_gravity = gravity;
17873 clutter_actor_get_content_box (self, &to_box);
17875 _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17879 clutter_actor_queue_redraw (self);
17881 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17885 * clutter_actor_get_content_gravity:
17886 * @self: a #ClutterActor
17888 * Retrieves the content gravity as set using
17889 * clutter_actor_get_content_gravity().
17891 * Return value: the content gravity
17895 ClutterContentGravity
17896 clutter_actor_get_content_gravity (ClutterActor *self)
17898 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17899 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17901 return self->priv->content_gravity;
17905 * clutter_actor_get_content_box:
17906 * @self: a #ClutterActor
17907 * @box: (out caller-allocates): the return location for the bounding
17908 * box for the #ClutterContent
17910 * Retrieves the bounding box for the #ClutterContent of @self.
17912 * The bounding box is relative to the actor's allocation.
17914 * If no #ClutterContent is set for @self, or if @self has not been
17915 * allocated yet, then the result is undefined.
17917 * The content box is guaranteed to be, at most, as big as the allocation
17918 * of the #ClutterActor.
17920 * If the #ClutterContent used by the actor has a preferred size, then
17921 * it is possible to modify the content box by using the
17922 * #ClutterActor:content-gravity property.
17927 clutter_actor_get_content_box (ClutterActor *self,
17928 ClutterActorBox *box)
17930 ClutterActorPrivate *priv;
17931 gfloat content_w, content_h;
17932 gfloat alloc_w, alloc_h;
17934 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17935 g_return_if_fail (box != NULL);
17941 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17942 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17944 if (priv->content_box_valid)
17946 *box = priv->content_box;
17950 /* no need to do any more work */
17951 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17954 if (priv->content == NULL)
17957 /* if the content does not have a preferred size then there is
17958 * no point in computing the content box
17960 if (!clutter_content_get_preferred_size (priv->content,
17968 switch (priv->content_gravity)
17970 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17971 box->x2 = box->x1 + MIN (content_w, alloc_w);
17972 box->y2 = box->y1 + MIN (content_h, alloc_h);
17975 case CLUTTER_CONTENT_GRAVITY_TOP:
17976 if (alloc_w > content_w)
17978 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17979 box->x2 = box->x1 + content_w;
17981 box->y2 = box->y1 + MIN (content_h, alloc_h);
17984 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17985 if (alloc_w > content_w)
17987 box->x1 += (alloc_w - content_w);
17988 box->x2 = box->x1 + content_w;
17990 box->y2 = box->y1 + MIN (content_h, alloc_h);
17993 case CLUTTER_CONTENT_GRAVITY_LEFT:
17994 box->x2 = box->x1 + MIN (content_w, alloc_w);
17995 if (alloc_h > content_h)
17997 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17998 box->y2 = box->y1 + content_h;
18002 case CLUTTER_CONTENT_GRAVITY_CENTER:
18003 if (alloc_w > content_w)
18005 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18006 box->x2 = box->x1 + content_w;
18008 if (alloc_h > content_h)
18010 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18011 box->y2 = box->y1 + content_h;
18015 case CLUTTER_CONTENT_GRAVITY_RIGHT:
18016 if (alloc_w > content_w)
18018 box->x1 += (alloc_w - content_w);
18019 box->x2 = box->x1 + content_w;
18021 if (alloc_h > content_h)
18023 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18024 box->y2 = box->y1 + content_h;
18028 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18029 box->x2 = box->x1 + MIN (content_w, alloc_w);
18030 if (alloc_h > content_h)
18032 box->y1 += (alloc_h - content_h);
18033 box->y2 = box->y1 + content_h;
18037 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18038 if (alloc_w > content_w)
18040 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18041 box->x2 = box->x1 + content_w;
18043 if (alloc_h > content_h)
18045 box->y1 += (alloc_h - content_h);
18046 box->y2 = box->y1 + content_h;
18050 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18051 if (alloc_w > content_w)
18053 box->x1 += (alloc_w - content_w);
18054 box->x2 = box->x1 + content_w;
18056 if (alloc_h > content_h)
18058 box->y1 += (alloc_h - content_h);
18059 box->y2 = box->y1 + content_h;
18063 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18064 g_assert_not_reached ();
18067 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18069 double r_c = content_w / content_h;
18070 double r_a = alloc_w / alloc_h;
18079 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18080 box->y2 = box->y1 + (alloc_w * r_c);
18087 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18088 box->x2 = box->x1 + (alloc_h * r_c);
18098 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18099 box->x2 = box->x1 + (alloc_h * r_c);
18106 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18107 box->y2 = box->y1 + (alloc_w * r_c);
18116 * clutter_actor_set_content_scaling_filters:
18117 * @self: a #ClutterActor
18118 * @min_filter: the minification filter for the content
18119 * @mag_filter: the magnification filter for the content
18121 * Sets the minification and magnification filter to be applied when
18122 * scaling the #ClutterActor:content of a #ClutterActor.
18124 * The #ClutterActor:minification-filter will be used when reducing
18125 * the size of the content; the #ClutterActor:magnification-filter
18126 * will be used when increasing the size of the content.
18131 clutter_actor_set_content_scaling_filters (ClutterActor *self,
18132 ClutterScalingFilter min_filter,
18133 ClutterScalingFilter mag_filter)
18135 ClutterActorPrivate *priv;
18139 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18142 obj = G_OBJECT (self);
18144 g_object_freeze_notify (obj);
18148 if (priv->min_filter != min_filter)
18150 priv->min_filter = min_filter;
18153 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18156 if (priv->mag_filter != mag_filter)
18158 priv->mag_filter = mag_filter;
18161 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18165 clutter_actor_queue_redraw (self);
18167 g_object_thaw_notify (obj);
18171 * clutter_actor_get_content_scaling_filters:
18172 * @self: a #ClutterActor
18173 * @min_filter: (out) (allow-none): return location for the minification
18175 * @mag_filter: (out) (allow-none): return location for the magnification
18178 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18183 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18184 ClutterScalingFilter *min_filter,
18185 ClutterScalingFilter *mag_filter)
18187 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18189 if (min_filter != NULL)
18190 *min_filter = self->priv->min_filter;
18192 if (mag_filter != NULL)
18193 *mag_filter = self->priv->mag_filter;