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: Base abstract class for all visual stage actors.
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);
171 * /* paint the content of the node using the allocation */
172 * clutter_paint_node_add_rectangle (node, &box);
174 * /* add the node, and transfer ownership */
175 * clutter_paint_node_add_child (root, node);
176 * clutter_paint_node_unref (node);
178 * </programlisting></informalexample>
181 * <title>Overriding the paint virtual function</title>
182 * <para>The #ClutterActorClass.paint() virtual function is invoked
183 * when the #ClutterActor::paint signal is emitted, and after the other
184 * signal handlers have been invoked. Overriding the paint virtual
185 * function gives total control to the paint sequence of the actor
186 * itself, including the children of the actor, if any.</para>
187 * <warning><para>It is strongly discouraged to override the
188 * #ClutterActorClass.paint() virtual function, as well as connecting
189 * to the #ClutterActor::paint signal. These hooks into the paint
190 * sequence are considered legacy, and will be removed when the Clutter
191 * API changes.</para></warning>
195 * <refsect2 id="ClutterActor-events">
196 * <title>Handling events on an actor</title>
197 * <para>A #ClutterActor can receive and handle input device events, for
198 * instance pointer events and key events, as long as its
199 * #ClutterActor:reactive property is set to %TRUE.</para>
200 * <para>Once an actor has been determined to be the source of an event,
201 * Clutter will traverse the scene graph from the top-level actor towards the
202 * event source, emitting the #ClutterActor::captured-event signal on each
203 * ancestor until it reaches the source; this phase is also called
204 * <emphasis>the capture phase</emphasis>. If the event propagation was not
205 * stopped, the graph is walked backwards, from the source actor to the
206 * top-level, and the #ClutterActor::event signal, along with other event
207 * signals if needed, is emitted; this phase is also called <emphasis>the
208 * bubble phase</emphasis>. At any point of the signal emission, signal
209 * handlers can stop the propagation through the scene graph by returning
210 * %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
211 * returning %CLUTTER_EVENT_PROPAGATE.</para>
214 * <refsect2 id="ClutterActor-subclassing">
215 * <title>Implementing an actor</title>
216 * <para>Careful consideration should be given when deciding to implement
217 * a #ClutterActor sub-class. It is generally recommended to implement a
218 * sub-class of #ClutterActor only for actors that should be used as leaf
219 * nodes of a scene graph.</para>
220 * <para>If your actor should be painted in a custom way, you should
221 * override the #ClutterActor::paint signal class handler. You can either
222 * opt to chain up to the parent class implementation or decide to fully
223 * override the default paint implementation; Clutter will set up the
224 * transformations and clip regions prior to emitting the #ClutterActor::paint
226 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
227 * #ClutterActorClass.get_preferred_height() virtual functions it is
228 * possible to change or provide the preferred size of an actor; similarly,
229 * by overriding the #ClutterActorClass.allocate() virtual function it is
230 * possible to control the layout of the children of an actor. Make sure to
231 * always chain up to the parent implementation of the
232 * #ClutterActorClass.allocate() virtual function.</para>
233 * <para>In general, it is strongly encouraged to use delegation and
234 * composition instead of direct subclassing.</para>
237 * <refsect2 id="ClutterActor-script">
238 * <title>ClutterActor custom properties for #ClutterScript</title>
239 * <para>#ClutterActor defines a custom "rotation" property which
240 * allows a short-hand description of the rotations to be applied
241 * to an actor.</para>
242 * <para>The syntax of the "rotation" property is the following:</para>
246 * { "<axis>" : [ <angle>, [ <center> ] ] }
250 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
251 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
252 * floating point value representing the rotation angle on the given axis,
254 * <para>The <emphasis>center</emphasis> array is optional, and if present
255 * it must contain the center of rotation as described by two coordinates:
256 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
258 * <para>#ClutterActor will also parse every positional and dimensional
259 * property defined as a string through clutter_units_from_string(); you
260 * should read the documentation for the #ClutterUnits parser format for
261 * the valid units and syntax.</para>
264 * <refsect2 id="ClutterActor-animating">
265 * <title>Custom animatable properties</title>
266 * <para>#ClutterActor allows accessing properties of #ClutterAction
267 * and #ClutterConstraint instances associated to an actor instance
268 * for animation purposes.</para>
269 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
270 * property it is necessary to set the #ClutterActorMeta:name property on the
271 * given action or constraint.</para>
272 * <para>The property can be accessed using the following syntax:</para>
275 * @<section>.<meta-name>.<property-name>
278 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
279 * <para>The <emphasis>section</emphasis> fragment can be one between
280 * "actions", "constraints" and "effects".</para>
281 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
282 * action or constraint, as specified by the #ClutterActorMeta:name
284 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
285 * action or constraint property to be animated.</para>
286 * <para>The example below animates a #ClutterBindConstraint applied to an
287 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
288 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
289 * its initial state is fully transparent and overlapping the actor to
290 * which is bound to. </para>
291 * <informalexample><programlisting>
292 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
293 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
294 * clutter_actor_add_constraint (rect, constraint);
296 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
297 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
298 * clutter_actor_add_constraint (rect, constraint);
300 * clutter_actor_set_reactive (rect, TRUE);
301 * clutter_actor_set_opacity (rect, 0);
303 * g_signal_connect (rect, "button-press-event",
304 * G_CALLBACK (on_button_press),
306 * </programlisting></informalexample>
307 * <para>On button press, the rectangle "slides" from behind the actor to
308 * which is bound to, using the #ClutterBindConstraint:offset property and
309 * the #ClutterActor:opacity property.</para>
310 * <informalexample><programlisting>
311 * float new_offset = clutter_actor_get_width (origin) + h_padding;
313 * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
315 * "@constraints.bind-x.offset", new_offset,
317 * </programlisting></informalexample>
320 * <refsect2 id="ClutterActor-animatable-properties">
321 * <title>Animatable properties</title>
322 * <para>Certain properties on #ClutterActor are marked as "animatable";
323 * these properties will be automatically tweened between the current
324 * value and the new value when one is set.</para>
325 * <para>For backward compatibility, animatable properties will only be
326 * tweened if the easing duration is greater than 0, or if a new easing
327 * state is set, for instance the following example:</para>
328 * <informalexample><programlisting>
329 * clutter_actor_save_easing_state (actor);
330 * clutter_actor_set_position (actor, 200, 200);
331 * clutter_actor_restore_easing_state (actor);
332 * </programlisting></informalexample>
333 * <para>will tween the actor to the (200, 200) coordinates using the default
334 * easing mode and duration of a new easing state. The example above is
335 * equivalent to the following code:</para>
336 * <informalexample><programlisting>
337 * clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
338 * clutter_actor_set_easing_duration (actor, 250);
339 * clutter_actor_set_position (actor, 200, 200);
340 * clutter_actor_restore_easing_state (actor);
341 * </programlisting></informalexample>
342 * <para>It is possible to nest easing states to tween animatable
343 * properties using different modes and durations, for instance:</para>
344 * <informalexample><programlisting>
345 * clutter_actor_save_easing_state (actor); /* outer state */
347 * /* set the duration of the animation to 2 seconds and change position */
348 * clutter_actor_set_easing_duration (actor, 2000);
349 * clutter_actor_set_position (actor, 0, 0);
351 * clutter_actor_save_easing_state (actor); /* inner state */
353 * /* set the duration of the animation to 5 seconds and change depth and opacity */
354 * clutter_actor_set_easing_duration (actor, 5000);
355 * clutter_actor_set_depth (actor, 200);
356 * clutter_actor_set_opacity (actor, 0);
358 * clutter_actor_restore_easing_state (actor);
360 * clutter_actor_restore_easing_state (actor);
361 * </programlisting></informalexample>
366 * CLUTTER_ACTOR_IS_MAPPED:
367 * @a: a #ClutterActor
369 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
371 * The mapped state is set when the actor is visible and all its parents up
372 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
374 * This check can be used to see if an actor is going to be painted, as only
375 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
377 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
378 * not be checked directly; instead, the recommended usage is to connect a
379 * handler on the #GObject::notify signal for the #ClutterActor:mapped
380 * property of #ClutterActor, and check the presence of
381 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
383 * It is also important to note that Clutter may delay the changes of
384 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
385 * limitations, or during the reparenting of an actor, to optimize
386 * unnecessary (and potentially expensive) state changes.
392 * CLUTTER_ACTOR_IS_REALIZED:
393 * @a: a #ClutterActor
395 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
397 * The realized state has an actor-dependant interpretation. If an
398 * actor wants to delay allocating resources until it is attached to a
399 * stage, it may use the realize state to do so. However it is
400 * perfectly acceptable for an actor to allocate Cogl resources before
401 * being realized because there is only one drawing context used by Clutter
402 * so any resources will work on any stage. If an actor is mapped it
403 * must also be realized, but an actor can be realized and unmapped
404 * (this is so hiding an actor temporarily doesn't do an expensive
405 * unrealize/realize).
407 * To be realized an actor must be inside a stage, and all its parents
414 * CLUTTER_ACTOR_IS_VISIBLE:
415 * @a: a #ClutterActor
417 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
418 * Equivalent to the ClutterActor::visible object property.
420 * Note that an actor is only painted onscreen if it's mapped, which
421 * means it's visible, and all its parents are visible, and one of the
422 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
428 * CLUTTER_ACTOR_IS_REACTIVE:
429 * @a: a #ClutterActor
431 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
433 * Only reactive actors will receive event-related signals.
444 #include <gobject/gvaluecollector.h>
446 #include <cogl/cogl.h>
448 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
449 #define CLUTTER_ENABLE_EXPERIMENTAL_API
451 #include "clutter-actor-private.h"
453 #include "clutter-action.h"
454 #include "clutter-actor-meta-private.h"
455 #include "clutter-animatable.h"
456 #include "clutter-color-static.h"
457 #include "clutter-color.h"
458 #include "clutter-constraint.h"
459 #include "clutter-container.h"
460 #include "clutter-content-private.h"
461 #include "clutter-debug.h"
462 #include "clutter-effect-private.h"
463 #include "clutter-enum-types.h"
464 #include "clutter-fixed-layout.h"
465 #include "clutter-flatten-effect.h"
466 #include "clutter-interval.h"
467 #include "clutter-main.h"
468 #include "clutter-marshal.h"
469 #include "clutter-paint-nodes.h"
470 #include "clutter-paint-node-private.h"
471 #include "clutter-paint-volume-private.h"
472 #include "clutter-private.h"
473 #include "clutter-profile.h"
474 #include "clutter-property-transition.h"
475 #include "clutter-scriptable.h"
476 #include "clutter-script-private.h"
477 #include "clutter-stage-private.h"
478 #include "clutter-timeline.h"
479 #include "clutter-transition.h"
480 #include "clutter-units.h"
482 #include "deprecated/clutter-actor.h"
483 #include "deprecated/clutter-behaviour.h"
484 #include "deprecated/clutter-container.h"
486 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
487 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
489 /* Internal enum used to control mapped state update. This is a hint
490 * which indicates when to do something other than just enforce
494 MAP_STATE_CHECK, /* just enforce invariants. */
495 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
496 * used when about to unparent.
498 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
499 * used to set mapped on toplevels.
501 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
502 * used just before unmapping parent.
506 /* 3 entries should be a good compromise, few layout managers
507 * will ask for 3 different preferred size in each allocation cycle */
508 #define N_CACHED_SIZE_REQUESTS 3
510 struct _ClutterActorPrivate
513 ClutterRequestMode request_mode;
515 /* our cached size requests for different width / height */
516 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
517 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
519 /* An age of 0 means the entry is not set */
520 guint cached_height_age;
521 guint cached_width_age;
523 /* the bounding box of the actor, relative to the parent's
526 ClutterActorBox allocation;
527 ClutterAllocationFlags allocation_flags;
529 /* clip, in actor coordinates */
530 cairo_rectangle_t clip;
532 /* the cached transformation matrix; see apply_transform() */
533 CoglMatrix transform;
536 gint opacity_override;
538 ClutterOffscreenRedirect offscreen_redirect;
540 /* This is an internal effect used to implement the
541 offscreen-redirect property */
542 ClutterEffect *flatten_effect;
545 ClutterActor *parent;
546 ClutterActor *prev_sibling;
547 ClutterActor *next_sibling;
548 ClutterActor *first_child;
549 ClutterActor *last_child;
553 /* tracks whenever the children of an actor are changed; the
554 * age is incremented by 1 whenever an actor is added or
555 * removed. the age is not incremented when the first or the
556 * last child pointers are changed, or when grandchildren of
557 * an actor are changed.
561 gchar *name; /* a non-unique name, used for debugging */
562 guint32 id; /* unique id, used for backward compatibility */
564 gint32 pick_id; /* per-stage unique id, used for picking */
566 /* a back-pointer to the Pango context that we can use
567 * to create pre-configured PangoLayout
569 PangoContext *pango_context;
571 /* the text direction configured for this child - either by
572 * application code, or by the actor's parent
574 ClutterTextDirection text_direction;
576 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
580 ClutterMetaGroup *actions;
581 ClutterMetaGroup *constraints;
582 ClutterMetaGroup *effects;
584 /* delegate object used to allocate the children of this actor */
585 ClutterLayoutManager *layout_manager;
587 /* delegate object used to paint the contents of this actor */
588 ClutterContent *content;
590 ClutterContentGravity content_gravity;
592 /* used when painting, to update the paint volume */
593 ClutterEffect *current_effect;
595 /* This is used to store an effect which needs to be redrawn. A
596 redraw can be queued to start from a particular effect. This is
597 used by parametrised effects that can cache an image of the
598 actor. If a parameter of the effect changes then it only needs to
599 redraw the cached image, not the actual actor. The pointer is
600 only valid if is_dirty == TRUE. If the pointer is NULL then the
601 whole actor is dirty. */
602 ClutterEffect *effect_to_redraw;
604 /* This is used when painting effects to implement the
605 clutter_actor_continue_paint() function. It points to the node in
606 the list of effects that is next in the chain */
607 const GList *next_effect_to_paint;
609 ClutterPaintVolume paint_volume;
611 /* NB: This volume isn't relative to this actor, it is in eye
612 * coordinates so that it can remain valid after the actor changes.
614 ClutterPaintVolume last_paint_volume;
616 ClutterStageQueueRedrawEntry *queue_redraw_entry;
618 ClutterColor bg_color;
622 /* fixed position and sizes */
623 guint position_set : 1;
624 guint min_width_set : 1;
625 guint min_height_set : 1;
626 guint natural_width_set : 1;
627 guint natural_height_set : 1;
628 /* cached request is invalid (implies allocation is too) */
629 guint needs_width_request : 1;
630 /* cached request is invalid (implies allocation is too) */
631 guint needs_height_request : 1;
632 /* cached allocation is invalid (request has changed, probably) */
633 guint needs_allocation : 1;
634 guint show_on_set_parent : 1;
636 guint clip_to_allocation : 1;
637 guint enable_model_view_transform : 1;
638 guint enable_paint_unmapped : 1;
639 guint has_pointer : 1;
640 guint propagated_one_redraw : 1;
641 guint paint_volume_valid : 1;
642 guint last_paint_volume_valid : 1;
643 guint in_clone_paint : 1;
644 guint transform_valid : 1;
645 /* This is TRUE if anything has queued a redraw since we were last
646 painted. In this case effect_to_redraw will point to an effect
647 the redraw was queued from or it will be NULL if the redraw was
648 queued without an effect. */
650 guint bg_color_set : 1;
659 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
660 * when set they force a size request, when gotten they
661 * get the allocation if the allocation is valid, and the
669 /* Then the rest of these size-related properties are the "actual"
670 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
675 PROP_FIXED_POSITION_SET,
684 PROP_NATURAL_WIDTH_SET,
687 PROP_NATURAL_HEIGHT_SET,
691 /* Allocation properties are read-only */
698 PROP_CLIP_TO_ALLOCATION,
702 PROP_OFFSCREEN_REDIRECT,
715 PROP_ROTATION_ANGLE_X,
716 PROP_ROTATION_ANGLE_Y,
717 PROP_ROTATION_ANGLE_Z,
718 PROP_ROTATION_CENTER_X,
719 PROP_ROTATION_CENTER_Y,
720 PROP_ROTATION_CENTER_Z,
721 /* This property only makes sense for the z rotation because the
722 others would depend on the actor having a size along the
724 PROP_ROTATION_CENTER_Z_GRAVITY,
730 PROP_SHOW_ON_SET_PARENT,
748 PROP_BACKGROUND_COLOR,
749 PROP_BACKGROUND_COLOR_SET,
755 PROP_CONTENT_GRAVITY,
761 static GParamSpec *obj_props[PROP_LAST];
780 BUTTON_RELEASE_EVENT,
792 static guint actor_signals[LAST_SIGNAL] = { 0, };
794 static void clutter_container_iface_init (ClutterContainerIface *iface);
795 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
796 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
797 static void atk_implementor_iface_init (AtkImplementorIface *iface);
799 /* These setters are all static for now, maybe they should be in the
800 * public API, but they are perhaps obscure enough to leave only as
803 static void clutter_actor_set_min_width (ClutterActor *self,
805 static void clutter_actor_set_min_height (ClutterActor *self,
807 static void clutter_actor_set_natural_width (ClutterActor *self,
808 gfloat natural_width);
809 static void clutter_actor_set_natural_height (ClutterActor *self,
810 gfloat natural_height);
811 static void clutter_actor_set_min_width_set (ClutterActor *self,
812 gboolean use_min_width);
813 static void clutter_actor_set_min_height_set (ClutterActor *self,
814 gboolean use_min_height);
815 static void clutter_actor_set_natural_width_set (ClutterActor *self,
816 gboolean use_natural_width);
817 static void clutter_actor_set_natural_height_set (ClutterActor *self,
818 gboolean use_natural_height);
819 static void clutter_actor_update_map_state (ClutterActor *self,
820 MapStateChange change);
821 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
823 /* Helper routines for managing anchor coords */
824 static void clutter_anchor_coord_get_units (ClutterActor *self,
825 const AnchorCoord *coord,
829 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
834 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
835 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
836 ClutterGravity gravity);
838 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
840 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
842 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
843 ClutterActor *ancestor,
846 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
848 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
850 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
851 const ClutterColor *color);
853 static void on_layout_manager_changed (ClutterLayoutManager *manager,
856 /* Helper macro which translates by the anchor coord, applies the
857 given transformation and then translates back */
858 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
859 gfloat _tx, _ty, _tz; \
860 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
861 cogl_matrix_translate ((m), _tx, _ty, _tz); \
863 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
865 static GQuark quark_shader_data = 0;
866 static GQuark quark_actor_layout_info = 0;
867 static GQuark quark_actor_transform_info = 0;
868 static GQuark quark_actor_animation_info = 0;
870 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
872 G_TYPE_INITIALLY_UNOWNED,
873 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
874 clutter_container_iface_init)
875 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
876 clutter_scriptable_iface_init)
877 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
878 clutter_animatable_iface_init)
879 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
880 atk_implementor_iface_init));
883 * clutter_actor_get_debug_name:
884 * @actor: a #ClutterActor
886 * Retrieves a printable name of @actor for debugging messages
888 * Return value: a string with a printable name
891 _clutter_actor_get_debug_name (ClutterActor *actor)
893 return actor->priv->name != NULL ? actor->priv->name
894 : G_OBJECT_TYPE_NAME (actor);
897 #ifdef CLUTTER_ENABLE_DEBUG
898 /* XXX - this is for debugging only, remove once working (or leave
899 * in only in some debug mode). Should leave it for a little while
900 * until we're confident in the new map/realize/visible handling.
903 clutter_actor_verify_map_state (ClutterActor *self)
905 ClutterActorPrivate *priv = self->priv;
907 if (CLUTTER_ACTOR_IS_REALIZED (self))
909 /* all bets are off during reparent when we're potentially realized,
910 * but should not be according to invariants
912 if (!CLUTTER_ACTOR_IN_REPARENT (self))
914 if (priv->parent == NULL)
916 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
920 g_warning ("Realized non-toplevel actor '%s' should "
922 _clutter_actor_get_debug_name (self));
924 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
926 g_warning ("Realized actor %s has an unrealized parent %s",
927 _clutter_actor_get_debug_name (self),
928 _clutter_actor_get_debug_name (priv->parent));
933 if (CLUTTER_ACTOR_IS_MAPPED (self))
935 if (!CLUTTER_ACTOR_IS_REALIZED (self))
936 g_warning ("Actor '%s' is mapped but not realized",
937 _clutter_actor_get_debug_name (self));
939 /* remaining bets are off during reparent when we're potentially
940 * mapped, but should not be according to invariants
942 if (!CLUTTER_ACTOR_IN_REPARENT (self))
944 if (priv->parent == NULL)
946 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
948 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
949 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
951 g_warning ("Toplevel actor '%s' is mapped "
953 _clutter_actor_get_debug_name (self));
958 g_warning ("Mapped actor '%s' should have a parent",
959 _clutter_actor_get_debug_name (self));
964 ClutterActor *iter = self;
966 /* check for the enable_paint_unmapped flag on the actor
967 * and parents; if the flag is enabled at any point of this
968 * branch of the scene graph then all the later checks
973 if (iter->priv->enable_paint_unmapped)
976 iter = iter->priv->parent;
979 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
981 g_warning ("Actor '%s' should not be mapped if parent '%s'"
983 _clutter_actor_get_debug_name (self),
984 _clutter_actor_get_debug_name (priv->parent));
987 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
989 g_warning ("Actor '%s' should not be mapped if parent '%s'"
991 _clutter_actor_get_debug_name (self),
992 _clutter_actor_get_debug_name (priv->parent));
995 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
997 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
998 g_warning ("Actor '%s' is mapped but its non-toplevel "
999 "parent '%s' is not mapped",
1000 _clutter_actor_get_debug_name (self),
1001 _clutter_actor_get_debug_name (priv->parent));
1008 #endif /* CLUTTER_ENABLE_DEBUG */
1011 clutter_actor_set_mapped (ClutterActor *self,
1014 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1019 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1020 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1024 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1025 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1029 /* this function updates the mapped and realized states according to
1030 * invariants, in the appropriate order.
1033 clutter_actor_update_map_state (ClutterActor *self,
1034 MapStateChange change)
1036 gboolean was_mapped;
1038 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1040 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1042 /* the mapped flag on top-level actors must be set by the
1043 * per-backend implementation because it might be asynchronous.
1045 * That is, the MAPPED flag on toplevels currently tracks the X
1046 * server mapped-ness of the window, while the expected behavior
1047 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1048 * This creates some weird complexity by breaking the invariant
1049 * that if we're visible and all ancestors shown then we are
1050 * also mapped - instead, we are mapped if all ancestors
1051 * _possibly excepting_ the stage are mapped. The stage
1052 * will map/unmap for example when it is minimized or
1053 * moved to another workspace.
1055 * So, the only invariant on the stage is that if visible it
1056 * should be realized, and that it has to be visible to be
1059 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1060 clutter_actor_realize (self);
1064 case MAP_STATE_CHECK:
1067 case MAP_STATE_MAKE_MAPPED:
1068 g_assert (!was_mapped);
1069 clutter_actor_set_mapped (self, TRUE);
1072 case MAP_STATE_MAKE_UNMAPPED:
1073 g_assert (was_mapped);
1074 clutter_actor_set_mapped (self, FALSE);
1077 case MAP_STATE_MAKE_UNREALIZED:
1078 /* we only use MAKE_UNREALIZED in unparent,
1079 * and unparenting a stage isn't possible.
1080 * If someone wants to just unrealize a stage
1081 * then clutter_actor_unrealize() doesn't
1082 * go through this codepath.
1084 g_warning ("Trying to force unrealize stage is not allowed");
1088 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1089 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1090 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1092 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1093 "it is somehow still mapped",
1094 _clutter_actor_get_debug_name (self));
1099 ClutterActorPrivate *priv = self->priv;
1100 ClutterActor *parent = priv->parent;
1101 gboolean should_be_mapped;
1102 gboolean may_be_realized;
1103 gboolean must_be_realized;
1105 should_be_mapped = FALSE;
1106 may_be_realized = TRUE;
1107 must_be_realized = FALSE;
1109 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1111 may_be_realized = FALSE;
1115 /* Maintain invariant that if parent is mapped, and we are
1116 * visible, then we are mapped ... unless parent is a
1117 * stage, in which case we map regardless of parent's map
1118 * state but do require stage to be visible and realized.
1120 * If parent is realized, that does not force us to be
1121 * realized; but if parent is unrealized, that does force
1122 * us to be unrealized.
1124 * The reason we don't force children to realize with
1125 * parents is _clutter_actor_rerealize(); if we require that
1126 * a realized parent means children are realized, then to
1127 * unrealize an actor we would have to unrealize its
1128 * parents, which would end up meaning unrealizing and
1129 * hiding the entire stage. So we allow unrealizing a
1130 * child (as long as that child is not mapped) while that
1131 * child still has a realized parent.
1133 * Also, if we unrealize from leaf nodes to root, and
1134 * realize from root to leaf, the invariants are never
1135 * violated if we allow children to be unrealized
1136 * while parents are realized.
1138 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1139 * to force us to unmap, even though parent is still
1140 * mapped. This is because we're unmapping from leaf nodes
1143 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1144 change != MAP_STATE_MAKE_UNMAPPED)
1146 gboolean parent_is_visible_realized_toplevel;
1148 parent_is_visible_realized_toplevel =
1149 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1150 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1151 CLUTTER_ACTOR_IS_REALIZED (parent));
1153 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1154 parent_is_visible_realized_toplevel)
1156 must_be_realized = TRUE;
1157 should_be_mapped = TRUE;
1161 /* if the actor has been set to be painted even if unmapped
1162 * then we should map it and check for realization as well;
1163 * this is an override for the branch of the scene graph
1164 * which begins with this node
1166 if (priv->enable_paint_unmapped)
1168 if (priv->parent == NULL)
1169 g_warning ("Attempting to map an unparented actor '%s'",
1170 _clutter_actor_get_debug_name (self));
1172 should_be_mapped = TRUE;
1173 must_be_realized = TRUE;
1176 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1177 may_be_realized = FALSE;
1180 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1183 g_warning ("Attempting to map a child that does not "
1184 "meet the necessary invariants: the actor '%s' "
1186 _clutter_actor_get_debug_name (self));
1188 g_warning ("Attempting to map a child that does not "
1189 "meet the necessary invariants: the actor '%s' "
1190 "is parented to an unmapped actor '%s'",
1191 _clutter_actor_get_debug_name (self),
1192 _clutter_actor_get_debug_name (priv->parent));
1195 /* If in reparent, we temporarily suspend unmap and unrealize.
1197 * We want to go in the order "realize, map" and "unmap, unrealize"
1201 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1202 clutter_actor_set_mapped (self, FALSE);
1205 if (must_be_realized)
1206 clutter_actor_realize (self);
1208 /* if we must be realized then we may be, presumably */
1209 g_assert (!(must_be_realized && !may_be_realized));
1212 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1213 clutter_actor_unrealize_not_hiding (self);
1216 if (should_be_mapped)
1218 if (!must_be_realized)
1219 g_warning ("Somehow we think actor '%s' should be mapped but "
1220 "not realized, which isn't allowed",
1221 _clutter_actor_get_debug_name (self));
1223 /* realization is allowed to fail (though I don't know what
1224 * an app is supposed to do about that - shouldn't it just
1225 * be a g_error? anyway, we have to avoid mapping if this
1228 if (CLUTTER_ACTOR_IS_REALIZED (self))
1229 clutter_actor_set_mapped (self, TRUE);
1233 #ifdef CLUTTER_ENABLE_DEBUG
1234 /* check all invariants were kept */
1235 clutter_actor_verify_map_state (self);
1240 clutter_actor_real_map (ClutterActor *self)
1242 ClutterActorPrivate *priv = self->priv;
1243 ClutterActor *stage, *iter;
1245 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1247 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1248 _clutter_actor_get_debug_name (self));
1250 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1252 stage = _clutter_actor_get_stage_internal (self);
1253 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1255 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1257 _clutter_actor_get_debug_name (self));
1259 /* notify on parent mapped before potentially mapping
1260 * children, so apps see a top-down notification.
1262 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1264 for (iter = self->priv->first_child;
1266 iter = iter->priv->next_sibling)
1268 clutter_actor_map (iter);
1273 * clutter_actor_map:
1274 * @self: A #ClutterActor
1276 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1277 * and realizes its children if they are visible. Does nothing if the
1278 * actor is not visible.
1280 * Calling this function is strongly disencouraged: the default
1281 * implementation of #ClutterActorClass.map() will map all the children
1282 * of an actor when mapping its parent.
1284 * When overriding map, it is mandatory to chain up to the parent
1290 clutter_actor_map (ClutterActor *self)
1292 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1294 if (CLUTTER_ACTOR_IS_MAPPED (self))
1297 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1300 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1304 clutter_actor_real_unmap (ClutterActor *self)
1306 ClutterActorPrivate *priv = self->priv;
1309 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1311 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1312 _clutter_actor_get_debug_name (self));
1314 for (iter = self->priv->first_child;
1316 iter = iter->priv->next_sibling)
1318 clutter_actor_unmap (iter);
1321 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1323 /* clear the contents of the last paint volume, so that hiding + moving +
1324 * showing will not result in the wrong area being repainted
1326 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1327 priv->last_paint_volume_valid = TRUE;
1329 /* notify on parent mapped after potentially unmapping
1330 * children, so apps see a bottom-up notification.
1332 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1334 /* relinquish keyboard focus if we were unmapped while owning it */
1335 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1337 ClutterStage *stage;
1339 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1342 _clutter_stage_release_pick_id (stage, priv->pick_id);
1346 if (stage != NULL &&
1347 clutter_stage_get_key_focus (stage) == self)
1349 clutter_stage_set_key_focus (stage, NULL);
1355 * clutter_actor_unmap:
1356 * @self: A #ClutterActor
1358 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1359 * unmaps its children if they were mapped.
1361 * Calling this function is not encouraged: the default #ClutterActor
1362 * implementation of #ClutterActorClass.unmap() will also unmap any
1363 * eventual children by default when their parent is unmapped.
1365 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1366 * chain up to the parent implementation.
1368 * <note>It is important to note that the implementation of the
1369 * #ClutterActorClass.unmap() virtual function may be called after
1370 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1371 * implementation, but it is guaranteed to be called before the
1372 * #GObjectClass.finalize() implementation.</note>
1377 clutter_actor_unmap (ClutterActor *self)
1379 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1381 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1384 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1388 clutter_actor_real_show (ClutterActor *self)
1390 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1392 ClutterActorPrivate *priv = self->priv;
1394 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1396 /* we notify on the "visible" flag in the clutter_actor_show()
1397 * wrapper so the entire show signal emission completes first
1400 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1402 /* we queue a relayout unless the actor is inside a
1403 * container that explicitly told us not to
1405 if (priv->parent != NULL &&
1406 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1408 /* While an actor is hidden the parent may not have
1409 * allocated/requested so we need to start from scratch
1410 * and avoid the short-circuiting in
1411 * clutter_actor_queue_relayout().
1413 priv->needs_width_request = FALSE;
1414 priv->needs_height_request = FALSE;
1415 priv->needs_allocation = FALSE;
1416 clutter_actor_queue_relayout (self);
1422 set_show_on_set_parent (ClutterActor *self,
1425 ClutterActorPrivate *priv = self->priv;
1427 set_show = !!set_show;
1429 if (priv->show_on_set_parent == set_show)
1432 if (priv->parent == NULL)
1434 priv->show_on_set_parent = set_show;
1435 g_object_notify_by_pspec (G_OBJECT (self),
1436 obj_props[PROP_SHOW_ON_SET_PARENT]);
1441 * clutter_actor_show:
1442 * @self: A #ClutterActor
1444 * Flags an actor to be displayed. An actor that isn't shown will not
1445 * be rendered on the stage.
1447 * Actors are visible by default.
1449 * If this function is called on an actor without a parent, the
1450 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1454 clutter_actor_show (ClutterActor *self)
1456 ClutterActorPrivate *priv;
1458 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1460 /* simple optimization */
1461 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1463 /* we still need to set the :show-on-set-parent property, in
1464 * case show() is called on an unparented actor
1466 set_show_on_set_parent (self, TRUE);
1470 #ifdef CLUTTER_ENABLE_DEBUG
1471 clutter_actor_verify_map_state (self);
1476 g_object_freeze_notify (G_OBJECT (self));
1478 set_show_on_set_parent (self, TRUE);
1480 g_signal_emit (self, actor_signals[SHOW], 0);
1481 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1483 if (priv->parent != NULL)
1484 clutter_actor_queue_redraw (priv->parent);
1486 g_object_thaw_notify (G_OBJECT (self));
1490 * clutter_actor_show_all:
1491 * @self: a #ClutterActor
1493 * Calls clutter_actor_show() on all children of an actor (if any).
1497 * Deprecated: 1.10: Actors are visible by default
1500 clutter_actor_show_all (ClutterActor *self)
1502 ClutterActorClass *klass;
1504 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1506 klass = CLUTTER_ACTOR_GET_CLASS (self);
1507 if (klass->show_all)
1508 klass->show_all (self);
1512 clutter_actor_real_hide (ClutterActor *self)
1514 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1516 ClutterActorPrivate *priv = self->priv;
1518 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1520 /* we notify on the "visible" flag in the clutter_actor_hide()
1521 * wrapper so the entire hide signal emission completes first
1524 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1526 /* we queue a relayout unless the actor is inside a
1527 * container that explicitly told us not to
1529 if (priv->parent != NULL &&
1530 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1531 clutter_actor_queue_relayout (priv->parent);
1536 * clutter_actor_hide:
1537 * @self: A #ClutterActor
1539 * Flags an actor to be hidden. A hidden actor will not be
1540 * rendered on the stage.
1542 * Actors are visible by default.
1544 * If this function is called on an actor without a parent, the
1545 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1549 clutter_actor_hide (ClutterActor *self)
1551 ClutterActorPrivate *priv;
1553 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1555 /* simple optimization */
1556 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1558 /* we still need to set the :show-on-set-parent property, in
1559 * case hide() is called on an unparented actor
1561 set_show_on_set_parent (self, FALSE);
1565 #ifdef CLUTTER_ENABLE_DEBUG
1566 clutter_actor_verify_map_state (self);
1571 g_object_freeze_notify (G_OBJECT (self));
1573 set_show_on_set_parent (self, FALSE);
1575 g_signal_emit (self, actor_signals[HIDE], 0);
1576 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1578 if (priv->parent != NULL)
1579 clutter_actor_queue_redraw (priv->parent);
1581 g_object_thaw_notify (G_OBJECT (self));
1585 * clutter_actor_hide_all:
1586 * @self: a #ClutterActor
1588 * Calls clutter_actor_hide() on all child actors (if any).
1592 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1593 * prevent its children from being painted as well.
1596 clutter_actor_hide_all (ClutterActor *self)
1598 ClutterActorClass *klass;
1600 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1602 klass = CLUTTER_ACTOR_GET_CLASS (self);
1603 if (klass->hide_all)
1604 klass->hide_all (self);
1608 * clutter_actor_realize:
1609 * @self: A #ClutterActor
1611 * Realization informs the actor that it is attached to a stage. It
1612 * can use this to allocate resources if it wanted to delay allocation
1613 * until it would be rendered. However it is perfectly acceptable for
1614 * an actor to create resources before being realized because Clutter
1615 * only ever has a single rendering context so that actor is free to
1616 * be moved from one stage to another.
1618 * This function does nothing if the actor is already realized.
1620 * Because a realized actor must have realized parent actors, calling
1621 * clutter_actor_realize() will also realize all parents of the actor.
1623 * This function does not realize child actors, except in the special
1624 * case that realizing the stage, when the stage is visible, will
1625 * suddenly map (and thus realize) the children of the stage.
1628 clutter_actor_realize (ClutterActor *self)
1630 ClutterActorPrivate *priv;
1632 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1636 #ifdef CLUTTER_ENABLE_DEBUG
1637 clutter_actor_verify_map_state (self);
1640 if (CLUTTER_ACTOR_IS_REALIZED (self))
1643 /* To be realized, our parent actors must be realized first.
1644 * This will only succeed if we're inside a toplevel.
1646 if (priv->parent != NULL)
1647 clutter_actor_realize (priv->parent);
1649 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1651 /* toplevels can be realized at any time */
1655 /* "Fail" the realization if parent is missing or unrealized;
1656 * this should really be a g_warning() not some kind of runtime
1657 * failure; how can an app possibly recover? Instead it's a bug
1658 * in the app and the app should get an explanatory warning so
1659 * someone can fix it. But for now it's too hard to fix this
1660 * because e.g. ClutterTexture needs reworking.
1662 if (priv->parent == NULL ||
1663 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1667 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1669 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1670 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1672 g_signal_emit (self, actor_signals[REALIZE], 0);
1674 /* Stage actor is allowed to unset the realized flag again in its
1675 * default signal handler, though that is a pathological situation.
1678 /* If realization "failed" we'll have to update child state. */
1679 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1683 clutter_actor_real_unrealize (ClutterActor *self)
1685 /* we must be unmapped (implying our children are also unmapped) */
1686 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1690 * clutter_actor_unrealize:
1691 * @self: A #ClutterActor
1693 * Unrealization informs the actor that it may be being destroyed or
1694 * moved to another stage. The actor may want to destroy any
1695 * underlying graphics resources at this point. However it is
1696 * perfectly acceptable for it to retain the resources until the actor
1697 * is destroyed because Clutter only ever uses a single rendering
1698 * context and all of the graphics resources are valid on any stage.
1700 * Because mapped actors must be realized, actors may not be
1701 * unrealized if they are mapped. This function hides the actor to be
1702 * sure it isn't mapped, an application-visible side effect that you
1703 * may not be expecting.
1705 * This function should not be called by application code.
1708 clutter_actor_unrealize (ClutterActor *self)
1710 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1711 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1713 /* This function should not really be in the public API, because
1714 * there isn't a good reason to call it. ClutterActor will already
1715 * unrealize things for you when it's important to do so.
1717 * If you were using clutter_actor_unrealize() in a dispose
1718 * implementation, then don't, just chain up to ClutterActor's
1721 * If you were using clutter_actor_unrealize() to implement
1722 * unrealizing children of your container, then don't, ClutterActor
1723 * will already take care of that.
1725 * If you were using clutter_actor_unrealize() to re-realize to
1726 * create your resources in a different way, then use
1727 * _clutter_actor_rerealize() (inside Clutter) or just call your
1728 * code that recreates your resources directly (outside Clutter).
1731 #ifdef CLUTTER_ENABLE_DEBUG
1732 clutter_actor_verify_map_state (self);
1735 clutter_actor_hide (self);
1737 clutter_actor_unrealize_not_hiding (self);
1740 static ClutterActorTraverseVisitFlags
1741 unrealize_actor_before_children_cb (ClutterActor *self,
1745 /* If an actor is already unrealized we know its children have also
1746 * already been unrealized... */
1747 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1748 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1750 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1752 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1755 static ClutterActorTraverseVisitFlags
1756 unrealize_actor_after_children_cb (ClutterActor *self,
1760 /* We want to unset the realized flag only _after_
1761 * child actors are unrealized, to maintain invariants.
1763 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1764 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1765 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1769 * clutter_actor_unrealize_not_hiding:
1770 * @self: A #ClutterActor
1772 * Unrealization informs the actor that it may be being destroyed or
1773 * moved to another stage. The actor may want to destroy any
1774 * underlying graphics resources at this point. However it is
1775 * perfectly acceptable for it to retain the resources until the actor
1776 * is destroyed because Clutter only ever uses a single rendering
1777 * context and all of the graphics resources are valid on any stage.
1779 * Because mapped actors must be realized, actors may not be
1780 * unrealized if they are mapped. You must hide the actor or one of
1781 * its parents before attempting to unrealize.
1783 * This function is separate from clutter_actor_unrealize() because it
1784 * does not automatically hide the actor.
1785 * Actors need not be hidden to be unrealized, they just need to
1786 * be unmapped. In fact we don't want to mess up the application's
1787 * setting of the "visible" flag, so hiding is very undesirable.
1789 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1790 * backward compatibility.
1793 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1795 _clutter_actor_traverse (self,
1796 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1797 unrealize_actor_before_children_cb,
1798 unrealize_actor_after_children_cb,
1803 * _clutter_actor_rerealize:
1804 * @self: A #ClutterActor
1805 * @callback: Function to call while unrealized
1806 * @data: data for callback
1808 * If an actor is already unrealized, this just calls the callback.
1810 * If it is realized, it unrealizes temporarily, calls the callback,
1811 * and then re-realizes the actor.
1813 * As a side effect, leaves all children of the actor unrealized if
1814 * the actor was realized but not showing. This is because when we
1815 * unrealize the actor temporarily we must unrealize its children
1816 * (e.g. children of a stage can't be realized if stage window is
1817 * gone). And we aren't clever enough to save the realization state of
1818 * all children. In most cases this should not matter, because
1819 * the children will automatically realize when they next become mapped.
1822 _clutter_actor_rerealize (ClutterActor *self,
1823 ClutterCallback callback,
1826 gboolean was_mapped;
1827 gboolean was_showing;
1828 gboolean was_realized;
1830 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1832 #ifdef CLUTTER_ENABLE_DEBUG
1833 clutter_actor_verify_map_state (self);
1836 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1837 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1838 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1840 /* Must be unmapped to unrealize. Note we only have to hide this
1841 * actor if it was mapped (if all parents were showing). If actor
1842 * is merely visible (but not mapped), then that's fine, we can
1846 clutter_actor_hide (self);
1848 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1850 /* unrealize self and all children */
1851 clutter_actor_unrealize_not_hiding (self);
1853 if (callback != NULL)
1855 (* callback) (self, data);
1859 clutter_actor_show (self); /* will realize only if mapping implies it */
1860 else if (was_realized)
1861 clutter_actor_realize (self); /* realize self and all parents */
1865 clutter_actor_real_pick (ClutterActor *self,
1866 const ClutterColor *color)
1868 /* the default implementation is just to paint a rectangle
1869 * with the same size of the actor using the passed color
1871 if (clutter_actor_should_pick_paint (self))
1873 ClutterActorBox box = { 0, };
1874 float width, height;
1876 clutter_actor_get_allocation_box (self, &box);
1878 width = box.x2 - box.x1;
1879 height = box.y2 - box.y1;
1881 cogl_set_source_color4ub (color->red,
1886 cogl_rectangle (0, 0, width, height);
1889 /* XXX - this thoroughly sucks, but we need to maintain compatibility
1890 * with existing container classes that override the pick() virtual
1891 * and chain up to the default implementation - otherwise we'll end up
1892 * painting our children twice.
1894 * this has to go away for 2.0; hopefully along the pick() itself.
1896 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1900 for (iter = self->priv->first_child;
1902 iter = iter->priv->next_sibling)
1903 clutter_actor_paint (iter);
1908 * clutter_actor_should_pick_paint:
1909 * @self: A #ClutterActor
1911 * Should be called inside the implementation of the
1912 * #ClutterActor::pick virtual function in order to check whether
1913 * the actor should paint itself in pick mode or not.
1915 * This function should never be called directly by applications.
1917 * Return value: %TRUE if the actor should paint its silhouette,
1921 clutter_actor_should_pick_paint (ClutterActor *self)
1923 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1925 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1926 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1927 CLUTTER_ACTOR_IS_REACTIVE (self)))
1934 clutter_actor_real_get_preferred_width (ClutterActor *self,
1936 gfloat *min_width_p,
1937 gfloat *natural_width_p)
1939 ClutterActorPrivate *priv = self->priv;
1941 if (priv->n_children != 0 &&
1942 priv->layout_manager != NULL)
1944 ClutterContainer *container = CLUTTER_CONTAINER (self);
1946 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1947 "for the preferred width",
1948 G_OBJECT_TYPE_NAME (priv->layout_manager),
1949 priv->layout_manager);
1951 clutter_layout_manager_get_preferred_width (priv->layout_manager,
1960 /* Default implementation is always 0x0, usually an actor
1961 * using this default is relying on someone to set the
1964 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1969 if (natural_width_p)
1970 *natural_width_p = 0;
1974 clutter_actor_real_get_preferred_height (ClutterActor *self,
1976 gfloat *min_height_p,
1977 gfloat *natural_height_p)
1979 ClutterActorPrivate *priv = self->priv;
1981 if (priv->n_children != 0 &&
1982 priv->layout_manager != NULL)
1984 ClutterContainer *container = CLUTTER_CONTAINER (self);
1986 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1987 "for the preferred height",
1988 G_OBJECT_TYPE_NAME (priv->layout_manager),
1989 priv->layout_manager);
1991 clutter_layout_manager_get_preferred_height (priv->layout_manager,
1999 /* Default implementation is always 0x0, usually an actor
2000 * using this default is relying on someone to set the
2003 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2008 if (natural_height_p)
2009 *natural_height_p = 0;
2013 clutter_actor_store_old_geometry (ClutterActor *self,
2014 ClutterActorBox *box)
2016 *box = self->priv->allocation;
2020 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2021 const ClutterActorBox *old)
2023 ClutterActorPrivate *priv = self->priv;
2024 GObject *obj = G_OBJECT (self);
2026 g_object_freeze_notify (obj);
2028 /* to avoid excessive requisition or allocation cycles we
2029 * use the cached values.
2031 * - if we don't have an allocation we assume that we need
2033 * - if we don't have a width or a height request we notify
2035 * - if we have a valid allocation then we check the old
2036 * bounding box with the current allocation and we notify
2039 if (priv->needs_allocation)
2041 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2042 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2043 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2044 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2046 else if (priv->needs_width_request || priv->needs_height_request)
2048 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2049 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2054 gfloat widthu, heightu;
2056 xu = priv->allocation.x1;
2057 yu = priv->allocation.y1;
2058 widthu = priv->allocation.x2 - priv->allocation.x1;
2059 heightu = priv->allocation.y2 - priv->allocation.y1;
2062 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2065 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2067 if (widthu != (old->x2 - old->x1))
2068 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2070 if (heightu != (old->y2 - old->y1))
2071 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2074 g_object_thaw_notify (obj);
2078 * clutter_actor_set_allocation_internal:
2079 * @self: a #ClutterActor
2080 * @box: a #ClutterActorBox
2081 * @flags: allocation flags
2083 * Stores the allocation of @self.
2085 * This function only performs basic storage and property notification.
2087 * This function should be called by clutter_actor_set_allocation()
2088 * and by the default implementation of #ClutterActorClass.allocate().
2090 * Return value: %TRUE if the allocation of the #ClutterActor has been
2091 * changed, and %FALSE otherwise
2093 static inline gboolean
2094 clutter_actor_set_allocation_internal (ClutterActor *self,
2095 const ClutterActorBox *box,
2096 ClutterAllocationFlags flags)
2098 ClutterActorPrivate *priv = self->priv;
2100 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2101 gboolean flags_changed;
2103 ClutterActorBox old_alloc = { 0, };
2105 obj = G_OBJECT (self);
2107 g_object_freeze_notify (obj);
2109 clutter_actor_store_old_geometry (self, &old_alloc);
2111 x1_changed = priv->allocation.x1 != box->x1;
2112 y1_changed = priv->allocation.y1 != box->y1;
2113 x2_changed = priv->allocation.x2 != box->x2;
2114 y2_changed = priv->allocation.y2 != box->y2;
2116 flags_changed = priv->allocation_flags != flags;
2118 priv->allocation = *box;
2119 priv->allocation_flags = flags;
2121 /* allocation is authoritative */
2122 priv->needs_width_request = FALSE;
2123 priv->needs_height_request = FALSE;
2124 priv->needs_allocation = FALSE;
2126 if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
2128 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2129 _clutter_actor_get_debug_name (self));
2131 priv->transform_valid = FALSE;
2133 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2135 /* if the allocation changes, so does the content box */
2136 if (priv->content != NULL)
2137 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2144 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2146 g_object_thaw_notify (obj);
2151 static void clutter_actor_real_allocate (ClutterActor *self,
2152 const ClutterActorBox *box,
2153 ClutterAllocationFlags flags);
2156 clutter_actor_maybe_layout_children (ClutterActor *self,
2157 const ClutterActorBox *allocation,
2158 ClutterAllocationFlags flags)
2160 ClutterActorPrivate *priv = self->priv;
2162 /* this is going to be a bit hard to follow, so let's put an explanation
2165 * we want ClutterActor to have a default layout manager if the actor was
2166 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2168 * we also want any subclass of ClutterActor that does not override the
2169 * ::allocate() virtual function to delegate to a layout manager.
2171 * finally, we want to allow people subclassing ClutterActor and overriding
2172 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2174 * on the other hand, we want existing actor subclasses overriding the
2175 * ::allocate() virtual function and chaining up to the parent's
2176 * implementation to continue working without allocating their children
2177 * twice, or without entering an allocation loop.
2179 * for the first two points, we check if the class of the actor is
2180 * overridding the ::allocate() virtual function; if it isn't, then we
2181 * follow through with checking whether we have children and a layout
2182 * manager, and eventually calling clutter_layout_manager_allocate().
2184 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2185 * allocation flags that we got passed, and if it is present, we continue
2186 * with the check above.
2188 * if neither of these two checks yields a positive result, we just
2189 * assume that the ::allocate() virtual function that resulted in this
2190 * function being called will also allocate the children of the actor.
2193 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2196 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2202 if (priv->n_children != 0 &&
2203 priv->layout_manager != NULL)
2205 ClutterContainer *container = CLUTTER_CONTAINER (self);
2206 ClutterAllocationFlags children_flags;
2207 ClutterActorBox children_box;
2209 /* normalize the box passed to the layout manager */
2210 children_box.x1 = children_box.y1 = 0.f;
2211 children_box.x2 = (allocation->x2 - allocation->x1);
2212 children_box.y2 = (allocation->y2 - allocation->y1);
2214 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2215 * the actor's children, since it refers only to the current
2216 * actor's allocation.
2218 children_flags = flags;
2219 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2221 CLUTTER_NOTE (LAYOUT,
2222 "Allocating %d children of %s "
2223 "at { %.2f, %.2f - %.2f x %.2f } "
2226 _clutter_actor_get_debug_name (self),
2229 (allocation->x2 - allocation->x1),
2230 (allocation->y2 - allocation->y1),
2231 G_OBJECT_TYPE_NAME (priv->layout_manager));
2233 clutter_layout_manager_allocate (priv->layout_manager,
2241 clutter_actor_real_allocate (ClutterActor *self,
2242 const ClutterActorBox *box,
2243 ClutterAllocationFlags flags)
2245 ClutterActorPrivate *priv = self->priv;
2248 g_object_freeze_notify (G_OBJECT (self));
2250 changed = clutter_actor_set_allocation_internal (self, box, flags);
2252 /* we allocate our children before we notify changes in our geometry,
2253 * so that people connecting to properties will be able to get valid
2254 * data out of the sub-tree of the scene graph that has this actor at
2257 clutter_actor_maybe_layout_children (self, box, flags);
2261 ClutterActorBox signal_box = priv->allocation;
2262 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2264 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2269 g_object_thaw_notify (G_OBJECT (self));
2273 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2274 ClutterActor *origin)
2276 /* no point in queuing a redraw on a destroyed actor */
2277 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2280 /* NB: We can't bail out early here if the actor is hidden in case
2281 * the actor bas been cloned. In this case the clone will need to
2282 * receive the signal so it can queue its own redraw.
2285 /* calls klass->queue_redraw in default handler */
2286 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2290 clutter_actor_real_queue_redraw (ClutterActor *self,
2291 ClutterActor *origin)
2293 ClutterActor *parent;
2295 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2296 _clutter_actor_get_debug_name (self),
2297 origin != NULL ? _clutter_actor_get_debug_name (origin)
2300 /* no point in queuing a redraw on a destroyed actor */
2301 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2304 /* If the queue redraw is coming from a child then the actor has
2305 become dirty and any queued effect is no longer valid */
2308 self->priv->is_dirty = TRUE;
2309 self->priv->effect_to_redraw = NULL;
2312 /* If the actor isn't visible, we still had to emit the signal
2313 * to allow for a ClutterClone, but the appearance of the parent
2314 * won't change so we don't have to propagate up the hierarchy.
2316 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2319 /* Although we could determine here that a full stage redraw
2320 * has already been queued and immediately bail out, we actually
2321 * guarantee that we will propagate a queue-redraw signal to our
2322 * parent at least once so that it's possible to implement a
2323 * container that tracks which of its children have queued a
2326 if (self->priv->propagated_one_redraw)
2328 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2329 if (stage != NULL &&
2330 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2334 self->priv->propagated_one_redraw = TRUE;
2336 /* notify parents, if they are all visible eventually we'll
2337 * queue redraw on the stage, which queues the redraw idle.
2339 parent = clutter_actor_get_parent (self);
2342 /* this will go up recursively */
2343 _clutter_actor_signal_queue_redraw (parent, origin);
2348 clutter_actor_real_queue_relayout (ClutterActor *self)
2350 ClutterActorPrivate *priv = self->priv;
2352 /* no point in queueing a redraw on a destroyed actor */
2353 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2356 priv->needs_width_request = TRUE;
2357 priv->needs_height_request = TRUE;
2358 priv->needs_allocation = TRUE;
2360 /* reset the cached size requests */
2361 memset (priv->width_requests, 0,
2362 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2363 memset (priv->height_requests, 0,
2364 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2366 /* We need to go all the way up the hierarchy */
2367 if (priv->parent != NULL)
2368 _clutter_actor_queue_only_relayout (priv->parent);
2372 * clutter_actor_apply_relative_transform_to_point:
2373 * @self: A #ClutterActor
2374 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2375 * default #ClutterStage
2376 * @point: A point as #ClutterVertex
2377 * @vertex: (out caller-allocates): The translated #ClutterVertex
2379 * Transforms @point in coordinates relative to the actor into
2380 * ancestor-relative coordinates using the relevant transform
2381 * stack (i.e. scale, rotation, etc).
2383 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2384 * this case, the coordinates returned will be the coordinates on
2385 * the stage before the projection is applied. This is different from
2386 * the behaviour of clutter_actor_apply_transform_to_point().
2391 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2392 ClutterActor *ancestor,
2393 const ClutterVertex *point,
2394 ClutterVertex *vertex)
2399 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2400 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2401 g_return_if_fail (point != NULL);
2402 g_return_if_fail (vertex != NULL);
2407 if (ancestor == NULL)
2408 ancestor = _clutter_actor_get_stage_internal (self);
2410 if (ancestor == NULL)
2416 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2417 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2421 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2422 const ClutterVertex *vertices_in,
2423 ClutterVertex *vertices_out,
2426 ClutterActor *stage;
2427 CoglMatrix modelview;
2428 CoglMatrix projection;
2431 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2433 stage = _clutter_actor_get_stage_internal (self);
2435 /* We really can't do anything meaningful in this case so don't try
2436 * to do any transform */
2440 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2441 * that gets us to stage coordinates, we want to go all the way to eye
2443 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2445 /* Fetch the projection and viewport */
2446 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2447 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2453 _clutter_util_fully_transform_vertices (&modelview,
2464 * clutter_actor_apply_transform_to_point:
2465 * @self: A #ClutterActor
2466 * @point: A point as #ClutterVertex
2467 * @vertex: (out caller-allocates): The translated #ClutterVertex
2469 * Transforms @point in coordinates relative to the actor
2470 * into screen-relative coordinates with the current actor
2471 * transformation (i.e. scale, rotation, etc)
2476 clutter_actor_apply_transform_to_point (ClutterActor *self,
2477 const ClutterVertex *point,
2478 ClutterVertex *vertex)
2480 g_return_if_fail (point != NULL);
2481 g_return_if_fail (vertex != NULL);
2482 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2486 * _clutter_actor_get_relative_transformation_matrix:
2487 * @self: The actor whose coordinate space you want to transform from.
2488 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2489 * or %NULL if you want to transform all the way to eye coordinates.
2490 * @matrix: A #CoglMatrix to store the transformation
2492 * This gets a transformation @matrix that will transform coordinates from the
2493 * coordinate space of @self into the coordinate space of @ancestor.
2495 * For example if you need a matrix that can transform the local actor
2496 * coordinates of @self into stage coordinates you would pass the actor's stage
2497 * pointer as the @ancestor.
2499 * If you pass %NULL then the transformation will take you all the way through
2500 * to eye coordinates. This can be useful if you want to extract the entire
2501 * modelview transform that Clutter applies before applying the projection
2502 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2503 * using cogl_set_modelview_matrix() for example then you would want a matrix
2504 * that transforms into eye coordinates.
2506 * <note><para>This function explicitly initializes the given @matrix. If you just
2507 * want clutter to multiply a relative transformation with an existing matrix
2508 * you can use clutter_actor_apply_relative_transformation_matrix()
2509 * instead.</para></note>
2512 /* XXX: We should consider caching the stage relative modelview along with
2513 * the actor itself */
2515 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2516 ClutterActor *ancestor,
2519 cogl_matrix_init_identity (matrix);
2521 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2524 /* Project the given @box into stage window coordinates, writing the
2525 * transformed vertices to @verts[]. */
2527 _clutter_actor_transform_and_project_box (ClutterActor *self,
2528 const ClutterActorBox *box,
2529 ClutterVertex verts[])
2531 ClutterVertex box_vertices[4];
2533 box_vertices[0].x = box->x1;
2534 box_vertices[0].y = box->y1;
2535 box_vertices[0].z = 0;
2536 box_vertices[1].x = box->x2;
2537 box_vertices[1].y = box->y1;
2538 box_vertices[1].z = 0;
2539 box_vertices[2].x = box->x1;
2540 box_vertices[2].y = box->y2;
2541 box_vertices[2].z = 0;
2542 box_vertices[3].x = box->x2;
2543 box_vertices[3].y = box->y2;
2544 box_vertices[3].z = 0;
2547 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2551 * clutter_actor_get_allocation_vertices:
2552 * @self: A #ClutterActor
2553 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2554 * against, or %NULL to use the #ClutterStage
2555 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2556 * location for an array of 4 #ClutterVertex in which to store the result
2558 * Calculates the transformed coordinates of the four corners of the
2559 * actor in the plane of @ancestor. The returned vertices relate to
2560 * the #ClutterActorBox coordinates as follows:
2562 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2563 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2564 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2565 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2568 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2569 * this case, the coordinates returned will be the coordinates on
2570 * the stage before the projection is applied. This is different from
2571 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2576 clutter_actor_get_allocation_vertices (ClutterActor *self,
2577 ClutterActor *ancestor,
2578 ClutterVertex verts[])
2580 ClutterActorPrivate *priv;
2581 ClutterActorBox box;
2582 ClutterVertex vertices[4];
2583 CoglMatrix modelview;
2585 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2586 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2588 if (ancestor == NULL)
2589 ancestor = _clutter_actor_get_stage_internal (self);
2591 /* Fallback to a NOP transform if the actor isn't parented under a
2593 if (ancestor == NULL)
2598 /* if the actor needs to be allocated we force a relayout, so that
2599 * we will have valid values to use in the transformations */
2600 if (priv->needs_allocation)
2602 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2604 _clutter_stage_maybe_relayout (stage);
2607 box.x1 = box.y1 = 0;
2608 /* The result isn't really meaningful in this case but at
2609 * least try to do something *vaguely* reasonable... */
2610 clutter_actor_get_size (self, &box.x2, &box.y2);
2614 clutter_actor_get_allocation_box (self, &box);
2616 vertices[0].x = box.x1;
2617 vertices[0].y = box.y1;
2619 vertices[1].x = box.x2;
2620 vertices[1].y = box.y1;
2622 vertices[2].x = box.x1;
2623 vertices[2].y = box.y2;
2625 vertices[3].x = box.x2;
2626 vertices[3].y = box.y2;
2629 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2632 cogl_matrix_transform_points (&modelview,
2634 sizeof (ClutterVertex),
2636 sizeof (ClutterVertex),
2642 * clutter_actor_get_abs_allocation_vertices:
2643 * @self: A #ClutterActor
2644 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2645 * of 4 #ClutterVertex where to store the result.
2647 * Calculates the transformed screen coordinates of the four corners of
2648 * the actor; the returned vertices relate to the #ClutterActorBox
2649 * coordinates as follows:
2651 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2652 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2653 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2654 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2660 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2661 ClutterVertex verts[])
2663 ClutterActorPrivate *priv;
2664 ClutterActorBox actor_space_allocation;
2666 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2670 /* if the actor needs to be allocated we force a relayout, so that
2671 * the actor allocation box will be valid for
2672 * _clutter_actor_transform_and_project_box()
2674 if (priv->needs_allocation)
2676 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2677 /* There's nothing meaningful we can do now */
2681 _clutter_stage_maybe_relayout (stage);
2684 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2685 * own coordinate space... */
2686 actor_space_allocation.x1 = 0;
2687 actor_space_allocation.y1 = 0;
2688 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2689 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2690 _clutter_actor_transform_and_project_box (self,
2691 &actor_space_allocation,
2696 clutter_actor_real_apply_transform (ClutterActor *self,
2699 ClutterActorPrivate *priv = self->priv;
2701 if (!priv->transform_valid)
2703 CoglMatrix *transform = &priv->transform;
2704 const ClutterTransformInfo *info;
2706 info = _clutter_actor_get_transform_info_or_defaults (self);
2708 cogl_matrix_init_identity (transform);
2710 cogl_matrix_translate (transform,
2711 priv->allocation.x1,
2712 priv->allocation.y1,
2716 cogl_matrix_translate (transform, 0, 0, info->depth);
2719 * because the rotation involves translations, we must scale
2720 * before applying the rotations (if we apply the scale after
2721 * the rotations, the translations included in the rotation are
2722 * not scaled and so the entire object will move on the screen
2723 * as a result of rotating it).
2725 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2727 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2728 &info->scale_center,
2729 cogl_matrix_scale (transform,
2736 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2738 cogl_matrix_rotate (transform,
2743 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2745 cogl_matrix_rotate (transform,
2750 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2752 cogl_matrix_rotate (transform,
2756 if (!clutter_anchor_coord_is_zero (&info->anchor))
2760 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2761 cogl_matrix_translate (transform, -x, -y, -z);
2764 priv->transform_valid = TRUE;
2767 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2770 /* Applies the transforms associated with this actor to the given
2773 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2776 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2780 * clutter_actor_apply_relative_transformation_matrix:
2781 * @self: The actor whose coordinate space you want to transform from.
2782 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2783 * or %NULL if you want to transform all the way to eye coordinates.
2784 * @matrix: A #CoglMatrix to apply the transformation too.
2786 * This multiplies a transform with @matrix that will transform coordinates
2787 * from the coordinate space of @self into the coordinate space of @ancestor.
2789 * For example if you need a matrix that can transform the local actor
2790 * coordinates of @self into stage coordinates you would pass the actor's stage
2791 * pointer as the @ancestor.
2793 * If you pass %NULL then the transformation will take you all the way through
2794 * to eye coordinates. This can be useful if you want to extract the entire
2795 * modelview transform that Clutter applies before applying the projection
2796 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2797 * using cogl_set_modelview_matrix() for example then you would want a matrix
2798 * that transforms into eye coordinates.
2800 * <note>This function doesn't initialize the given @matrix, it simply
2801 * multiplies the requested transformation matrix with the existing contents of
2802 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2803 * before calling this function, or you can use
2804 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2807 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2808 ClutterActor *ancestor,
2811 ClutterActor *parent;
2813 /* Note we terminate before ever calling stage->apply_transform()
2814 * since that would conceptually be relative to the underlying
2815 * window OpenGL coordinates so we'd need a special @ancestor
2816 * value to represent the fake parent of the stage. */
2817 if (self == ancestor)
2820 parent = clutter_actor_get_parent (self);
2823 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2826 _clutter_actor_apply_modelview_transform (self, matrix);
2830 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2831 ClutterPaintVolume *pv,
2833 const CoglColor *color)
2835 static CoglPipeline *outline = NULL;
2836 CoglPrimitive *prim;
2837 ClutterVertex line_ends[12 * 2];
2840 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2841 /* XXX: at some point we'll query this from the stage but we can't
2842 * do that until the osx backend uses Cogl natively. */
2843 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2845 if (outline == NULL)
2846 outline = cogl_pipeline_new (ctx);
2848 _clutter_paint_volume_complete (pv);
2850 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2853 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2854 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2855 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2856 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2861 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2862 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2863 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2864 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2866 /* Lines connecting front face to back face */
2867 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2868 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2869 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2870 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2873 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2875 (CoglVertexP3 *)line_ends);
2877 cogl_pipeline_set_color (outline, color);
2878 cogl_framebuffer_draw_primitive (fb, outline, prim);
2879 cogl_object_unref (prim);
2883 PangoLayout *layout;
2884 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2885 pango_layout_set_text (layout, label, -1);
2886 cogl_pango_render_layout (layout,
2891 g_object_unref (layout);
2896 _clutter_actor_draw_paint_volume (ClutterActor *self)
2898 ClutterPaintVolume *pv;
2901 pv = _clutter_actor_get_paint_volume_mutable (self);
2904 gfloat width, height;
2905 ClutterPaintVolume fake_pv;
2907 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2908 _clutter_paint_volume_init_static (&fake_pv, stage);
2910 clutter_actor_get_size (self, &width, &height);
2911 clutter_paint_volume_set_width (&fake_pv, width);
2912 clutter_paint_volume_set_height (&fake_pv, height);
2914 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2915 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2916 _clutter_actor_get_debug_name (self),
2919 clutter_paint_volume_free (&fake_pv);
2923 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2924 _clutter_actor_draw_paint_volume_full (self, pv,
2925 _clutter_actor_get_debug_name (self),
2931 _clutter_actor_paint_cull_result (ClutterActor *self,
2933 ClutterCullResult result)
2935 ClutterPaintVolume *pv;
2940 if (result == CLUTTER_CULL_RESULT_IN)
2941 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2942 else if (result == CLUTTER_CULL_RESULT_OUT)
2943 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2945 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2948 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2950 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2951 _clutter_actor_draw_paint_volume_full (self, pv,
2952 _clutter_actor_get_debug_name (self),
2956 PangoLayout *layout;
2958 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2959 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2960 cogl_set_source_color (&color);
2962 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2963 pango_layout_set_text (layout, label, -1);
2964 cogl_pango_render_layout (layout,
2970 g_object_unref (layout);
2974 static int clone_paint_level = 0;
2977 _clutter_actor_push_clone_paint (void)
2979 clone_paint_level++;
2983 _clutter_actor_pop_clone_paint (void)
2985 clone_paint_level--;
2989 in_clone_paint (void)
2991 return clone_paint_level > 0;
2994 /* Returns TRUE if the actor can be ignored */
2995 /* FIXME: we should return a ClutterCullResult, and
2996 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2997 * means there's no point in trying to cull descendants of the current
3000 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3002 ClutterActorPrivate *priv = self->priv;
3003 ClutterActor *stage;
3004 const ClutterPlane *stage_clip;
3006 if (!priv->last_paint_volume_valid)
3008 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3009 "->last_paint_volume_valid == FALSE",
3010 _clutter_actor_get_debug_name (self));
3014 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3017 stage = _clutter_actor_get_stage_internal (self);
3018 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3019 if (G_UNLIKELY (!stage_clip))
3021 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3022 "No stage clip set",
3023 _clutter_actor_get_debug_name (self));
3027 if (cogl_get_draw_framebuffer () !=
3028 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3030 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3031 "Current framebuffer doesn't correspond to stage",
3032 _clutter_actor_get_debug_name (self));
3037 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3042 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3044 ClutterActorPrivate *priv = self->priv;
3045 const ClutterPaintVolume *pv;
3047 if (priv->last_paint_volume_valid)
3049 clutter_paint_volume_free (&priv->last_paint_volume);
3050 priv->last_paint_volume_valid = FALSE;
3053 pv = clutter_actor_get_paint_volume (self);
3056 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3057 "Actor failed to report a paint volume",
3058 _clutter_actor_get_debug_name (self));
3062 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3064 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3065 NULL); /* eye coordinates */
3067 priv->last_paint_volume_valid = TRUE;
3070 static inline gboolean
3071 actor_has_shader_data (ClutterActor *self)
3073 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3077 _clutter_actor_get_pick_id (ClutterActor *self)
3079 if (self->priv->pick_id < 0)
3082 return self->priv->pick_id;
3085 /* This is the same as clutter_actor_add_effect except that it doesn't
3086 queue a redraw and it doesn't notify on the effect property */
3088 _clutter_actor_add_effect_internal (ClutterActor *self,
3089 ClutterEffect *effect)
3091 ClutterActorPrivate *priv = self->priv;
3093 if (priv->effects == NULL)
3095 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3096 priv->effects->actor = self;
3099 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3102 /* This is the same as clutter_actor_remove_effect except that it doesn't
3103 queue a redraw and it doesn't notify on the effect property */
3105 _clutter_actor_remove_effect_internal (ClutterActor *self,
3106 ClutterEffect *effect)
3108 ClutterActorPrivate *priv = self->priv;
3110 if (priv->effects == NULL)
3113 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3117 needs_flatten_effect (ClutterActor *self)
3119 ClutterActorPrivate *priv = self->priv;
3121 if (G_UNLIKELY (clutter_paint_debug_flags &
3122 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3125 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3127 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3129 if (clutter_actor_get_paint_opacity (self) < 255 &&
3130 clutter_actor_has_overlaps (self))
3138 add_or_remove_flatten_effect (ClutterActor *self)
3140 ClutterActorPrivate *priv = self->priv;
3142 /* Add or remove the flatten effect depending on the
3143 offscreen-redirect property. */
3144 if (needs_flatten_effect (self))
3146 if (priv->flatten_effect == NULL)
3148 ClutterActorMeta *actor_meta;
3151 priv->flatten_effect = _clutter_flatten_effect_new ();
3152 /* Keep a reference to the effect so that we can queue
3154 g_object_ref_sink (priv->flatten_effect);
3156 /* Set the priority of the effect to high so that it will
3157 always be applied to the actor first. It uses an internal
3158 priority so that it won't be visible to applications */
3159 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3160 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3161 _clutter_actor_meta_set_priority (actor_meta, priority);
3163 /* This will add the effect without queueing a redraw */
3164 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3169 if (priv->flatten_effect != NULL)
3171 /* Destroy the effect so that it will lose its fbo cache of
3173 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3174 g_object_unref (priv->flatten_effect);
3175 priv->flatten_effect = NULL;
3181 clutter_actor_real_paint (ClutterActor *actor)
3183 ClutterActorPrivate *priv = actor->priv;
3186 for (iter = priv->first_child;
3188 iter = iter->priv->next_sibling)
3190 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3191 _clutter_actor_get_debug_name (iter),
3192 _clutter_actor_get_debug_name (actor),
3193 iter->priv->allocation.x1,
3194 iter->priv->allocation.y1,
3195 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3196 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3198 clutter_actor_paint (iter);
3203 clutter_actor_paint_node (ClutterActor *actor,
3204 ClutterPaintNode *root)
3206 ClutterActorPrivate *priv = actor->priv;
3208 if (priv->bg_color_set &&
3209 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3211 ClutterPaintNode *node;
3212 ClutterColor bg_color;
3213 ClutterActorBox box;
3217 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3218 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3220 bg_color = priv->bg_color;
3221 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3222 * priv->bg_color.alpha
3225 node = clutter_color_node_new (&bg_color);
3226 clutter_paint_node_set_name (node, "backgroundColor");
3227 clutter_paint_node_add_rectangle (node, &box);
3228 clutter_paint_node_add_child (root, node);
3229 clutter_paint_node_unref (node);
3232 if (priv->content != NULL)
3233 _clutter_content_paint_content (priv->content, actor, root);
3235 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3236 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3238 if (clutter_paint_node_get_n_children (root) == 0)
3241 #ifdef CLUTTER_ENABLE_DEBUG
3242 if (CLUTTER_HAS_DEBUG (PAINT))
3244 /* dump the tree only if we have one */
3245 _clutter_paint_node_dump_tree (root);
3247 #endif /* CLUTTER_ENABLE_DEBUG */
3249 _clutter_paint_node_paint (root);
3251 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3257 * clutter_actor_paint:
3258 * @self: A #ClutterActor
3260 * Renders the actor to display.
3262 * This function should not be called directly by applications.
3263 * Call clutter_actor_queue_redraw() to queue paints, instead.
3265 * This function is context-aware, and will either cause a
3266 * regular paint or a pick paint.
3268 * This function will emit the #ClutterActor::paint signal or
3269 * the #ClutterActor::pick signal, depending on the context.
3271 * This function does not paint the actor if the actor is set to 0,
3272 * unless it is performing a pick paint.
3275 clutter_actor_paint (ClutterActor *self)
3277 ClutterActorPrivate *priv;
3278 ClutterPickMode pick_mode;
3279 gboolean clip_set = FALSE;
3280 gboolean shader_applied = FALSE;
3282 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3283 "Actor real-paint counter",
3284 "Increments each time any actor is painted",
3285 0 /* no application private data */);
3286 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3287 "Actor pick-paint counter",
3288 "Increments each time any actor is painted "
3290 0 /* no application private data */);
3292 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3294 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3299 pick_mode = _clutter_context_get_pick_mode ();
3301 if (pick_mode == CLUTTER_PICK_NONE)
3302 priv->propagated_one_redraw = FALSE;
3304 /* It's an important optimization that we consider painting of
3305 * actors with 0 opacity to be a NOP... */
3306 if (pick_mode == CLUTTER_PICK_NONE &&
3307 /* ignore top-levels, since they might be transparent */
3308 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3309 /* Use the override opacity if its been set */
3310 ((priv->opacity_override >= 0) ?
3311 priv->opacity_override : priv->opacity) == 0)
3314 /* if we aren't paintable (not in a toplevel with all
3315 * parents paintable) then do nothing.
3317 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3320 /* mark that we are in the paint process */
3321 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3325 if (priv->enable_model_view_transform)
3329 /* XXX: It could be better to cache the modelview with the actor
3330 * instead of progressively building up the transformations on
3331 * the matrix stack every time we paint. */
3332 cogl_get_modelview_matrix (&matrix);
3333 _clutter_actor_apply_modelview_transform (self, &matrix);
3335 #ifdef CLUTTER_ENABLE_DEBUG
3336 /* Catch when out-of-band transforms have been made by actors not as part
3337 * of an apply_transform vfunc... */
3338 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3340 CoglMatrix expected_matrix;
3342 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3345 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3347 GString *buf = g_string_sized_new (1024);
3348 ClutterActor *parent;
3351 while (parent != NULL)
3353 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3355 if (parent->priv->parent != NULL)
3356 g_string_append (buf, "->");
3358 parent = parent->priv->parent;
3361 g_warning ("Unexpected transform found when painting actor "
3362 "\"%s\". This will be caused by one of the actor's "
3363 "ancestors (%s) using the Cogl API directly to transform "
3364 "children instead of using ::apply_transform().",
3365 _clutter_actor_get_debug_name (self),
3368 g_string_free (buf, TRUE);
3371 #endif /* CLUTTER_ENABLE_DEBUG */
3373 cogl_set_modelview_matrix (&matrix);
3378 cogl_clip_push_rectangle (priv->clip.x,
3380 priv->clip.x + priv->clip.width,
3381 priv->clip.y + priv->clip.height);
3384 else if (priv->clip_to_allocation)
3386 gfloat width, height;
3388 width = priv->allocation.x2 - priv->allocation.x1;
3389 height = priv->allocation.y2 - priv->allocation.y1;
3391 cogl_clip_push_rectangle (0, 0, width, height);
3395 if (pick_mode == CLUTTER_PICK_NONE)
3397 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3399 /* We check whether we need to add the flatten effect before
3400 each paint so that we can avoid having a mechanism for
3401 applications to notify when the value of the
3402 has_overlaps virtual changes. */
3403 add_or_remove_flatten_effect (self);
3406 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3408 /* We save the current paint volume so that the next time the
3409 * actor queues a redraw we can constrain the redraw to just
3410 * cover the union of the new bounding box and the old.
3412 * We also fetch the current paint volume to perform culling so
3413 * we can avoid painting actors outside the current clip region.
3415 * If we are painting inside a clone, we should neither update
3416 * the paint volume or use it to cull painting, since the paint
3417 * box represents the location of the source actor on the
3420 * XXX: We are starting to do a lot of vertex transforms on
3421 * the CPU in a typical paint, so at some point we should
3422 * audit these and consider caching some things.
3424 * NB: We don't perform culling while picking at this point because
3425 * clutter-stage.c doesn't setup the clipping planes appropriately.
3427 * NB: We don't want to update the last-paint-volume during picking
3428 * because the last-paint-volume is used to determine the old screen
3429 * space location of an actor that has moved so we can know the
3430 * minimal region to redraw to clear an old view of the actor. If we
3431 * update this during picking then by the time we come around to
3432 * paint then the last-paint-volume would likely represent the new
3433 * actor position not the old.
3435 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3438 /* annoyingly gcc warns if uninitialized even though
3439 * the initialization is redundant :-( */
3440 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3442 if (G_LIKELY ((clutter_paint_debug_flags &
3443 (CLUTTER_DEBUG_DISABLE_CULLING |
3444 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3445 (CLUTTER_DEBUG_DISABLE_CULLING |
3446 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3447 _clutter_actor_update_last_paint_volume (self);
3449 success = cull_actor (self, &result);
3451 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3452 _clutter_actor_paint_cull_result (self, success, result);
3453 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3457 if (priv->effects == NULL)
3459 if (pick_mode == CLUTTER_PICK_NONE &&
3460 actor_has_shader_data (self))
3462 _clutter_actor_shader_pre_paint (self, FALSE);
3463 shader_applied = TRUE;
3466 priv->next_effect_to_paint = NULL;
3469 priv->next_effect_to_paint =
3470 _clutter_meta_group_peek_metas (priv->effects);
3472 clutter_actor_continue_paint (self);
3475 _clutter_actor_shader_post_paint (self);
3477 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3478 pick_mode == CLUTTER_PICK_NONE))
3479 _clutter_actor_draw_paint_volume (self);
3482 /* If we make it here then the actor has run through a complete
3483 paint run including all the effects so it's no longer dirty */
3484 if (pick_mode == CLUTTER_PICK_NONE)
3485 priv->is_dirty = FALSE;
3492 /* paint sequence complete */
3493 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3497 * clutter_actor_continue_paint:
3498 * @self: A #ClutterActor
3500 * Run the next stage of the paint sequence. This function should only
3501 * be called within the implementation of the ‘run’ virtual of a
3502 * #ClutterEffect. It will cause the run method of the next effect to
3503 * be applied, or it will paint the actual actor if the current effect
3504 * is the last effect in the chain.
3509 clutter_actor_continue_paint (ClutterActor *self)
3511 ClutterActorPrivate *priv;
3513 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3514 /* This should only be called from with in the ‘run’ implementation
3515 of a ClutterEffect */
3516 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3520 /* Skip any effects that are disabled */
3521 while (priv->next_effect_to_paint &&
3522 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3523 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3525 /* If this has come from the last effect then we'll just paint the
3527 if (priv->next_effect_to_paint == NULL)
3529 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3531 ClutterPaintNode *dummy;
3532 gboolean emit_paint;
3534 /* XXX - this will go away in 2.0, when we can get rid of this
3535 * stuff and switch to a pure retained render tree of PaintNodes
3536 * for the entire frame, starting from the Stage.
3538 dummy = _clutter_dummy_node_new ();
3539 clutter_paint_node_set_name (dummy, "Root");
3540 emit_paint = !clutter_actor_paint_node (self, dummy);
3541 clutter_paint_node_unref (dummy);
3543 if (emit_paint || CLUTTER_ACTOR_IS_TOPLEVEL (self))
3544 g_signal_emit (self, actor_signals[PAINT], 0);
3547 CLUTTER_NOTE (PAINT, "The actor '%s' painted using PaintNodes, "
3548 "skipping the emission of the paint signal.",
3549 _clutter_actor_get_debug_name (self));
3554 ClutterColor col = { 0, };
3556 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3558 /* Actor will then paint silhouette of itself in supplied
3559 * color. See clutter_stage_get_actor_at_pos() for where
3560 * picking is enabled.
3562 g_signal_emit (self, actor_signals[PICK], 0, &col);
3567 ClutterEffect *old_current_effect;
3568 ClutterEffectPaintFlags run_flags = 0;
3570 /* Cache the current effect so that we can put it back before
3572 old_current_effect = priv->current_effect;
3574 priv->current_effect = priv->next_effect_to_paint->data;
3575 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3577 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3581 /* If there's an effect queued with this redraw then all
3582 effects up to that one will be considered dirty. It
3583 is expected the queued effect will paint the cached
3584 image and not call clutter_actor_continue_paint again
3585 (although it should work ok if it does) */
3586 if (priv->effect_to_redraw == NULL ||
3587 priv->current_effect != priv->effect_to_redraw)
3588 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3591 _clutter_effect_paint (priv->current_effect, run_flags);
3595 /* We can't determine when an actor has been modified since
3596 its last pick so lets just assume it has always been
3598 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3600 _clutter_effect_pick (priv->current_effect, run_flags);
3603 priv->current_effect = old_current_effect;
3607 static ClutterActorTraverseVisitFlags
3608 invalidate_queue_redraw_entry (ClutterActor *self,
3612 ClutterActorPrivate *priv = self->priv;
3614 if (priv->queue_redraw_entry != NULL)
3616 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3617 priv->queue_redraw_entry = NULL;
3620 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3624 remove_child (ClutterActor *self,
3625 ClutterActor *child)
3627 ClutterActor *prev_sibling, *next_sibling;
3629 prev_sibling = child->priv->prev_sibling;
3630 next_sibling = child->priv->next_sibling;
3632 if (prev_sibling != NULL)
3633 prev_sibling->priv->next_sibling = next_sibling;
3635 if (next_sibling != NULL)
3636 next_sibling->priv->prev_sibling = prev_sibling;
3638 if (self->priv->first_child == child)
3639 self->priv->first_child = next_sibling;
3641 if (self->priv->last_child == child)
3642 self->priv->last_child = prev_sibling;
3644 child->priv->parent = NULL;
3645 child->priv->prev_sibling = NULL;
3646 child->priv->next_sibling = NULL;
3650 REMOVE_CHILD_DESTROY_META = 1 << 0,
3651 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3652 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3653 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3654 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3655 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3657 /* default flags for public API */
3658 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3659 REMOVE_CHILD_EMIT_PARENT_SET |
3660 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3661 REMOVE_CHILD_CHECK_STATE |
3662 REMOVE_CHILD_FLUSH_QUEUE |
3663 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3665 /* flags for legacy/deprecated API */
3666 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3667 REMOVE_CHILD_FLUSH_QUEUE |
3668 REMOVE_CHILD_EMIT_PARENT_SET |
3669 REMOVE_CHILD_NOTIFY_FIRST_LAST
3670 } ClutterActorRemoveChildFlags;
3673 * clutter_actor_remove_child_internal:
3674 * @self: a #ClutterActor
3675 * @child: the child of @self that has to be removed
3676 * @flags: control the removal operations
3678 * Removes @child from the list of children of @self.
3681 clutter_actor_remove_child_internal (ClutterActor *self,
3682 ClutterActor *child,
3683 ClutterActorRemoveChildFlags flags)
3685 ClutterActor *old_first, *old_last;
3686 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3687 gboolean flush_queue;
3688 gboolean notify_first_last;
3689 gboolean was_mapped;
3691 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3692 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3693 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3694 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3695 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3696 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3698 g_object_freeze_notify (G_OBJECT (self));
3701 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3705 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3707 /* we need to unrealize *before* we set parent_actor to NULL,
3708 * because in an unrealize method actors are dissociating from the
3709 * stage, which means they need to be able to
3710 * clutter_actor_get_stage().
3712 * yhis should unmap and unrealize, unless we're reparenting.
3714 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3721 /* We take this opportunity to invalidate any queue redraw entry
3722 * associated with the actor and descendants since we won't be able to
3723 * determine the appropriate stage after this.
3725 * we do this after we updated the mapped state because actors might
3726 * end up queueing redraws inside their mapped/unmapped virtual
3727 * functions, and if we invalidate the redraw entry we could end up
3728 * with an inconsistent state and weird memory corruption. see
3731 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3732 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3734 _clutter_actor_traverse (child,
3736 invalidate_queue_redraw_entry,
3741 old_first = self->priv->first_child;
3742 old_last = self->priv->last_child;
3744 remove_child (self, child);
3746 self->priv->n_children -= 1;
3748 self->priv->age += 1;
3750 /* clutter_actor_reparent() will emit ::parent-set for us */
3751 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3752 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3754 /* if the child was mapped then we need to relayout ourselves to account
3755 * for the removed child
3758 clutter_actor_queue_relayout (self);
3760 /* we need to emit the signal before dropping the reference */
3761 if (emit_actor_removed)
3762 g_signal_emit_by_name (self, "actor-removed", child);
3764 if (notify_first_last)
3766 if (old_first != self->priv->first_child)
3767 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3769 if (old_last != self->priv->last_child)
3770 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3773 g_object_thaw_notify (G_OBJECT (self));
3775 /* remove the reference we acquired in clutter_actor_add_child() */
3776 g_object_unref (child);
3779 static const ClutterTransformInfo default_transform_info = {
3780 0.0, { 0, }, /* rotation-x */
3781 0.0, { 0, }, /* rotation-y */
3782 0.0, { 0, }, /* rotation-z */
3784 1.0, 1.0, { 0, }, /* scale */
3786 { 0, }, /* anchor */
3792 * _clutter_actor_get_transform_info_or_defaults:
3793 * @self: a #ClutterActor
3795 * Retrieves the ClutterTransformInfo structure associated to an actor.
3797 * If the actor does not have a ClutterTransformInfo structure associated
3798 * to it, then the default structure will be returned.
3800 * This function should only be used for getters.
3802 * Return value: a const pointer to the ClutterTransformInfo structure
3804 const ClutterTransformInfo *
3805 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3807 ClutterTransformInfo *info;
3809 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3813 return &default_transform_info;
3817 clutter_transform_info_free (gpointer data)
3820 g_slice_free (ClutterTransformInfo, data);
3824 * _clutter_actor_get_transform_info:
3825 * @self: a #ClutterActor
3827 * Retrieves a pointer to the ClutterTransformInfo structure.
3829 * If the actor does not have a ClutterTransformInfo associated to it, one
3830 * will be created and initialized to the default values.
3832 * This function should be used for setters.
3834 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3837 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3840 ClutterTransformInfo *
3841 _clutter_actor_get_transform_info (ClutterActor *self)
3843 ClutterTransformInfo *info;
3845 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3848 info = g_slice_new (ClutterTransformInfo);
3850 *info = default_transform_info;
3852 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3854 clutter_transform_info_free);
3861 * clutter_actor_set_rotation_angle_internal:
3862 * @self: a #ClutterActor
3863 * @axis: the axis of the angle to change
3864 * @angle: the angle of rotation
3866 * Sets the rotation angle on the given axis without affecting the
3867 * rotation center point.
3870 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3871 ClutterRotateAxis axis,
3874 GObject *obj = G_OBJECT (self);
3875 ClutterTransformInfo *info;
3877 info = _clutter_actor_get_transform_info (self);
3879 g_object_freeze_notify (obj);
3883 case CLUTTER_X_AXIS:
3884 info->rx_angle = angle;
3885 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3888 case CLUTTER_Y_AXIS:
3889 info->ry_angle = angle;
3890 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3893 case CLUTTER_Z_AXIS:
3894 info->rz_angle = angle;
3895 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3899 self->priv->transform_valid = FALSE;
3901 g_object_thaw_notify (obj);
3903 clutter_actor_queue_redraw (self);
3907 clutter_actor_set_rotation_angle (ClutterActor *self,
3908 ClutterRotateAxis axis,
3911 ClutterTransformInfo *info;
3913 info = _clutter_actor_get_transform_info (self);
3915 if (clutter_actor_get_easing_duration (self) != 0)
3917 ClutterTransition *transition;
3918 GParamSpec *pspec = NULL;
3919 double *cur_angle_p = NULL;
3923 case CLUTTER_X_AXIS:
3924 cur_angle_p = &info->rx_angle;
3925 pspec = obj_props[PROP_ROTATION_ANGLE_X];
3928 case CLUTTER_Y_AXIS:
3929 cur_angle_p = &info->ry_angle;
3930 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3933 case CLUTTER_Z_AXIS:
3934 cur_angle_p = &info->rz_angle;
3935 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3939 g_assert (pspec != NULL);
3940 g_assert (cur_angle_p != NULL);
3942 transition = _clutter_actor_get_transition (self, pspec);
3943 if (transition == NULL)
3945 transition = _clutter_actor_create_transition (self, pspec,
3948 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3951 _clutter_actor_update_transition (self, pspec, angle);
3953 self->priv->transform_valid = FALSE;
3954 clutter_actor_queue_redraw (self);
3957 clutter_actor_set_rotation_angle_internal (self, axis, angle);
3961 * clutter_actor_set_rotation_center_internal:
3962 * @self: a #ClutterActor
3963 * @axis: the axis of the center to change
3964 * @center: the coordinates of the rotation center
3966 * Sets the rotation center on the given axis without affecting the
3970 clutter_actor_set_rotation_center_internal (ClutterActor *self,
3971 ClutterRotateAxis axis,
3972 const ClutterVertex *center)
3974 GObject *obj = G_OBJECT (self);
3975 ClutterTransformInfo *info;
3976 ClutterVertex v = { 0, 0, 0 };
3978 info = _clutter_actor_get_transform_info (self);
3983 g_object_freeze_notify (obj);
3987 case CLUTTER_X_AXIS:
3988 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3989 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3992 case CLUTTER_Y_AXIS:
3993 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3994 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3997 case CLUTTER_Z_AXIS:
3998 /* if the previously set rotation center was fractional, then
3999 * setting explicit coordinates will have to notify the
4000 * :rotation-center-z-gravity property as well
4002 if (info->rz_center.is_fractional)
4003 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4005 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4006 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4010 self->priv->transform_valid = FALSE;
4012 g_object_thaw_notify (obj);
4014 clutter_actor_queue_redraw (self);
4018 clutter_actor_animate_scale_factor (ClutterActor *self,
4023 ClutterTransition *transition;
4025 transition = _clutter_actor_get_transition (self, pspec);
4026 if (transition == NULL)
4028 transition = _clutter_actor_create_transition (self, pspec,
4031 clutter_timeline_start (CLUTTER_TIMELINE (transition));
4034 _clutter_actor_update_transition (self, pspec, new_factor);
4037 self->priv->transform_valid = FALSE;
4038 clutter_actor_queue_redraw (self);
4042 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4046 GObject *obj = G_OBJECT (self);
4047 ClutterTransformInfo *info;
4049 info = _clutter_actor_get_transform_info (self);
4051 if (pspec == obj_props[PROP_SCALE_X])
4052 info->scale_x = factor;
4054 info->scale_y = factor;
4056 self->priv->transform_valid = FALSE;
4057 clutter_actor_queue_redraw (self);
4058 g_object_notify_by_pspec (obj, pspec);
4062 clutter_actor_set_scale_factor (ClutterActor *self,
4063 ClutterRotateAxis axis,
4066 GObject *obj = G_OBJECT (self);
4067 ClutterTransformInfo *info;
4070 info = _clutter_actor_get_transform_info (self);
4072 g_object_freeze_notify (obj);
4076 case CLUTTER_X_AXIS:
4077 pspec = obj_props[PROP_SCALE_X];
4079 if (clutter_actor_get_easing_duration (self) != 0)
4080 clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4082 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4085 case CLUTTER_Y_AXIS:
4086 pspec = obj_props[PROP_SCALE_Y];
4088 if (clutter_actor_get_easing_duration (self) != 0)
4089 clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4091 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4095 g_assert_not_reached ();
4098 g_object_thaw_notify (obj);
4102 clutter_actor_set_scale_center (ClutterActor *self,
4103 ClutterRotateAxis axis,
4106 GObject *obj = G_OBJECT (self);
4107 ClutterTransformInfo *info;
4108 gfloat center_x, center_y;
4110 info = _clutter_actor_get_transform_info (self);
4112 g_object_freeze_notify (obj);
4114 /* get the current scale center coordinates */
4115 clutter_anchor_coord_get_units (self, &info->scale_center,
4120 /* we need to notify this too, because setting explicit coordinates will
4121 * change the gravity as a side effect
4123 if (info->scale_center.is_fractional)
4124 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4128 case CLUTTER_X_AXIS:
4129 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4130 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4133 case CLUTTER_Y_AXIS:
4134 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4135 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4139 g_assert_not_reached ();
4142 self->priv->transform_valid = FALSE;
4144 clutter_actor_queue_redraw (self);
4146 g_object_thaw_notify (obj);
4150 clutter_actor_set_anchor_coord (ClutterActor *self,
4151 ClutterRotateAxis axis,
4154 GObject *obj = G_OBJECT (self);
4155 ClutterTransformInfo *info;
4156 gfloat anchor_x, anchor_y;
4158 info = _clutter_actor_get_transform_info (self);
4160 g_object_freeze_notify (obj);
4162 clutter_anchor_coord_get_units (self, &info->anchor,
4167 if (info->anchor.is_fractional)
4168 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4172 case CLUTTER_X_AXIS:
4173 clutter_anchor_coord_set_units (&info->anchor,
4177 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4180 case CLUTTER_Y_AXIS:
4181 clutter_anchor_coord_set_units (&info->anchor,
4185 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4189 g_assert_not_reached ();
4192 self->priv->transform_valid = FALSE;
4194 clutter_actor_queue_redraw (self);
4196 g_object_thaw_notify (obj);
4200 clutter_actor_set_property (GObject *object,
4202 const GValue *value,
4205 ClutterActor *actor = CLUTTER_ACTOR (object);
4206 ClutterActorPrivate *priv = actor->priv;
4211 clutter_actor_set_x (actor, g_value_get_float (value));
4215 clutter_actor_set_y (actor, g_value_get_float (value));
4219 clutter_actor_set_width (actor, g_value_get_float (value));
4223 clutter_actor_set_height (actor, g_value_get_float (value));
4227 clutter_actor_set_x (actor, g_value_get_float (value));
4231 clutter_actor_set_y (actor, g_value_get_float (value));
4234 case PROP_FIXED_POSITION_SET:
4235 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4238 case PROP_MIN_WIDTH:
4239 clutter_actor_set_min_width (actor, g_value_get_float (value));
4242 case PROP_MIN_HEIGHT:
4243 clutter_actor_set_min_height (actor, g_value_get_float (value));
4246 case PROP_NATURAL_WIDTH:
4247 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4250 case PROP_NATURAL_HEIGHT:
4251 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4254 case PROP_MIN_WIDTH_SET:
4255 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4258 case PROP_MIN_HEIGHT_SET:
4259 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4262 case PROP_NATURAL_WIDTH_SET:
4263 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4266 case PROP_NATURAL_HEIGHT_SET:
4267 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4270 case PROP_REQUEST_MODE:
4271 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4275 clutter_actor_set_depth (actor, g_value_get_float (value));
4279 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4282 case PROP_OFFSCREEN_REDIRECT:
4283 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4287 clutter_actor_set_name (actor, g_value_get_string (value));
4291 if (g_value_get_boolean (value) == TRUE)
4292 clutter_actor_show (actor);
4294 clutter_actor_hide (actor);
4298 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4299 g_value_get_double (value));
4303 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4304 g_value_get_double (value));
4307 case PROP_SCALE_CENTER_X:
4308 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4309 g_value_get_float (value));
4312 case PROP_SCALE_CENTER_Y:
4313 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4314 g_value_get_float (value));
4317 case PROP_SCALE_GRAVITY:
4319 const ClutterTransformInfo *info;
4320 ClutterGravity gravity;
4322 info = _clutter_actor_get_transform_info_or_defaults (actor);
4323 gravity = g_value_get_enum (value);
4325 clutter_actor_set_scale_with_gravity (actor,
4334 const ClutterGeometry *geom = g_value_get_boxed (value);
4336 clutter_actor_set_clip (actor,
4338 geom->width, geom->height);
4342 case PROP_CLIP_TO_ALLOCATION:
4343 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4347 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4350 case PROP_ROTATION_ANGLE_X:
4351 clutter_actor_set_rotation_angle (actor,
4353 g_value_get_double (value));
4356 case PROP_ROTATION_ANGLE_Y:
4357 clutter_actor_set_rotation_angle (actor,
4359 g_value_get_double (value));
4362 case PROP_ROTATION_ANGLE_Z:
4363 clutter_actor_set_rotation_angle (actor,
4365 g_value_get_double (value));
4368 case PROP_ROTATION_CENTER_X:
4369 clutter_actor_set_rotation_center_internal (actor,
4371 g_value_get_boxed (value));
4374 case PROP_ROTATION_CENTER_Y:
4375 clutter_actor_set_rotation_center_internal (actor,
4377 g_value_get_boxed (value));
4380 case PROP_ROTATION_CENTER_Z:
4381 clutter_actor_set_rotation_center_internal (actor,
4383 g_value_get_boxed (value));
4386 case PROP_ROTATION_CENTER_Z_GRAVITY:
4388 const ClutterTransformInfo *info;
4390 info = _clutter_actor_get_transform_info_or_defaults (actor);
4391 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4392 g_value_get_enum (value));
4397 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4398 g_value_get_float (value));
4402 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4403 g_value_get_float (value));
4406 case PROP_ANCHOR_GRAVITY:
4407 clutter_actor_set_anchor_point_from_gravity (actor,
4408 g_value_get_enum (value));
4411 case PROP_SHOW_ON_SET_PARENT:
4412 priv->show_on_set_parent = g_value_get_boolean (value);
4415 case PROP_TEXT_DIRECTION:
4416 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4420 clutter_actor_add_action (actor, g_value_get_object (value));
4423 case PROP_CONSTRAINTS:
4424 clutter_actor_add_constraint (actor, g_value_get_object (value));
4428 clutter_actor_add_effect (actor, g_value_get_object (value));
4431 case PROP_LAYOUT_MANAGER:
4432 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4436 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4440 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4443 case PROP_MARGIN_TOP:
4444 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4447 case PROP_MARGIN_BOTTOM:
4448 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4451 case PROP_MARGIN_LEFT:
4452 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4455 case PROP_MARGIN_RIGHT:
4456 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4459 case PROP_BACKGROUND_COLOR:
4460 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4464 clutter_actor_set_content (actor, g_value_get_object (value));
4467 case PROP_CONTENT_GRAVITY:
4468 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4472 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4478 clutter_actor_get_property (GObject *object,
4483 ClutterActor *actor = CLUTTER_ACTOR (object);
4484 ClutterActorPrivate *priv = actor->priv;
4489 g_value_set_float (value, clutter_actor_get_x (actor));
4493 g_value_set_float (value, clutter_actor_get_y (actor));
4497 g_value_set_float (value, clutter_actor_get_width (actor));
4501 g_value_set_float (value, clutter_actor_get_height (actor));
4506 const ClutterLayoutInfo *info;
4508 info = _clutter_actor_get_layout_info_or_defaults (actor);
4509 g_value_set_float (value, info->fixed_x);
4515 const ClutterLayoutInfo *info;
4517 info = _clutter_actor_get_layout_info_or_defaults (actor);
4518 g_value_set_float (value, info->fixed_y);
4522 case PROP_FIXED_POSITION_SET:
4523 g_value_set_boolean (value, priv->position_set);
4526 case PROP_MIN_WIDTH:
4528 const ClutterLayoutInfo *info;
4530 info = _clutter_actor_get_layout_info_or_defaults (actor);
4531 g_value_set_float (value, info->min_width);
4535 case PROP_MIN_HEIGHT:
4537 const ClutterLayoutInfo *info;
4539 info = _clutter_actor_get_layout_info_or_defaults (actor);
4540 g_value_set_float (value, info->min_height);
4544 case PROP_NATURAL_WIDTH:
4546 const ClutterLayoutInfo *info;
4548 info = _clutter_actor_get_layout_info_or_defaults (actor);
4549 g_value_set_float (value, info->natural_width);
4553 case PROP_NATURAL_HEIGHT:
4555 const ClutterLayoutInfo *info;
4557 info = _clutter_actor_get_layout_info_or_defaults (actor);
4558 g_value_set_float (value, info->natural_height);
4562 case PROP_MIN_WIDTH_SET:
4563 g_value_set_boolean (value, priv->min_width_set);
4566 case PROP_MIN_HEIGHT_SET:
4567 g_value_set_boolean (value, priv->min_height_set);
4570 case PROP_NATURAL_WIDTH_SET:
4571 g_value_set_boolean (value, priv->natural_width_set);
4574 case PROP_NATURAL_HEIGHT_SET:
4575 g_value_set_boolean (value, priv->natural_height_set);
4578 case PROP_REQUEST_MODE:
4579 g_value_set_enum (value, priv->request_mode);
4582 case PROP_ALLOCATION:
4583 g_value_set_boxed (value, &priv->allocation);
4587 g_value_set_float (value, clutter_actor_get_depth (actor));
4591 g_value_set_uint (value, priv->opacity);
4594 case PROP_OFFSCREEN_REDIRECT:
4595 g_value_set_enum (value, priv->offscreen_redirect);
4599 g_value_set_string (value, priv->name);
4603 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4607 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4611 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4615 g_value_set_boolean (value, priv->has_clip);
4620 ClutterGeometry clip;
4622 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4623 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4624 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4625 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4627 g_value_set_boxed (value, &clip);
4631 case PROP_CLIP_TO_ALLOCATION:
4632 g_value_set_boolean (value, priv->clip_to_allocation);
4637 const ClutterTransformInfo *info;
4639 info = _clutter_actor_get_transform_info_or_defaults (actor);
4640 g_value_set_double (value, info->scale_x);
4646 const ClutterTransformInfo *info;
4648 info = _clutter_actor_get_transform_info_or_defaults (actor);
4649 g_value_set_double (value, info->scale_y);
4653 case PROP_SCALE_CENTER_X:
4657 clutter_actor_get_scale_center (actor, ¢er, NULL);
4659 g_value_set_float (value, center);
4663 case PROP_SCALE_CENTER_Y:
4667 clutter_actor_get_scale_center (actor, NULL, ¢er);
4669 g_value_set_float (value, center);
4673 case PROP_SCALE_GRAVITY:
4674 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4678 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4681 case PROP_ROTATION_ANGLE_X:
4683 const ClutterTransformInfo *info;
4685 info = _clutter_actor_get_transform_info_or_defaults (actor);
4686 g_value_set_double (value, info->rx_angle);
4690 case PROP_ROTATION_ANGLE_Y:
4692 const ClutterTransformInfo *info;
4694 info = _clutter_actor_get_transform_info_or_defaults (actor);
4695 g_value_set_double (value, info->ry_angle);
4699 case PROP_ROTATION_ANGLE_Z:
4701 const ClutterTransformInfo *info;
4703 info = _clutter_actor_get_transform_info_or_defaults (actor);
4704 g_value_set_double (value, info->rz_angle);
4708 case PROP_ROTATION_CENTER_X:
4710 ClutterVertex center;
4712 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4717 g_value_set_boxed (value, ¢er);
4721 case PROP_ROTATION_CENTER_Y:
4723 ClutterVertex center;
4725 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4730 g_value_set_boxed (value, ¢er);
4734 case PROP_ROTATION_CENTER_Z:
4736 ClutterVertex center;
4738 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4743 g_value_set_boxed (value, ¢er);
4747 case PROP_ROTATION_CENTER_Z_GRAVITY:
4748 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4753 const ClutterTransformInfo *info;
4756 info = _clutter_actor_get_transform_info_or_defaults (actor);
4757 clutter_anchor_coord_get_units (actor, &info->anchor,
4761 g_value_set_float (value, anchor_x);
4767 const ClutterTransformInfo *info;
4770 info = _clutter_actor_get_transform_info_or_defaults (actor);
4771 clutter_anchor_coord_get_units (actor, &info->anchor,
4775 g_value_set_float (value, anchor_y);
4779 case PROP_ANCHOR_GRAVITY:
4780 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4783 case PROP_SHOW_ON_SET_PARENT:
4784 g_value_set_boolean (value, priv->show_on_set_parent);
4787 case PROP_TEXT_DIRECTION:
4788 g_value_set_enum (value, priv->text_direction);
4791 case PROP_HAS_POINTER:
4792 g_value_set_boolean (value, priv->has_pointer);
4795 case PROP_LAYOUT_MANAGER:
4796 g_value_set_object (value, priv->layout_manager);
4801 const ClutterLayoutInfo *info;
4803 info = _clutter_actor_get_layout_info_or_defaults (actor);
4804 g_value_set_enum (value, info->x_align);
4810 const ClutterLayoutInfo *info;
4812 info = _clutter_actor_get_layout_info_or_defaults (actor);
4813 g_value_set_enum (value, info->y_align);
4817 case PROP_MARGIN_TOP:
4819 const ClutterLayoutInfo *info;
4821 info = _clutter_actor_get_layout_info_or_defaults (actor);
4822 g_value_set_float (value, info->margin.top);
4826 case PROP_MARGIN_BOTTOM:
4828 const ClutterLayoutInfo *info;
4830 info = _clutter_actor_get_layout_info_or_defaults (actor);
4831 g_value_set_float (value, info->margin.bottom);
4835 case PROP_MARGIN_LEFT:
4837 const ClutterLayoutInfo *info;
4839 info = _clutter_actor_get_layout_info_or_defaults (actor);
4840 g_value_set_float (value, info->margin.left);
4844 case PROP_MARGIN_RIGHT:
4846 const ClutterLayoutInfo *info;
4848 info = _clutter_actor_get_layout_info_or_defaults (actor);
4849 g_value_set_float (value, info->margin.right);
4853 case PROP_BACKGROUND_COLOR_SET:
4854 g_value_set_boolean (value, priv->bg_color_set);
4857 case PROP_BACKGROUND_COLOR:
4858 g_value_set_boxed (value, &priv->bg_color);
4861 case PROP_FIRST_CHILD:
4862 g_value_set_object (value, priv->first_child);
4865 case PROP_LAST_CHILD:
4866 g_value_set_object (value, priv->last_child);
4870 g_value_set_object (value, priv->content);
4873 case PROP_CONTENT_GRAVITY:
4874 g_value_set_enum (value, priv->content_gravity);
4877 case PROP_CONTENT_BOX:
4879 ClutterActorBox box = { 0, };
4881 clutter_actor_get_content_box (actor, &box);
4882 g_value_set_boxed (value, &box);
4887 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4893 clutter_actor_dispose (GObject *object)
4895 ClutterActor *self = CLUTTER_ACTOR (object);
4896 ClutterActorPrivate *priv = self->priv;
4898 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4900 g_type_name (G_OBJECT_TYPE (self)),
4903 g_signal_emit (self, actor_signals[DESTROY], 0);
4905 /* avoid recursing when called from clutter_actor_destroy() */
4906 if (priv->parent != NULL)
4908 ClutterActor *parent = priv->parent;
4910 /* go through the Container implementation unless this
4911 * is an internal child and has been marked as such.
4913 * removing the actor from its parent will reset the
4914 * realized and mapped states.
4916 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4917 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4919 clutter_actor_remove_child_internal (parent, self,
4920 REMOVE_CHILD_LEGACY_FLAGS);
4923 /* parent must be gone at this point */
4924 g_assert (priv->parent == NULL);
4926 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4928 /* can't be mapped or realized with no parent */
4929 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4930 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4933 g_clear_object (&priv->pango_context);
4934 g_clear_object (&priv->actions);
4935 g_clear_object (&priv->constraints);
4936 g_clear_object (&priv->effects);
4937 g_clear_object (&priv->flatten_effect);
4939 if (priv->layout_manager != NULL)
4941 clutter_layout_manager_set_container (priv->layout_manager, NULL);
4942 g_clear_object (&priv->layout_manager);
4945 if (priv->content != NULL)
4947 _clutter_content_detached (priv->content, self);
4948 g_clear_object (&priv->content);
4951 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4955 clutter_actor_finalize (GObject *object)
4957 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4959 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4960 priv->name != NULL ? priv->name : "<none>",
4962 g_type_name (G_OBJECT_TYPE (object)));
4964 _clutter_context_release_id (priv->id);
4966 g_free (priv->name);
4968 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4973 * clutter_actor_get_accessible:
4974 * @self: a #ClutterActor
4976 * Returns the accessible object that describes the actor to an
4977 * assistive technology.
4979 * If no class-specific #AtkObject implementation is available for the
4980 * actor instance in question, it will inherit an #AtkObject
4981 * implementation from the first ancestor class for which such an
4982 * implementation is defined.
4984 * The documentation of the <ulink
4985 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4986 * library contains more information about accessible objects and
4989 * Returns: (transfer none): the #AtkObject associated with @actor
4992 clutter_actor_get_accessible (ClutterActor *self)
4994 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4996 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5000 clutter_actor_real_get_accessible (ClutterActor *actor)
5002 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5006 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5008 AtkObject *accessible;
5010 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5011 if (accessible != NULL)
5012 g_object_ref (accessible);
5018 atk_implementor_iface_init (AtkImplementorIface *iface)
5020 iface->ref_accessible = _clutter_actor_ref_accessible;
5024 clutter_actor_update_default_paint_volume (ClutterActor *self,
5025 ClutterPaintVolume *volume)
5027 ClutterActorPrivate *priv = self->priv;
5028 gboolean res = FALSE;
5030 /* we start from the allocation */
5031 clutter_paint_volume_set_width (volume,
5032 priv->allocation.x2 - priv->allocation.x1);
5033 clutter_paint_volume_set_height (volume,
5034 priv->allocation.y2 - priv->allocation.y1);
5036 /* if the actor has a clip set then we have a pretty definite
5037 * size for the paint volume: the actor cannot possibly paint
5038 * outside the clip region.
5040 if (priv->clip_to_allocation)
5042 /* the allocation has already been set, so we just flip the
5049 ClutterActor *child;
5051 if (priv->has_clip &&
5052 priv->clip.width >= 0 &&
5053 priv->clip.height >= 0)
5055 ClutterVertex origin;
5057 origin.x = priv->clip.x;
5058 origin.y = priv->clip.y;
5061 clutter_paint_volume_set_origin (volume, &origin);
5062 clutter_paint_volume_set_width (volume, priv->clip.width);
5063 clutter_paint_volume_set_height (volume, priv->clip.height);
5068 /* if we don't have children we just bail out here... */
5069 if (priv->n_children == 0)
5072 /* ...but if we have children then we ask for their paint volume in
5073 * our coordinates. if any of our children replies that it doesn't
5074 * have a paint volume, we bail out
5076 for (child = priv->first_child;
5078 child = child->priv->next_sibling)
5080 const ClutterPaintVolume *child_volume;
5082 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5083 if (child_volume == NULL)
5089 clutter_paint_volume_union (volume, child_volume);
5099 clutter_actor_real_get_paint_volume (ClutterActor *self,
5100 ClutterPaintVolume *volume)
5102 ClutterActorClass *klass;
5105 klass = CLUTTER_ACTOR_GET_CLASS (self);
5107 /* XXX - this thoroughly sucks, but we don't want to penalize users
5108 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5109 * redraw. This should go away in 2.0.
5111 if (klass->paint == clutter_actor_real_paint &&
5112 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5118 /* this is the default return value: we cannot know if a class
5119 * is going to paint outside its allocation, so we take the
5120 * conservative approach.
5125 if (clutter_actor_update_default_paint_volume (self, volume))
5132 * clutter_actor_get_default_paint_volume:
5133 * @self: a #ClutterActor
5135 * Retrieves the default paint volume for @self.
5137 * This function provides the same #ClutterPaintVolume that would be
5138 * computed by the default implementation inside #ClutterActor of the
5139 * #ClutterActorClass.get_paint_volume() virtual function.
5141 * This function should only be used by #ClutterActor subclasses that
5142 * cannot chain up to the parent implementation when computing their
5145 * Return value: (transfer none): a pointer to the default
5146 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5147 * the actor could not compute a valid paint volume. The returned value
5148 * is not guaranteed to be stable across multiple frames, so if you
5149 * want to retain it, you will need to copy it using
5150 * clutter_paint_volume_copy().
5154 const ClutterPaintVolume *
5155 clutter_actor_get_default_paint_volume (ClutterActor *self)
5157 ClutterPaintVolume volume;
5158 ClutterPaintVolume *res;
5160 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5163 _clutter_paint_volume_init_static (&volume, self);
5164 if (clutter_actor_update_default_paint_volume (self, &volume))
5166 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5170 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5171 _clutter_paint_volume_copy_static (&volume, res);
5175 clutter_paint_volume_free (&volume);
5181 clutter_actor_real_has_overlaps (ClutterActor *self)
5183 /* By default we'll assume that all actors need an offscreen redirect to get
5184 * the correct opacity. Actors such as ClutterTexture that would never need
5185 * an offscreen redirect can override this to return FALSE. */
5190 clutter_actor_real_destroy (ClutterActor *actor)
5192 ClutterActorIter iter;
5194 clutter_actor_iter_init (&iter, actor);
5195 while (clutter_actor_iter_next (&iter, NULL))
5196 clutter_actor_iter_destroy (&iter);
5200 clutter_actor_constructor (GType gtype,
5202 GObjectConstructParam *props)
5204 GObjectClass *gobject_class;
5208 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5209 retval = gobject_class->constructor (gtype, n_props, props);
5210 self = CLUTTER_ACTOR (retval);
5212 if (self->priv->layout_manager == NULL)
5214 ClutterLayoutManager *default_layout;
5216 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5218 default_layout = clutter_fixed_layout_new ();
5219 clutter_actor_set_layout_manager (self, default_layout);
5226 clutter_actor_class_init (ClutterActorClass *klass)
5228 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5230 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5231 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5232 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5233 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5235 object_class->constructor = clutter_actor_constructor;
5236 object_class->set_property = clutter_actor_set_property;
5237 object_class->get_property = clutter_actor_get_property;
5238 object_class->dispose = clutter_actor_dispose;
5239 object_class->finalize = clutter_actor_finalize;
5241 klass->show = clutter_actor_real_show;
5242 klass->show_all = clutter_actor_show;
5243 klass->hide = clutter_actor_real_hide;
5244 klass->hide_all = clutter_actor_hide;
5245 klass->map = clutter_actor_real_map;
5246 klass->unmap = clutter_actor_real_unmap;
5247 klass->unrealize = clutter_actor_real_unrealize;
5248 klass->pick = clutter_actor_real_pick;
5249 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5250 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5251 klass->allocate = clutter_actor_real_allocate;
5252 klass->queue_redraw = clutter_actor_real_queue_redraw;
5253 klass->queue_relayout = clutter_actor_real_queue_relayout;
5254 klass->apply_transform = clutter_actor_real_apply_transform;
5255 klass->get_accessible = clutter_actor_real_get_accessible;
5256 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5257 klass->has_overlaps = clutter_actor_real_has_overlaps;
5258 klass->paint = clutter_actor_real_paint;
5259 klass->destroy = clutter_actor_real_destroy;
5261 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5266 * X coordinate of the actor in pixels. If written, forces a fixed
5267 * position for the actor. If read, returns the fixed position if any,
5268 * otherwise the allocation if available, otherwise 0.
5270 * The #ClutterActor:x property is animatable.
5273 g_param_spec_float ("x",
5275 P_("X coordinate of the actor"),
5276 -G_MAXFLOAT, G_MAXFLOAT,
5279 G_PARAM_STATIC_STRINGS |
5280 CLUTTER_PARAM_ANIMATABLE);
5285 * Y coordinate of the actor in pixels. If written, forces a fixed
5286 * position for the actor. If read, returns the fixed position if
5287 * any, otherwise the allocation if available, otherwise 0.
5289 * The #ClutterActor:y property is animatable.
5292 g_param_spec_float ("y",
5294 P_("Y coordinate of the actor"),
5295 -G_MAXFLOAT, G_MAXFLOAT,
5298 G_PARAM_STATIC_STRINGS |
5299 CLUTTER_PARAM_ANIMATABLE);
5302 * ClutterActor:width:
5304 * Width of the actor (in pixels). If written, forces the minimum and
5305 * natural size request of the actor to the given width. If read, returns
5306 * the allocated width if available, otherwise the width request.
5308 * The #ClutterActor:width property is animatable.
5310 obj_props[PROP_WIDTH] =
5311 g_param_spec_float ("width",
5313 P_("Width of the actor"),
5317 G_PARAM_STATIC_STRINGS |
5318 CLUTTER_PARAM_ANIMATABLE);
5321 * ClutterActor:height:
5323 * Height of the actor (in pixels). If written, forces the minimum and
5324 * natural size request of the actor to the given height. If read, returns
5325 * the allocated height if available, otherwise the height request.
5327 * The #ClutterActor:height property is animatable.
5329 obj_props[PROP_HEIGHT] =
5330 g_param_spec_float ("height",
5332 P_("Height of the actor"),
5336 G_PARAM_STATIC_STRINGS |
5337 CLUTTER_PARAM_ANIMATABLE);
5340 * ClutterActor:fixed-x:
5342 * The fixed X position of the actor in pixels.
5344 * Writing this property sets #ClutterActor:fixed-position-set
5345 * property as well, as a side effect
5349 obj_props[PROP_FIXED_X] =
5350 g_param_spec_float ("fixed-x",
5352 P_("Forced X position of the actor"),
5353 -G_MAXFLOAT, G_MAXFLOAT,
5355 CLUTTER_PARAM_READWRITE);
5358 * ClutterActor:fixed-y:
5360 * The fixed Y position of the actor in pixels.
5362 * Writing this property sets the #ClutterActor:fixed-position-set
5363 * property as well, as a side effect
5367 obj_props[PROP_FIXED_Y] =
5368 g_param_spec_float ("fixed-y",
5370 P_("Forced Y position of the actor"),
5371 -G_MAXFLOAT, G_MAXFLOAT,
5373 CLUTTER_PARAM_READWRITE);
5376 * ClutterActor:fixed-position-set:
5378 * This flag controls whether the #ClutterActor:fixed-x and
5379 * #ClutterActor:fixed-y properties are used
5383 obj_props[PROP_FIXED_POSITION_SET] =
5384 g_param_spec_boolean ("fixed-position-set",
5385 P_("Fixed position set"),
5386 P_("Whether to use fixed positioning for the actor"),
5388 CLUTTER_PARAM_READWRITE);
5391 * ClutterActor:min-width:
5393 * A forced minimum width request for the actor, in pixels
5395 * Writing this property sets the #ClutterActor:min-width-set property
5396 * as well, as a side effect.
5398 *This property overrides the usual width request of the actor.
5402 obj_props[PROP_MIN_WIDTH] =
5403 g_param_spec_float ("min-width",
5405 P_("Forced minimum width request for the actor"),
5408 CLUTTER_PARAM_READWRITE);
5411 * ClutterActor:min-height:
5413 * A forced minimum height request for the actor, in pixels
5415 * Writing this property sets the #ClutterActor:min-height-set property
5416 * as well, as a side effect. This property overrides the usual height
5417 * request of the actor.
5421 obj_props[PROP_MIN_HEIGHT] =
5422 g_param_spec_float ("min-height",
5424 P_("Forced minimum height request for the actor"),
5427 CLUTTER_PARAM_READWRITE);
5430 * ClutterActor:natural-width:
5432 * A forced natural width request for the actor, in pixels
5434 * Writing this property sets the #ClutterActor:natural-width-set
5435 * property as well, as a side effect. This property overrides the
5436 * usual width request of the actor
5440 obj_props[PROP_NATURAL_WIDTH] =
5441 g_param_spec_float ("natural-width",
5442 P_("Natural Width"),
5443 P_("Forced natural width request for the actor"),
5446 CLUTTER_PARAM_READWRITE);
5449 * ClutterActor:natural-height:
5451 * A forced natural height request for the actor, in pixels
5453 * Writing this property sets the #ClutterActor:natural-height-set
5454 * property as well, as a side effect. This property overrides the
5455 * usual height request of the actor
5459 obj_props[PROP_NATURAL_HEIGHT] =
5460 g_param_spec_float ("natural-height",
5461 P_("Natural Height"),
5462 P_("Forced natural height request for the actor"),
5465 CLUTTER_PARAM_READWRITE);
5468 * ClutterActor:min-width-set:
5470 * This flag controls whether the #ClutterActor:min-width property
5475 obj_props[PROP_MIN_WIDTH_SET] =
5476 g_param_spec_boolean ("min-width-set",
5477 P_("Minimum width set"),
5478 P_("Whether to use the min-width property"),
5480 CLUTTER_PARAM_READWRITE);
5483 * ClutterActor:min-height-set:
5485 * This flag controls whether the #ClutterActor:min-height property
5490 obj_props[PROP_MIN_HEIGHT_SET] =
5491 g_param_spec_boolean ("min-height-set",
5492 P_("Minimum height set"),
5493 P_("Whether to use the min-height property"),
5495 CLUTTER_PARAM_READWRITE);
5498 * ClutterActor:natural-width-set:
5500 * This flag controls whether the #ClutterActor:natural-width property
5505 obj_props[PROP_NATURAL_WIDTH_SET] =
5506 g_param_spec_boolean ("natural-width-set",
5507 P_("Natural width set"),
5508 P_("Whether to use the natural-width property"),
5510 CLUTTER_PARAM_READWRITE);
5513 * ClutterActor:natural-height-set:
5515 * This flag controls whether the #ClutterActor:natural-height property
5520 obj_props[PROP_NATURAL_HEIGHT_SET] =
5521 g_param_spec_boolean ("natural-height-set",
5522 P_("Natural height set"),
5523 P_("Whether to use the natural-height property"),
5525 CLUTTER_PARAM_READWRITE);
5528 * ClutterActor:allocation:
5530 * The allocation for the actor, in pixels
5532 * This is property is read-only, but you might monitor it to know when an
5533 * actor moves or resizes
5537 obj_props[PROP_ALLOCATION] =
5538 g_param_spec_boxed ("allocation",
5540 P_("The actor's allocation"),
5541 CLUTTER_TYPE_ACTOR_BOX,
5542 CLUTTER_PARAM_READABLE);
5545 * ClutterActor:request-mode:
5547 * Request mode for the #ClutterActor. The request mode determines the
5548 * type of geometry management used by the actor, either height for width
5549 * (the default) or width for height.
5551 * For actors implementing height for width, the parent container should get
5552 * the preferred width first, and then the preferred height for that width.
5554 * For actors implementing width for height, the parent container should get
5555 * the preferred height first, and then the preferred width for that height.
5560 * ClutterRequestMode mode;
5561 * gfloat natural_width, min_width;
5562 * gfloat natural_height, min_height;
5564 * mode = clutter_actor_get_request_mode (child);
5565 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5567 * clutter_actor_get_preferred_width (child, -1,
5569 * &natural_width);
5570 * clutter_actor_get_preferred_height (child, natural_width,
5572 * &natural_height);
5576 * clutter_actor_get_preferred_height (child, -1,
5578 * &natural_height);
5579 * clutter_actor_get_preferred_width (child, natural_height,
5581 * &natural_width);
5585 * will retrieve the minimum and natural width and height depending on the
5586 * preferred request mode of the #ClutterActor "child".
5588 * The clutter_actor_get_preferred_size() function will implement this
5593 obj_props[PROP_REQUEST_MODE] =
5594 g_param_spec_enum ("request-mode",
5596 P_("The actor's request mode"),
5597 CLUTTER_TYPE_REQUEST_MODE,
5598 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5599 CLUTTER_PARAM_READWRITE);
5602 * ClutterActor:depth:
5604 * The position of the actor on the Z axis.
5606 * The #ClutterActor:depth property is relative to the parent's
5609 * The #ClutterActor:depth property is animatable.
5613 obj_props[PROP_DEPTH] =
5614 g_param_spec_float ("depth",
5616 P_("Position on the Z axis"),
5617 -G_MAXFLOAT, G_MAXFLOAT,
5620 G_PARAM_STATIC_STRINGS |
5621 CLUTTER_PARAM_ANIMATABLE);
5624 * ClutterActor:opacity:
5626 * Opacity of an actor, between 0 (fully transparent) and
5627 * 255 (fully opaque)
5629 * The #ClutterActor:opacity property is animatable.
5631 obj_props[PROP_OPACITY] =
5632 g_param_spec_uint ("opacity",
5634 P_("Opacity of an actor"),
5638 G_PARAM_STATIC_STRINGS |
5639 CLUTTER_PARAM_ANIMATABLE);
5642 * ClutterActor:offscreen-redirect:
5644 * Determines the conditions in which the actor will be redirected
5645 * to an offscreen framebuffer while being painted. For example this
5646 * can be used to cache an actor in a framebuffer or for improved
5647 * handling of transparent actors. See
5648 * clutter_actor_set_offscreen_redirect() for details.
5652 obj_props[PROP_OFFSCREEN_REDIRECT] =
5653 g_param_spec_flags ("offscreen-redirect",
5654 P_("Offscreen redirect"),
5655 P_("Flags controlling when to flatten the actor into a single image"),
5656 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5658 CLUTTER_PARAM_READWRITE);
5661 * ClutterActor:visible:
5663 * Whether the actor is set to be visible or not
5665 * See also #ClutterActor:mapped
5667 obj_props[PROP_VISIBLE] =
5668 g_param_spec_boolean ("visible",
5670 P_("Whether the actor is visible or not"),
5672 CLUTTER_PARAM_READWRITE);
5675 * ClutterActor:mapped:
5677 * Whether the actor is mapped (will be painted when the stage
5678 * to which it belongs is mapped)
5682 obj_props[PROP_MAPPED] =
5683 g_param_spec_boolean ("mapped",
5685 P_("Whether the actor will be painted"),
5687 CLUTTER_PARAM_READABLE);
5690 * ClutterActor:realized:
5692 * Whether the actor has been realized
5696 obj_props[PROP_REALIZED] =
5697 g_param_spec_boolean ("realized",
5699 P_("Whether the actor has been realized"),
5701 CLUTTER_PARAM_READABLE);
5704 * ClutterActor:reactive:
5706 * Whether the actor is reactive to events or not
5708 * Only reactive actors will emit event-related signals
5712 obj_props[PROP_REACTIVE] =
5713 g_param_spec_boolean ("reactive",
5715 P_("Whether the actor is reactive to events"),
5717 CLUTTER_PARAM_READWRITE);
5720 * ClutterActor:has-clip:
5722 * Whether the actor has the #ClutterActor:clip property set or not
5724 obj_props[PROP_HAS_CLIP] =
5725 g_param_spec_boolean ("has-clip",
5727 P_("Whether the actor has a clip set"),
5729 CLUTTER_PARAM_READABLE);
5732 * ClutterActor:clip:
5734 * The clip region for the actor, in actor-relative coordinates
5736 * Every part of the actor outside the clip region will not be
5739 obj_props[PROP_CLIP] =
5740 g_param_spec_boxed ("clip",
5742 P_("The clip region for the actor"),
5743 CLUTTER_TYPE_GEOMETRY,
5744 CLUTTER_PARAM_READWRITE);
5747 * ClutterActor:name:
5749 * The name of the actor
5753 obj_props[PROP_NAME] =
5754 g_param_spec_string ("name",
5756 P_("Name of the actor"),
5758 CLUTTER_PARAM_READWRITE);
5761 * ClutterActor:scale-x:
5763 * The horizontal scale of the actor.
5765 * The #ClutterActor:scale-x property is animatable.
5769 obj_props[PROP_SCALE_X] =
5770 g_param_spec_double ("scale-x",
5772 P_("Scale factor on the X axis"),
5776 G_PARAM_STATIC_STRINGS |
5777 CLUTTER_PARAM_ANIMATABLE);
5780 * ClutterActor:scale-y:
5782 * The vertical scale of the actor.
5784 * The #ClutterActor:scale-y property is animatable.
5788 obj_props[PROP_SCALE_Y] =
5789 g_param_spec_double ("scale-y",
5791 P_("Scale factor on the Y axis"),
5795 G_PARAM_STATIC_STRINGS |
5796 CLUTTER_PARAM_ANIMATABLE);
5799 * ClutterActor:scale-center-x:
5801 * The horizontal center point for scaling
5805 obj_props[PROP_SCALE_CENTER_X] =
5806 g_param_spec_float ("scale-center-x",
5807 P_("Scale Center X"),
5808 P_("Horizontal scale center"),
5809 -G_MAXFLOAT, G_MAXFLOAT,
5811 CLUTTER_PARAM_READWRITE);
5814 * ClutterActor:scale-center-y:
5816 * The vertical center point for scaling
5820 obj_props[PROP_SCALE_CENTER_Y] =
5821 g_param_spec_float ("scale-center-y",
5822 P_("Scale Center Y"),
5823 P_("Vertical scale center"),
5824 -G_MAXFLOAT, G_MAXFLOAT,
5826 CLUTTER_PARAM_READWRITE);
5829 * ClutterActor:scale-gravity:
5831 * The center point for scaling expressed as a #ClutterGravity
5835 obj_props[PROP_SCALE_GRAVITY] =
5836 g_param_spec_enum ("scale-gravity",
5837 P_("Scale Gravity"),
5838 P_("The center of scaling"),
5839 CLUTTER_TYPE_GRAVITY,
5840 CLUTTER_GRAVITY_NONE,
5841 CLUTTER_PARAM_READWRITE);
5844 * ClutterActor:rotation-angle-x:
5846 * The rotation angle on the X axis.
5848 * The #ClutterActor:rotation-angle-x property is animatable.
5852 obj_props[PROP_ROTATION_ANGLE_X] =
5853 g_param_spec_double ("rotation-angle-x",
5854 P_("Rotation Angle X"),
5855 P_("The rotation angle on the X axis"),
5856 -G_MAXDOUBLE, G_MAXDOUBLE,
5859 G_PARAM_STATIC_STRINGS |
5860 CLUTTER_PARAM_ANIMATABLE);
5863 * ClutterActor:rotation-angle-y:
5865 * The rotation angle on the Y axis
5867 * The #ClutterActor:rotation-angle-y property is animatable.
5871 obj_props[PROP_ROTATION_ANGLE_Y] =
5872 g_param_spec_double ("rotation-angle-y",
5873 P_("Rotation Angle Y"),
5874 P_("The rotation angle on the Y axis"),
5875 -G_MAXDOUBLE, G_MAXDOUBLE,
5878 G_PARAM_STATIC_STRINGS |
5879 CLUTTER_PARAM_ANIMATABLE);
5882 * ClutterActor:rotation-angle-z:
5884 * The rotation angle on the Z axis
5886 * The #ClutterActor:rotation-angle-z property is animatable.
5890 obj_props[PROP_ROTATION_ANGLE_Z] =
5891 g_param_spec_double ("rotation-angle-z",
5892 P_("Rotation Angle Z"),
5893 P_("The rotation angle on the Z axis"),
5894 -G_MAXDOUBLE, G_MAXDOUBLE,
5897 G_PARAM_STATIC_STRINGS |
5898 CLUTTER_PARAM_ANIMATABLE);
5901 * ClutterActor:rotation-center-x:
5903 * The rotation center on the X axis.
5907 obj_props[PROP_ROTATION_CENTER_X] =
5908 g_param_spec_boxed ("rotation-center-x",
5909 P_("Rotation Center X"),
5910 P_("The rotation center on the X axis"),
5911 CLUTTER_TYPE_VERTEX,
5912 CLUTTER_PARAM_READWRITE);
5915 * ClutterActor:rotation-center-y:
5917 * The rotation center on the Y axis.
5921 obj_props[PROP_ROTATION_CENTER_Y] =
5922 g_param_spec_boxed ("rotation-center-y",
5923 P_("Rotation Center Y"),
5924 P_("The rotation center on the Y axis"),
5925 CLUTTER_TYPE_VERTEX,
5926 CLUTTER_PARAM_READWRITE);
5929 * ClutterActor:rotation-center-z:
5931 * The rotation center on the Z axis.
5935 obj_props[PROP_ROTATION_CENTER_Z] =
5936 g_param_spec_boxed ("rotation-center-z",
5937 P_("Rotation Center Z"),
5938 P_("The rotation center on the Z axis"),
5939 CLUTTER_TYPE_VERTEX,
5940 CLUTTER_PARAM_READWRITE);
5943 * ClutterActor:rotation-center-z-gravity:
5945 * The rotation center on the Z axis expressed as a #ClutterGravity.
5949 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5950 g_param_spec_enum ("rotation-center-z-gravity",
5951 P_("Rotation Center Z Gravity"),
5952 P_("Center point for rotation around the Z axis"),
5953 CLUTTER_TYPE_GRAVITY,
5954 CLUTTER_GRAVITY_NONE,
5955 CLUTTER_PARAM_READWRITE);
5958 * ClutterActor:anchor-x:
5960 * The X coordinate of an actor's anchor point, relative to
5961 * the actor coordinate space, in pixels
5965 obj_props[PROP_ANCHOR_X] =
5966 g_param_spec_float ("anchor-x",
5968 P_("X coordinate of the anchor point"),
5969 -G_MAXFLOAT, G_MAXFLOAT,
5971 CLUTTER_PARAM_READWRITE);
5974 * ClutterActor:anchor-y:
5976 * The Y coordinate of an actor's anchor point, relative to
5977 * the actor coordinate space, in pixels
5981 obj_props[PROP_ANCHOR_Y] =
5982 g_param_spec_float ("anchor-y",
5984 P_("Y coordinate of the anchor point"),
5985 -G_MAXFLOAT, G_MAXFLOAT,
5987 CLUTTER_PARAM_READWRITE);
5990 * ClutterActor:anchor-gravity:
5992 * The anchor point expressed as a #ClutterGravity
5996 obj_props[PROP_ANCHOR_GRAVITY] =
5997 g_param_spec_enum ("anchor-gravity",
5998 P_("Anchor Gravity"),
5999 P_("The anchor point as a ClutterGravity"),
6000 CLUTTER_TYPE_GRAVITY,
6001 CLUTTER_GRAVITY_NONE,
6002 CLUTTER_PARAM_READWRITE);
6005 * ClutterActor:show-on-set-parent:
6007 * If %TRUE, the actor is automatically shown when parented.
6009 * Calling clutter_actor_hide() on an actor which has not been
6010 * parented will set this property to %FALSE as a side effect.
6014 obj_props[PROP_SHOW_ON_SET_PARENT] =
6015 g_param_spec_boolean ("show-on-set-parent",
6016 P_("Show on set parent"),
6017 P_("Whether the actor is shown when parented"),
6019 CLUTTER_PARAM_READWRITE);
6022 * ClutterActor:clip-to-allocation:
6024 * Whether the clip region should track the allocated area
6027 * This property is ignored if a clip area has been explicitly
6028 * set using clutter_actor_set_clip().
6032 obj_props[PROP_CLIP_TO_ALLOCATION] =
6033 g_param_spec_boolean ("clip-to-allocation",
6034 P_("Clip to Allocation"),
6035 P_("Sets the clip region to track the actor's allocation"),
6037 CLUTTER_PARAM_READWRITE);
6040 * ClutterActor:text-direction:
6042 * The direction of the text inside a #ClutterActor.
6046 obj_props[PROP_TEXT_DIRECTION] =
6047 g_param_spec_enum ("text-direction",
6048 P_("Text Direction"),
6049 P_("Direction of the text"),
6050 CLUTTER_TYPE_TEXT_DIRECTION,
6051 CLUTTER_TEXT_DIRECTION_LTR,
6052 CLUTTER_PARAM_READWRITE);
6055 * ClutterActor:has-pointer:
6057 * Whether the actor contains the pointer of a #ClutterInputDevice
6062 obj_props[PROP_HAS_POINTER] =
6063 g_param_spec_boolean ("has-pointer",
6065 P_("Whether the actor contains the pointer of an input device"),
6067 CLUTTER_PARAM_READABLE);
6070 * ClutterActor:actions:
6072 * Adds a #ClutterAction to the actor
6076 obj_props[PROP_ACTIONS] =
6077 g_param_spec_object ("actions",
6079 P_("Adds an action to the actor"),
6080 CLUTTER_TYPE_ACTION,
6081 CLUTTER_PARAM_WRITABLE);
6084 * ClutterActor:constraints:
6086 * Adds a #ClutterConstraint to the actor
6090 obj_props[PROP_CONSTRAINTS] =
6091 g_param_spec_object ("constraints",
6093 P_("Adds a constraint to the actor"),
6094 CLUTTER_TYPE_CONSTRAINT,
6095 CLUTTER_PARAM_WRITABLE);
6098 * ClutterActor:effect:
6100 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6104 obj_props[PROP_EFFECT] =
6105 g_param_spec_object ("effect",
6107 P_("Add an effect to be applied on the actor"),
6108 CLUTTER_TYPE_EFFECT,
6109 CLUTTER_PARAM_WRITABLE);
6112 * ClutterActor:layout-manager:
6114 * A delegate object for controlling the layout of the children of
6119 obj_props[PROP_LAYOUT_MANAGER] =
6120 g_param_spec_object ("layout-manager",
6121 P_("Layout Manager"),
6122 P_("The object controlling the layout of an actor's children"),
6123 CLUTTER_TYPE_LAYOUT_MANAGER,
6124 CLUTTER_PARAM_READWRITE);
6128 * ClutterActor:x-align:
6130 * The alignment of an actor on the X axis, if the actor has been given
6131 * extra space for its allocation.
6135 obj_props[PROP_X_ALIGN] =
6136 g_param_spec_enum ("x-align",
6138 P_("The alignment of the actor on the X axis within its allocation"),
6139 CLUTTER_TYPE_ACTOR_ALIGN,
6140 CLUTTER_ACTOR_ALIGN_FILL,
6141 CLUTTER_PARAM_READWRITE);
6144 * ClutterActor:y-align:
6146 * The alignment of an actor on the Y axis, if the actor has been given
6147 * extra space for its allocation.
6151 obj_props[PROP_Y_ALIGN] =
6152 g_param_spec_enum ("y-align",
6154 P_("The alignment of the actor on the Y axis within its allocation"),
6155 CLUTTER_TYPE_ACTOR_ALIGN,
6156 CLUTTER_ACTOR_ALIGN_FILL,
6157 CLUTTER_PARAM_READWRITE);
6160 * ClutterActor:margin-top:
6162 * The margin (in pixels) from the top of the actor.
6164 * This property adds a margin to the actor's preferred size; the margin
6165 * will be automatically taken into account when allocating the actor.
6169 obj_props[PROP_MARGIN_TOP] =
6170 g_param_spec_float ("margin-top",
6172 P_("Extra space at the top"),
6175 CLUTTER_PARAM_READWRITE);
6178 * ClutterActor:margin-bottom:
6180 * The margin (in pixels) from the bottom of the actor.
6182 * This property adds a margin to the actor's preferred size; the margin
6183 * will be automatically taken into account when allocating the actor.
6187 obj_props[PROP_MARGIN_BOTTOM] =
6188 g_param_spec_float ("margin-bottom",
6189 P_("Margin Bottom"),
6190 P_("Extra space at the bottom"),
6193 CLUTTER_PARAM_READWRITE);
6196 * ClutterActor:margin-left:
6198 * The margin (in pixels) from the left of the actor.
6200 * This property adds a margin to the actor's preferred size; the margin
6201 * will be automatically taken into account when allocating the actor.
6205 obj_props[PROP_MARGIN_LEFT] =
6206 g_param_spec_float ("margin-left",
6208 P_("Extra space at the left"),
6211 CLUTTER_PARAM_READWRITE);
6214 * ClutterActor:margin-right:
6216 * The margin (in pixels) from the right of the actor.
6218 * This property adds a margin to the actor's preferred size; the margin
6219 * will be automatically taken into account when allocating the actor.
6223 obj_props[PROP_MARGIN_RIGHT] =
6224 g_param_spec_float ("margin-right",
6226 P_("Extra space at the right"),
6229 CLUTTER_PARAM_READWRITE);
6232 * ClutterActor:background-color-set:
6234 * Whether the #ClutterActor:background-color property has been set.
6238 obj_props[PROP_BACKGROUND_COLOR_SET] =
6239 g_param_spec_boolean ("background-color-set",
6240 P_("Background Color Set"),
6241 P_("Whether the background color is set"),
6243 CLUTTER_PARAM_READABLE);
6246 * ClutterActor:background-color:
6248 * Paints a solid fill of the actor's allocation using the specified
6251 * The #ClutterActor:background-color property is animatable.
6255 obj_props[PROP_BACKGROUND_COLOR] =
6256 clutter_param_spec_color ("background-color",
6257 P_("Background color"),
6258 P_("The actor's background color"),
6259 CLUTTER_COLOR_Transparent,
6261 G_PARAM_STATIC_STRINGS |
6262 CLUTTER_PARAM_ANIMATABLE);
6265 * ClutterActor:first-child:
6267 * The actor's first child.
6271 obj_props[PROP_FIRST_CHILD] =
6272 g_param_spec_object ("first-child",
6274 P_("The actor's first child"),
6276 CLUTTER_PARAM_READABLE);
6279 * ClutterActor:last-child:
6281 * The actor's last child.
6285 obj_props[PROP_LAST_CHILD] =
6286 g_param_spec_object ("last-child",
6288 P_("The actor's last child"),
6290 CLUTTER_PARAM_READABLE);
6293 * ClutterActor:content:
6295 * The #ClutterContent implementation that controls the content
6300 obj_props[PROP_CONTENT] =
6301 g_param_spec_object ("content",
6303 P_("Delegate object for painting the actor's content"),
6304 CLUTTER_TYPE_CONTENT,
6305 CLUTTER_PARAM_READWRITE);
6308 * ClutterActor:content-gravity:
6310 * The alignment that should be honoured by the #ClutterContent
6311 * set with the #ClutterActor:content property.
6313 * Changing the value of this property will change the bounding box of
6314 * the content; you can use the #ClutterActor:content-box property to
6315 * get the position and size of the content within the actor's
6318 * This property is meaningful only for #ClutterContent implementations
6319 * that have a preferred size, and if the preferred size is smaller than
6320 * the actor's allocation.
6324 obj_props[PROP_CONTENT_GRAVITY] =
6325 g_param_spec_enum ("content-gravity",
6326 P_("Content Gravity"),
6327 P_("Alignment of the actor's content"),
6328 CLUTTER_TYPE_CONTENT_GRAVITY,
6329 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6330 CLUTTER_PARAM_READWRITE);
6333 * ClutterActor:content-box:
6335 * The bounding box for the #ClutterContent used by the actor.
6337 * The value of this property is controlled by the #ClutterActor:allocation
6338 * and #ClutterActor:content-gravity properties of #ClutterActor.
6340 * The bounding box for the content is guaranteed to never exceed the
6341 * allocation's of the actor.
6345 obj_props[PROP_CONTENT_BOX] =
6346 g_param_spec_boxed ("content-box",
6348 P_("The bounding box of the actor's content"),
6349 CLUTTER_TYPE_ACTOR_BOX,
6350 CLUTTER_PARAM_READABLE);
6352 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6355 * ClutterActor::destroy:
6356 * @actor: the #ClutterActor which emitted the signal
6358 * The ::destroy signal notifies that all references held on the
6359 * actor which emitted it should be released.
6361 * The ::destroy signal should be used by all holders of a reference
6364 * This signal might result in the finalization of the #ClutterActor
6365 * if all references are released.
6367 * Composite actors and actors implementing the #ClutterContainer
6368 * interface should override the default implementation of the
6369 * class handler of this signal and call clutter_actor_destroy() on
6370 * their children. When overriding the default class handler, it is
6371 * required to chain up to the parent's implementation.
6375 actor_signals[DESTROY] =
6376 g_signal_new (I_("destroy"),
6377 G_TYPE_FROM_CLASS (object_class),
6378 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6379 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6381 _clutter_marshal_VOID__VOID,
6384 * ClutterActor::show:
6385 * @actor: the object which received the signal
6387 * The ::show signal is emitted when an actor is visible and
6388 * rendered on the stage.
6392 actor_signals[SHOW] =
6393 g_signal_new (I_("show"),
6394 G_TYPE_FROM_CLASS (object_class),
6396 G_STRUCT_OFFSET (ClutterActorClass, show),
6398 _clutter_marshal_VOID__VOID,
6401 * ClutterActor::hide:
6402 * @actor: the object which received the signal
6404 * The ::hide signal is emitted when an actor is no longer rendered
6409 actor_signals[HIDE] =
6410 g_signal_new (I_("hide"),
6411 G_TYPE_FROM_CLASS (object_class),
6413 G_STRUCT_OFFSET (ClutterActorClass, hide),
6415 _clutter_marshal_VOID__VOID,
6418 * ClutterActor::parent-set:
6419 * @actor: the object which received the signal
6420 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6422 * This signal is emitted when the parent of the actor changes.
6426 actor_signals[PARENT_SET] =
6427 g_signal_new (I_("parent-set"),
6428 G_TYPE_FROM_CLASS (object_class),
6430 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6432 _clutter_marshal_VOID__OBJECT,
6434 CLUTTER_TYPE_ACTOR);
6437 * ClutterActor::queue-redraw:
6438 * @actor: the actor we're bubbling the redraw request through
6439 * @origin: the actor which initiated the redraw request
6441 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6442 * is called on @origin.
6444 * The default implementation for #ClutterActor chains up to the
6445 * parent actor and queues a redraw on the parent, thus "bubbling"
6446 * the redraw queue up through the actor graph. The default
6447 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6448 * in a main loop idle handler.
6450 * Note that the @origin actor may be the stage, or a container; it
6451 * does not have to be a leaf node in the actor graph.
6453 * Toolkits embedding a #ClutterStage which require a redraw and
6454 * relayout cycle can stop the emission of this signal using the
6455 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6460 * on_redraw_complete (gpointer data)
6462 * ClutterStage *stage = data;
6464 * /* execute the Clutter drawing pipeline */
6465 * clutter_stage_ensure_redraw (stage);
6469 * on_stage_queue_redraw (ClutterStage *stage)
6471 * /* this prevents the default handler to run */
6472 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6474 * /* queue a redraw with the host toolkit and call
6475 * * a function when the redraw has been completed
6477 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6481 * <note><para>This signal is emitted before the Clutter paint
6482 * pipeline is executed. If you want to know when the pipeline has
6483 * been completed you should connect to the ::paint signal on the
6484 * Stage with g_signal_connect_after().</para></note>
6488 actor_signals[QUEUE_REDRAW] =
6489 g_signal_new (I_("queue-redraw"),
6490 G_TYPE_FROM_CLASS (object_class),
6493 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6495 _clutter_marshal_VOID__OBJECT,
6497 CLUTTER_TYPE_ACTOR);
6500 * ClutterActor::queue-relayout
6501 * @actor: the actor being queued for relayout
6503 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6504 * is called on an actor.
6506 * The default implementation for #ClutterActor chains up to the
6507 * parent actor and queues a relayout on the parent, thus "bubbling"
6508 * the relayout queue up through the actor graph.
6510 * The main purpose of this signal is to allow relayout to be propagated
6511 * properly in the procense of #ClutterClone actors. Applications will
6512 * not normally need to connect to this signal.
6516 actor_signals[QUEUE_RELAYOUT] =
6517 g_signal_new (I_("queue-relayout"),
6518 G_TYPE_FROM_CLASS (object_class),
6521 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6523 _clutter_marshal_VOID__VOID,
6527 * ClutterActor::event:
6528 * @actor: the actor which received the event
6529 * @event: a #ClutterEvent
6531 * The ::event signal is emitted each time an event is received
6532 * by the @actor. This signal will be emitted on every actor,
6533 * following the hierarchy chain, until it reaches the top-level
6534 * container (the #ClutterStage).
6536 * Return value: %TRUE if the event has been handled by the actor,
6537 * or %FALSE to continue the emission.
6541 actor_signals[EVENT] =
6542 g_signal_new (I_("event"),
6543 G_TYPE_FROM_CLASS (object_class),
6545 G_STRUCT_OFFSET (ClutterActorClass, event),
6546 _clutter_boolean_handled_accumulator, NULL,
6547 _clutter_marshal_BOOLEAN__BOXED,
6549 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6551 * ClutterActor::button-press-event:
6552 * @actor: the actor which received the event
6553 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6555 * The ::button-press-event signal is emitted each time a mouse button
6556 * is pressed on @actor.
6558 * Return value: %TRUE if the event has been handled by the actor,
6559 * or %FALSE to continue the emission.
6563 actor_signals[BUTTON_PRESS_EVENT] =
6564 g_signal_new (I_("button-press-event"),
6565 G_TYPE_FROM_CLASS (object_class),
6567 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6568 _clutter_boolean_handled_accumulator, NULL,
6569 _clutter_marshal_BOOLEAN__BOXED,
6571 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6573 * ClutterActor::button-release-event:
6574 * @actor: the actor which received the event
6575 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6577 * The ::button-release-event signal is emitted each time a mouse button
6578 * is released on @actor.
6580 * Return value: %TRUE if the event has been handled by the actor,
6581 * or %FALSE to continue the emission.
6585 actor_signals[BUTTON_RELEASE_EVENT] =
6586 g_signal_new (I_("button-release-event"),
6587 G_TYPE_FROM_CLASS (object_class),
6589 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6590 _clutter_boolean_handled_accumulator, NULL,
6591 _clutter_marshal_BOOLEAN__BOXED,
6593 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6595 * ClutterActor::scroll-event:
6596 * @actor: the actor which received the event
6597 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6599 * The ::scroll-event signal is emitted each time the mouse is
6600 * scrolled on @actor
6602 * Return value: %TRUE if the event has been handled by the actor,
6603 * or %FALSE to continue the emission.
6607 actor_signals[SCROLL_EVENT] =
6608 g_signal_new (I_("scroll-event"),
6609 G_TYPE_FROM_CLASS (object_class),
6611 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6612 _clutter_boolean_handled_accumulator, NULL,
6613 _clutter_marshal_BOOLEAN__BOXED,
6615 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6617 * ClutterActor::key-press-event:
6618 * @actor: the actor which received the event
6619 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6621 * The ::key-press-event signal is emitted each time a keyboard button
6622 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6624 * Return value: %TRUE if the event has been handled by the actor,
6625 * or %FALSE to continue the emission.
6629 actor_signals[KEY_PRESS_EVENT] =
6630 g_signal_new (I_("key-press-event"),
6631 G_TYPE_FROM_CLASS (object_class),
6633 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6634 _clutter_boolean_handled_accumulator, NULL,
6635 _clutter_marshal_BOOLEAN__BOXED,
6637 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6639 * ClutterActor::key-release-event:
6640 * @actor: the actor which received the event
6641 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6643 * The ::key-release-event signal is emitted each time a keyboard button
6644 * is released while @actor has key focus (see
6645 * clutter_stage_set_key_focus()).
6647 * Return value: %TRUE if the event has been handled by the actor,
6648 * or %FALSE to continue the emission.
6652 actor_signals[KEY_RELEASE_EVENT] =
6653 g_signal_new (I_("key-release-event"),
6654 G_TYPE_FROM_CLASS (object_class),
6656 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6657 _clutter_boolean_handled_accumulator, NULL,
6658 _clutter_marshal_BOOLEAN__BOXED,
6660 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6662 * ClutterActor::motion-event:
6663 * @actor: the actor which received the event
6664 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6666 * The ::motion-event signal is emitted each time the mouse pointer is
6667 * moved over @actor.
6669 * Return value: %TRUE if the event has been handled by the actor,
6670 * or %FALSE to continue the emission.
6674 actor_signals[MOTION_EVENT] =
6675 g_signal_new (I_("motion-event"),
6676 G_TYPE_FROM_CLASS (object_class),
6678 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6679 _clutter_boolean_handled_accumulator, NULL,
6680 _clutter_marshal_BOOLEAN__BOXED,
6682 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6685 * ClutterActor::key-focus-in:
6686 * @actor: the actor which now has key focus
6688 * The ::key-focus-in signal is emitted when @actor receives key focus.
6692 actor_signals[KEY_FOCUS_IN] =
6693 g_signal_new (I_("key-focus-in"),
6694 G_TYPE_FROM_CLASS (object_class),
6696 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6698 _clutter_marshal_VOID__VOID,
6702 * ClutterActor::key-focus-out:
6703 * @actor: the actor which now has key focus
6705 * The ::key-focus-out signal is emitted when @actor loses key focus.
6709 actor_signals[KEY_FOCUS_OUT] =
6710 g_signal_new (I_("key-focus-out"),
6711 G_TYPE_FROM_CLASS (object_class),
6713 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6715 _clutter_marshal_VOID__VOID,
6719 * ClutterActor::enter-event:
6720 * @actor: the actor which the pointer has entered.
6721 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6723 * The ::enter-event signal is emitted when the pointer enters the @actor
6725 * Return value: %TRUE if the event has been handled by the actor,
6726 * or %FALSE to continue the emission.
6730 actor_signals[ENTER_EVENT] =
6731 g_signal_new (I_("enter-event"),
6732 G_TYPE_FROM_CLASS (object_class),
6734 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6735 _clutter_boolean_handled_accumulator, NULL,
6736 _clutter_marshal_BOOLEAN__BOXED,
6738 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6741 * ClutterActor::leave-event:
6742 * @actor: the actor which the pointer has left
6743 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6745 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6747 * Return value: %TRUE if the event has been handled by the actor,
6748 * or %FALSE to continue the emission.
6752 actor_signals[LEAVE_EVENT] =
6753 g_signal_new (I_("leave-event"),
6754 G_TYPE_FROM_CLASS (object_class),
6756 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6757 _clutter_boolean_handled_accumulator, NULL,
6758 _clutter_marshal_BOOLEAN__BOXED,
6760 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6763 * ClutterActor::captured-event:
6764 * @actor: the actor which received the signal
6765 * @event: a #ClutterEvent
6767 * The ::captured-event signal is emitted when an event is captured
6768 * by Clutter. This signal will be emitted starting from the top-level
6769 * container (the #ClutterStage) to the actor which received the event
6770 * going down the hierarchy. This signal can be used to intercept every
6771 * event before the specialized events (like
6772 * ClutterActor::button-press-event or ::key-released-event) are
6775 * Return value: %TRUE if the event has been handled by the actor,
6776 * or %FALSE to continue the emission.
6780 actor_signals[CAPTURED_EVENT] =
6781 g_signal_new (I_("captured-event"),
6782 G_TYPE_FROM_CLASS (object_class),
6784 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6785 _clutter_boolean_handled_accumulator, NULL,
6786 _clutter_marshal_BOOLEAN__BOXED,
6788 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6791 * ClutterActor::paint:
6792 * @actor: the #ClutterActor that received the signal
6794 * The ::paint signal is emitted each time an actor is being painted.
6796 * Subclasses of #ClutterActor should override the class signal handler
6797 * and paint themselves in that function.
6799 * It is possible to connect a handler to the ::paint signal in order
6800 * to set up some custom aspect of a paint.
6804 actor_signals[PAINT] =
6805 g_signal_new (I_("paint"),
6806 G_TYPE_FROM_CLASS (object_class),
6809 G_STRUCT_OFFSET (ClutterActorClass, paint),
6811 _clutter_marshal_VOID__VOID,
6814 * ClutterActor::realize:
6815 * @actor: the #ClutterActor that received the signal
6817 * The ::realize signal is emitted each time an actor is being
6822 actor_signals[REALIZE] =
6823 g_signal_new (I_("realize"),
6824 G_TYPE_FROM_CLASS (object_class),
6826 G_STRUCT_OFFSET (ClutterActorClass, realize),
6828 _clutter_marshal_VOID__VOID,
6831 * ClutterActor::unrealize:
6832 * @actor: the #ClutterActor that received the signal
6834 * The ::unrealize signal is emitted each time an actor is being
6839 actor_signals[UNREALIZE] =
6840 g_signal_new (I_("unrealize"),
6841 G_TYPE_FROM_CLASS (object_class),
6843 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6845 _clutter_marshal_VOID__VOID,
6849 * ClutterActor::pick:
6850 * @actor: the #ClutterActor that received the signal
6851 * @color: the #ClutterColor to be used when picking
6853 * The ::pick signal is emitted each time an actor is being painted
6854 * in "pick mode". The pick mode is used to identify the actor during
6855 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6856 * The actor should paint its shape using the passed @pick_color.
6858 * Subclasses of #ClutterActor should override the class signal handler
6859 * and paint themselves in that function.
6861 * It is possible to connect a handler to the ::pick signal in order
6862 * to set up some custom aspect of a paint in pick mode.
6866 actor_signals[PICK] =
6867 g_signal_new (I_("pick"),
6868 G_TYPE_FROM_CLASS (object_class),
6870 G_STRUCT_OFFSET (ClutterActorClass, pick),
6872 _clutter_marshal_VOID__BOXED,
6874 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6877 * ClutterActor::allocation-changed:
6878 * @actor: the #ClutterActor that emitted the signal
6879 * @box: a #ClutterActorBox with the new allocation
6880 * @flags: #ClutterAllocationFlags for the allocation
6882 * The ::allocation-changed signal is emitted when the
6883 * #ClutterActor:allocation property changes. Usually, application
6884 * code should just use the notifications for the :allocation property
6885 * but if you want to track the allocation flags as well, for instance
6886 * to know whether the absolute origin of @actor changed, then you might
6887 * want use this signal instead.
6891 actor_signals[ALLOCATION_CHANGED] =
6892 g_signal_new (I_("allocation-changed"),
6893 G_TYPE_FROM_CLASS (object_class),
6897 _clutter_marshal_VOID__BOXED_FLAGS,
6899 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6900 CLUTTER_TYPE_ALLOCATION_FLAGS);
6904 clutter_actor_init (ClutterActor *self)
6906 ClutterActorPrivate *priv;
6908 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6910 priv->id = _clutter_context_acquire_id (self);
6913 priv->opacity = 0xff;
6914 priv->show_on_set_parent = TRUE;
6916 priv->needs_width_request = TRUE;
6917 priv->needs_height_request = TRUE;
6918 priv->needs_allocation = TRUE;
6920 priv->cached_width_age = 1;
6921 priv->cached_height_age = 1;
6923 priv->opacity_override = -1;
6924 priv->enable_model_view_transform = TRUE;
6926 /* Initialize an empty paint volume to start with */
6927 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6928 priv->last_paint_volume_valid = TRUE;
6930 priv->transform_valid = FALSE;
6932 /* the default is to stretch the content, to match the
6933 * current behaviour of basically all actors. also, it's
6934 * the easiest thing to compute.
6936 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6940 * clutter_actor_new:
6942 * Creates a new #ClutterActor.
6944 * A newly created actor has a floating reference, which will be sunk
6945 * when it is added to another actor.
6947 * Return value: (transfer full): the newly created #ClutterActor
6952 clutter_actor_new (void)
6954 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6958 * clutter_actor_destroy:
6959 * @self: a #ClutterActor
6961 * Destroys an actor. When an actor is destroyed, it will break any
6962 * references it holds to other objects. If the actor is inside a
6963 * container, the actor will be removed.
6965 * When you destroy a container, its children will be destroyed as well.
6967 * Note: you cannot destroy the #ClutterStage returned by
6968 * clutter_stage_get_default().
6971 clutter_actor_destroy (ClutterActor *self)
6973 g_return_if_fail (CLUTTER_IS_ACTOR (self));
6975 g_object_ref (self);
6977 /* avoid recursion while destroying */
6978 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6980 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6982 g_object_run_dispose (G_OBJECT (self));
6984 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6987 g_object_unref (self);
6991 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6992 ClutterPaintVolume *clip)
6994 ClutterActorPrivate *priv = self->priv;
6995 ClutterPaintVolume *pv;
6998 /* Remove queue entry early in the process, otherwise a new
6999 queue_redraw() during signal handling could put back this
7000 object in the stage redraw list (but the entry is freed as
7001 soon as we return from this function, causing a segfault
7004 priv->queue_redraw_entry = NULL;
7006 /* If we've been explicitly passed a clip volume then there's
7007 * nothing more to calculate, but otherwise the only thing we know
7008 * is that the change is constrained to the given actor.
7010 * The idea is that if we know the paint volume for where the actor
7011 * was last drawn (in eye coordinates) and we also have the paint
7012 * volume for where it will be drawn next (in actor coordinates)
7013 * then if we queue a redraw for both these volumes that will cover
7014 * everything that needs to be redrawn to clear the old view and
7015 * show the latest view of the actor.
7017 * Don't clip this redraw if we don't know what position we had for
7018 * the previous redraw since we don't know where to set the clip so
7019 * it will clear the actor as it is currently.
7023 _clutter_actor_set_queue_redraw_clip (self, clip);
7026 else if (G_LIKELY (priv->last_paint_volume_valid))
7028 pv = _clutter_actor_get_paint_volume_mutable (self);
7031 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7033 /* make sure we redraw the actors old position... */
7034 _clutter_actor_set_queue_redraw_clip (stage,
7035 &priv->last_paint_volume);
7036 _clutter_actor_signal_queue_redraw (stage, stage);
7037 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7039 /* XXX: Ideally the redraw signal would take a clip volume
7040 * argument, but that would be an ABI break. Until we can
7041 * break the ABI we pass the argument out-of-band
7044 /* setup the clip for the actors new position... */
7045 _clutter_actor_set_queue_redraw_clip (self, pv);
7054 _clutter_actor_signal_queue_redraw (self, self);
7056 /* Just in case anyone is manually firing redraw signals without
7057 * using the public queue_redraw() API we are careful to ensure that
7058 * our out-of-band clip member is cleared before returning...
7060 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7062 if (G_LIKELY (clipped))
7063 _clutter_actor_set_queue_redraw_clip (self, NULL);
7067 _clutter_actor_get_allocation_clip (ClutterActor *self,
7068 ClutterActorBox *clip)
7070 ClutterActorBox allocation;
7072 /* XXX: we don't care if we get an out of date allocation here
7073 * because clutter_actor_queue_redraw_with_clip knows to ignore
7074 * the clip if the actor's allocation is invalid.
7076 * This is noted because clutter_actor_get_allocation_box does some
7077 * unnecessary work to support buggy code with a comment suggesting
7078 * that it could be changed later which would be good for this use
7081 clutter_actor_get_allocation_box (self, &allocation);
7083 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7084 * actor's own coordinate space but the allocation is in parent
7088 clip->x2 = allocation.x2 - allocation.x1;
7089 clip->y2 = allocation.y2 - allocation.y1;
7093 _clutter_actor_queue_redraw_full (ClutterActor *self,
7094 ClutterRedrawFlags flags,
7095 ClutterPaintVolume *volume,
7096 ClutterEffect *effect)
7098 ClutterActorPrivate *priv = self->priv;
7099 ClutterPaintVolume allocation_pv;
7100 ClutterPaintVolume *pv;
7101 gboolean should_free_pv;
7102 ClutterActor *stage;
7104 /* Here's an outline of the actor queue redraw mechanism:
7106 * The process starts in one of the following two functions which
7107 * are wrappers for this function:
7108 * clutter_actor_queue_redraw
7109 * _clutter_actor_queue_redraw_with_clip
7111 * additionally, an effect can queue a redraw by wrapping this
7112 * function in clutter_effect_queue_rerun
7114 * This functions queues an entry in a list associated with the
7115 * stage which is a list of actors that queued a redraw while
7116 * updating the timelines, performing layouting and processing other
7117 * mainloop sources before the next paint starts.
7119 * We aim to minimize the processing done at this point because
7120 * there is a good chance other events will happen while updating
7121 * the scenegraph that would invalidate any expensive work we might
7122 * otherwise try to do here. For example we don't try and resolve
7123 * the screen space bounding box of an actor at this stage so as to
7124 * minimize how much of the screen redraw because it's possible
7125 * something else will happen which will force a full redraw anyway.
7127 * When all updates are complete and we come to paint the stage then
7128 * we iterate this list and actually emit the "queue-redraw" signals
7129 * for each of the listed actors which will bubble up to the stage
7130 * for each actor and at that point we will transform the actors
7131 * paint volume into screen coordinates to determine the clip region
7132 * for what needs to be redrawn in the next paint.
7134 * Besides minimizing redundant work another reason for this
7135 * deferred design is that it's more likely we will be able to
7136 * determine the paint volume of an actor once we've finished
7137 * updating the scenegraph because its allocation should be up to
7138 * date. NB: If we can't determine an actors paint volume then we
7139 * can't automatically queue a clipped redraw which can make a big
7140 * difference to performance.
7142 * So the control flow goes like this:
7143 * One of clutter_actor_queue_redraw,
7144 * _clutter_actor_queue_redraw_with_clip
7145 * or clutter_effect_queue_rerun
7147 * then control moves to:
7148 * _clutter_stage_queue_actor_redraw
7150 * later during _clutter_stage_do_update, once relayouting is done
7151 * and the scenegraph has been updated we will call:
7152 * _clutter_stage_finish_queue_redraws
7154 * _clutter_stage_finish_queue_redraws will call
7155 * _clutter_actor_finish_queue_redraw for each listed actor.
7156 * Note: actors *are* allowed to queue further redraws during this
7157 * process (considering clone actors or texture_new_from_actor which
7158 * respond to their source queueing a redraw by queuing a redraw
7159 * themselves). We repeat the process until the list is empty.
7161 * This will result in the "queue-redraw" signal being fired for
7162 * each actor which will pass control to the default signal handler:
7163 * clutter_actor_real_queue_redraw
7165 * This will bubble up to the stages handler:
7166 * clutter_stage_real_queue_redraw
7168 * clutter_stage_real_queue_redraw will transform the actors paint
7169 * volume into screen space and add it as a clip region for the next
7173 /* ignore queueing a redraw for actors being destroyed */
7174 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7177 stage = _clutter_actor_get_stage_internal (self);
7179 /* Ignore queueing a redraw for actors not descended from a stage */
7183 /* ignore queueing a redraw on stages that are being destroyed */
7184 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7187 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7189 ClutterActorBox allocation_clip;
7190 ClutterVertex origin;
7192 /* If the actor doesn't have a valid allocation then we will
7193 * queue a full stage redraw. */
7194 if (priv->needs_allocation)
7196 /* NB: NULL denotes an undefined clip which will result in a
7198 _clutter_actor_set_queue_redraw_clip (self, NULL);
7199 _clutter_actor_signal_queue_redraw (self, self);
7203 _clutter_paint_volume_init_static (&allocation_pv, self);
7204 pv = &allocation_pv;
7206 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7208 origin.x = allocation_clip.x1;
7209 origin.y = allocation_clip.y1;
7211 clutter_paint_volume_set_origin (pv, &origin);
7212 clutter_paint_volume_set_width (pv,
7213 allocation_clip.x2 - allocation_clip.x1);
7214 clutter_paint_volume_set_height (pv,
7215 allocation_clip.y2 -
7216 allocation_clip.y1);
7217 should_free_pv = TRUE;
7222 should_free_pv = FALSE;
7225 self->priv->queue_redraw_entry =
7226 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7227 priv->queue_redraw_entry,
7232 clutter_paint_volume_free (pv);
7234 /* If this is the first redraw queued then we can directly use the
7236 if (!priv->is_dirty)
7237 priv->effect_to_redraw = effect;
7238 /* Otherwise we need to merge it with the existing effect parameter */
7239 else if (effect != NULL)
7241 /* If there's already an effect then we need to use whichever is
7242 later in the chain of actors. Otherwise a full redraw has
7243 already been queued on the actor so we need to ignore the
7245 if (priv->effect_to_redraw != NULL)
7247 if (priv->effects == NULL)
7248 g_warning ("Redraw queued with an effect that is "
7249 "not applied to the actor");
7254 for (l = _clutter_meta_group_peek_metas (priv->effects);
7258 if (l->data == priv->effect_to_redraw ||
7260 priv->effect_to_redraw = l->data;
7267 /* If no effect is specified then we need to redraw the whole
7269 priv->effect_to_redraw = NULL;
7272 priv->is_dirty = TRUE;
7276 * clutter_actor_queue_redraw:
7277 * @self: A #ClutterActor
7279 * Queues up a redraw of an actor and any children. The redraw occurs
7280 * once the main loop becomes idle (after the current batch of events
7281 * has been processed, roughly).
7283 * Applications rarely need to call this, as redraws are handled
7284 * automatically by modification functions.
7286 * This function will not do anything if @self is not visible, or
7287 * if the actor is inside an invisible part of the scenegraph.
7289 * Also be aware that painting is a NOP for actors with an opacity of
7292 * When you are implementing a custom actor you must queue a redraw
7293 * whenever some private state changes that will affect painting or
7294 * picking of your actor.
7297 clutter_actor_queue_redraw (ClutterActor *self)
7299 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7301 _clutter_actor_queue_redraw_full (self,
7303 NULL, /* clip volume */
7308 * _clutter_actor_queue_redraw_with_clip:
7309 * @self: A #ClutterActor
7310 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7311 * this queue redraw.
7312 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7313 * redrawn or %NULL if you are just using a @flag to state your
7316 * Queues up a clipped redraw of an actor and any children. The redraw
7317 * occurs once the main loop becomes idle (after the current batch of
7318 * events has been processed, roughly).
7320 * If no flags are given the clip volume is defined by @volume
7321 * specified in actor coordinates and tells Clutter that only content
7322 * within this volume has been changed so Clutter can optionally
7323 * optimize the redraw.
7325 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7326 * should be %NULL and this tells Clutter to use the actor's current
7327 * allocation as a clip box. This flag can only be used for 2D actors,
7328 * because any actor with depth may be projected outside its
7331 * Applications rarely need to call this, as redraws are handled
7332 * automatically by modification functions.
7334 * This function will not do anything if @self is not visible, or if
7335 * the actor is inside an invisible part of the scenegraph.
7337 * Also be aware that painting is a NOP for actors with an opacity of
7340 * When you are implementing a custom actor you must queue a redraw
7341 * whenever some private state changes that will affect painting or
7342 * picking of your actor.
7345 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7346 ClutterRedrawFlags flags,
7347 ClutterPaintVolume *volume)
7349 _clutter_actor_queue_redraw_full (self,
7351 volume, /* clip volume */
7356 _clutter_actor_queue_only_relayout (ClutterActor *self)
7358 ClutterActorPrivate *priv = self->priv;
7360 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7363 if (priv->needs_width_request &&
7364 priv->needs_height_request &&
7365 priv->needs_allocation)
7366 return; /* save some cpu cycles */
7368 #if CLUTTER_ENABLE_DEBUG
7369 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7371 g_warning ("The actor '%s' is currently inside an allocation "
7372 "cycle; calling clutter_actor_queue_relayout() is "
7374 _clutter_actor_get_debug_name (self));
7376 #endif /* CLUTTER_ENABLE_DEBUG */
7378 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7382 * clutter_actor_queue_redraw_with_clip:
7383 * @self: a #ClutterActor
7384 * @clip: (allow-none): a rectangular clip region, or %NULL
7386 * Queues a redraw on @self limited to a specific, actor-relative
7389 * If @clip is %NULL this function is equivalent to
7390 * clutter_actor_queue_redraw().
7395 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7396 const cairo_rectangle_int_t *clip)
7398 ClutterPaintVolume volume;
7399 ClutterVertex origin;
7401 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7405 clutter_actor_queue_redraw (self);
7409 _clutter_paint_volume_init_static (&volume, self);
7415 clutter_paint_volume_set_origin (&volume, &origin);
7416 clutter_paint_volume_set_width (&volume, clip->width);
7417 clutter_paint_volume_set_height (&volume, clip->height);
7419 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7421 clutter_paint_volume_free (&volume);
7425 * clutter_actor_queue_relayout:
7426 * @self: A #ClutterActor
7428 * Indicates that the actor's size request or other layout-affecting
7429 * properties may have changed. This function is used inside #ClutterActor
7430 * subclass implementations, not by applications directly.
7432 * Queueing a new layout automatically queues a redraw as well.
7437 clutter_actor_queue_relayout (ClutterActor *self)
7439 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7441 _clutter_actor_queue_only_relayout (self);
7442 clutter_actor_queue_redraw (self);
7446 * clutter_actor_get_preferred_size:
7447 * @self: a #ClutterActor
7448 * @min_width_p: (out) (allow-none): return location for the minimum
7450 * @min_height_p: (out) (allow-none): return location for the minimum
7452 * @natural_width_p: (out) (allow-none): return location for the natural
7454 * @natural_height_p: (out) (allow-none): return location for the natural
7457 * Computes the preferred minimum and natural size of an actor, taking into
7458 * account the actor's geometry management (either height-for-width
7459 * or width-for-height).
7461 * The width and height used to compute the preferred height and preferred
7462 * width are the actor's natural ones.
7464 * If you need to control the height for the preferred width, or the width for
7465 * the preferred height, you should use clutter_actor_get_preferred_width()
7466 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7467 * geometry management using the #ClutterActor:request-mode property.
7472 clutter_actor_get_preferred_size (ClutterActor *self,
7473 gfloat *min_width_p,
7474 gfloat *min_height_p,
7475 gfloat *natural_width_p,
7476 gfloat *natural_height_p)
7478 ClutterActorPrivate *priv;
7479 gfloat min_width, min_height;
7480 gfloat natural_width, natural_height;
7482 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7486 min_width = min_height = 0;
7487 natural_width = natural_height = 0;
7489 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7491 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7492 clutter_actor_get_preferred_width (self, -1,
7495 clutter_actor_get_preferred_height (self, natural_width,
7501 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7502 clutter_actor_get_preferred_height (self, -1,
7505 clutter_actor_get_preferred_width (self, natural_height,
7511 *min_width_p = min_width;
7514 *min_height_p = min_height;
7516 if (natural_width_p)
7517 *natural_width_p = natural_width;
7519 if (natural_height_p)
7520 *natural_height_p = natural_height;
7525 * @align: a #ClutterActorAlign
7526 * @direction: a #ClutterTextDirection
7528 * Retrieves the correct alignment depending on the text direction
7530 * Return value: the effective alignment
7532 static ClutterActorAlign
7533 effective_align (ClutterActorAlign align,
7534 ClutterTextDirection direction)
7536 ClutterActorAlign res;
7540 case CLUTTER_ACTOR_ALIGN_START:
7541 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7542 ? CLUTTER_ACTOR_ALIGN_END
7543 : CLUTTER_ACTOR_ALIGN_START;
7546 case CLUTTER_ACTOR_ALIGN_END:
7547 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7548 ? CLUTTER_ACTOR_ALIGN_START
7549 : CLUTTER_ACTOR_ALIGN_END;
7561 adjust_for_margin (float margin_start,
7563 float *minimum_size,
7564 float *natural_size,
7565 float *allocated_start,
7566 float *allocated_end)
7568 *minimum_size -= (margin_start + margin_end);
7569 *natural_size -= (margin_start + margin_end);
7570 *allocated_start += margin_start;
7571 *allocated_end -= margin_end;
7575 adjust_for_alignment (ClutterActorAlign alignment,
7577 float *allocated_start,
7578 float *allocated_end)
7580 float allocated_size = *allocated_end - *allocated_start;
7584 case CLUTTER_ACTOR_ALIGN_FILL:
7588 case CLUTTER_ACTOR_ALIGN_START:
7590 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7593 case CLUTTER_ACTOR_ALIGN_END:
7594 if (allocated_size > natural_size)
7596 *allocated_start += (allocated_size - natural_size);
7597 *allocated_end = *allocated_start + natural_size;
7601 case CLUTTER_ACTOR_ALIGN_CENTER:
7602 if (allocated_size > natural_size)
7604 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7605 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7612 * clutter_actor_adjust_width:
7613 * @self: a #ClutterActor
7614 * @minimum_width: (inout): the actor's preferred minimum width, which
7615 * will be adjusted depending on the margin
7616 * @natural_width: (inout): the actor's preferred natural width, which
7617 * will be adjusted depending on the margin
7618 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7619 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7621 * Adjusts the preferred and allocated position and size of an actor,
7622 * depending on the margin and alignment properties.
7625 clutter_actor_adjust_width (ClutterActor *self,
7626 gfloat *minimum_width,
7627 gfloat *natural_width,
7628 gfloat *adjusted_x1,
7629 gfloat *adjusted_x2)
7631 ClutterTextDirection text_dir;
7632 const ClutterLayoutInfo *info;
7634 info = _clutter_actor_get_layout_info_or_defaults (self);
7635 text_dir = clutter_actor_get_text_direction (self);
7637 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7639 /* this will tweak natural_width to remove the margin, so that
7640 * adjust_for_alignment() will use the correct size
7642 adjust_for_margin (info->margin.left, info->margin.right,
7643 minimum_width, natural_width,
7644 adjusted_x1, adjusted_x2);
7646 adjust_for_alignment (effective_align (info->x_align, text_dir),
7648 adjusted_x1, adjusted_x2);
7652 * clutter_actor_adjust_height:
7653 * @self: a #ClutterActor
7654 * @minimum_height: (inout): the actor's preferred minimum height, which
7655 * will be adjusted depending on the margin
7656 * @natural_height: (inout): the actor's preferred natural height, which
7657 * will be adjusted depending on the margin
7658 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7659 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7661 * Adjusts the preferred and allocated position and size of an actor,
7662 * depending on the margin and alignment properties.
7665 clutter_actor_adjust_height (ClutterActor *self,
7666 gfloat *minimum_height,
7667 gfloat *natural_height,
7668 gfloat *adjusted_y1,
7669 gfloat *adjusted_y2)
7671 const ClutterLayoutInfo *info;
7673 info = _clutter_actor_get_layout_info_or_defaults (self);
7675 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7677 /* this will tweak natural_height to remove the margin, so that
7678 * adjust_for_alignment() will use the correct size
7680 adjust_for_margin (info->margin.top, info->margin.bottom,
7681 minimum_height, natural_height,
7685 /* we don't use effective_align() here, because text direction
7686 * only affects the horizontal axis
7688 adjust_for_alignment (info->y_align,
7695 /* looks for a cached size request for this for_size. If not
7696 * found, returns the oldest entry so it can be overwritten */
7698 _clutter_actor_get_cached_size_request (gfloat for_size,
7699 SizeRequest *cached_size_requests,
7700 SizeRequest **result)
7704 *result = &cached_size_requests[0];
7706 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7710 sr = &cached_size_requests[i];
7713 sr->for_size == for_size)
7715 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7719 else if (sr->age < (*result)->age)
7725 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7731 * clutter_actor_get_preferred_width:
7732 * @self: A #ClutterActor
7733 * @for_height: available height when computing the preferred width,
7734 * or a negative value to indicate that no height is defined
7735 * @min_width_p: (out) (allow-none): return location for minimum width,
7737 * @natural_width_p: (out) (allow-none): return location for the natural
7740 * Computes the requested minimum and natural widths for an actor,
7741 * optionally depending on the specified height, or if they are
7742 * already computed, returns the cached values.
7744 * An actor may not get its request - depending on the layout
7745 * manager that's in effect.
7747 * A request should not incorporate the actor's scale or anchor point;
7748 * those transformations do not affect layout, only rendering.
7753 clutter_actor_get_preferred_width (ClutterActor *self,
7755 gfloat *min_width_p,
7756 gfloat *natural_width_p)
7758 float request_min_width, request_natural_width;
7759 SizeRequest *cached_size_request;
7760 const ClutterLayoutInfo *info;
7761 ClutterActorPrivate *priv;
7762 gboolean found_in_cache;
7764 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7768 info = _clutter_actor_get_layout_info_or_defaults (self);
7770 /* we shortcircuit the case of a fixed size set using set_width() */
7771 if (priv->min_width_set && priv->natural_width_set)
7773 if (min_width_p != NULL)
7774 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7776 if (natural_width_p != NULL)
7777 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7782 /* the remaining cases are:
7784 * - either min_width or natural_width have been set
7785 * - neither min_width or natural_width have been set
7787 * in both cases, we go through the cache (and through the actor in case
7788 * of cache misses) and determine the authoritative value depending on
7792 if (!priv->needs_width_request)
7795 _clutter_actor_get_cached_size_request (for_height,
7796 priv->width_requests,
7797 &cached_size_request);
7801 /* if the actor needs a width request we use the first slot */
7802 found_in_cache = FALSE;
7803 cached_size_request = &priv->width_requests[0];
7806 if (!found_in_cache)
7808 gfloat minimum_width, natural_width;
7809 ClutterActorClass *klass;
7811 minimum_width = natural_width = 0;
7813 /* adjust for the margin */
7814 if (for_height >= 0)
7816 for_height -= (info->margin.top + info->margin.bottom);
7821 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7823 klass = CLUTTER_ACTOR_GET_CLASS (self);
7824 klass->get_preferred_width (self, for_height,
7828 /* adjust for the margin */
7829 minimum_width += (info->margin.left + info->margin.right);
7830 natural_width += (info->margin.left + info->margin.right);
7832 /* Due to accumulated float errors, it's better not to warn
7833 * on this, but just fix it.
7835 if (natural_width < minimum_width)
7836 natural_width = minimum_width;
7838 cached_size_request->min_size = minimum_width;
7839 cached_size_request->natural_size = natural_width;
7840 cached_size_request->for_size = for_height;
7841 cached_size_request->age = priv->cached_width_age;
7843 priv->cached_width_age += 1;
7844 priv->needs_width_request = FALSE;
7847 if (!priv->min_width_set)
7848 request_min_width = cached_size_request->min_size;
7850 request_min_width = info->min_width;
7852 if (!priv->natural_width_set)
7853 request_natural_width = cached_size_request->natural_size;
7855 request_natural_width = info->natural_width;
7858 *min_width_p = request_min_width;
7860 if (natural_width_p)
7861 *natural_width_p = request_natural_width;
7865 * clutter_actor_get_preferred_height:
7866 * @self: A #ClutterActor
7867 * @for_width: available width to assume in computing desired height,
7868 * or a negative value to indicate that no width is defined
7869 * @min_height_p: (out) (allow-none): return location for minimum height,
7871 * @natural_height_p: (out) (allow-none): return location for natural
7874 * Computes the requested minimum and natural heights for an actor,
7875 * or if they are already computed, returns the cached values.
7877 * An actor may not get its request - depending on the layout
7878 * manager that's in effect.
7880 * A request should not incorporate the actor's scale or anchor point;
7881 * those transformations do not affect layout, only rendering.
7886 clutter_actor_get_preferred_height (ClutterActor *self,
7888 gfloat *min_height_p,
7889 gfloat *natural_height_p)
7891 float request_min_height, request_natural_height;
7892 SizeRequest *cached_size_request;
7893 const ClutterLayoutInfo *info;
7894 ClutterActorPrivate *priv;
7895 gboolean found_in_cache;
7897 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7901 info = _clutter_actor_get_layout_info_or_defaults (self);
7903 /* we shortcircuit the case of a fixed size set using set_height() */
7904 if (priv->min_height_set && priv->natural_height_set)
7906 if (min_height_p != NULL)
7907 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7909 if (natural_height_p != NULL)
7910 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7915 /* the remaining cases are:
7917 * - either min_height or natural_height have been set
7918 * - neither min_height or natural_height have been set
7920 * in both cases, we go through the cache (and through the actor in case
7921 * of cache misses) and determine the authoritative value depending on
7925 if (!priv->needs_height_request)
7928 _clutter_actor_get_cached_size_request (for_width,
7929 priv->height_requests,
7930 &cached_size_request);
7934 found_in_cache = FALSE;
7935 cached_size_request = &priv->height_requests[0];
7938 if (!found_in_cache)
7940 gfloat minimum_height, natural_height;
7941 ClutterActorClass *klass;
7943 minimum_height = natural_height = 0;
7945 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7947 /* adjust for margin */
7950 for_width -= (info->margin.left + info->margin.right);
7955 klass = CLUTTER_ACTOR_GET_CLASS (self);
7956 klass->get_preferred_height (self, for_width,
7960 /* adjust for margin */
7961 minimum_height += (info->margin.top + info->margin.bottom);
7962 natural_height += (info->margin.top + info->margin.bottom);
7964 /* Due to accumulated float errors, it's better not to warn
7965 * on this, but just fix it.
7967 if (natural_height < minimum_height)
7968 natural_height = minimum_height;
7970 cached_size_request->min_size = minimum_height;
7971 cached_size_request->natural_size = natural_height;
7972 cached_size_request->for_size = for_width;
7973 cached_size_request->age = priv->cached_height_age;
7975 priv->cached_height_age += 1;
7976 priv->needs_height_request = FALSE;
7979 if (!priv->min_height_set)
7980 request_min_height = cached_size_request->min_size;
7982 request_min_height = info->min_height;
7984 if (!priv->natural_height_set)
7985 request_natural_height = cached_size_request->natural_size;
7987 request_natural_height = info->natural_height;
7990 *min_height_p = request_min_height;
7992 if (natural_height_p)
7993 *natural_height_p = request_natural_height;
7997 * clutter_actor_get_allocation_box:
7998 * @self: A #ClutterActor
7999 * @box: (out): the function fills this in with the actor's allocation
8001 * Gets the layout box an actor has been assigned. The allocation can
8002 * only be assumed valid inside a paint() method; anywhere else, it
8003 * may be out-of-date.
8005 * An allocation does not incorporate the actor's scale or anchor point;
8006 * those transformations do not affect layout, only rendering.
8008 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8009 * of functions inside the implementation of the get_preferred_width()
8010 * or get_preferred_height() virtual functions.</note>
8015 clutter_actor_get_allocation_box (ClutterActor *self,
8016 ClutterActorBox *box)
8018 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8020 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8021 * which limits calling get_allocation to inside paint() basically; or
8022 * we can 2) force a layout, which could be expensive if someone calls
8023 * get_allocation somewhere silly; or we can 3) just return the latest
8024 * value, allowing it to be out-of-date, and assume people know what
8027 * The least-surprises approach that keeps existing code working is
8028 * likely to be 2). People can end up doing some inefficient things,
8029 * though, and in general code that requires 2) is probably broken.
8032 /* this implements 2) */
8033 if (G_UNLIKELY (self->priv->needs_allocation))
8035 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8037 /* do not queue a relayout on an unparented actor */
8039 _clutter_stage_maybe_relayout (stage);
8042 /* commenting out the code above and just keeping this assigment
8045 *box = self->priv->allocation;
8049 * clutter_actor_get_allocation_geometry:
8050 * @self: A #ClutterActor
8051 * @geom: (out): allocation geometry in pixels
8053 * Gets the layout box an actor has been assigned. The allocation can
8054 * only be assumed valid inside a paint() method; anywhere else, it
8055 * may be out-of-date.
8057 * An allocation does not incorporate the actor's scale or anchor point;
8058 * those transformations do not affect layout, only rendering.
8060 * The returned rectangle is in pixels.
8065 clutter_actor_get_allocation_geometry (ClutterActor *self,
8066 ClutterGeometry *geom)
8068 ClutterActorBox box;
8070 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8071 g_return_if_fail (geom != NULL);
8073 clutter_actor_get_allocation_box (self, &box);
8075 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8076 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8077 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8078 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8082 clutter_actor_update_constraints (ClutterActor *self,
8083 ClutterActorBox *allocation)
8085 ClutterActorPrivate *priv = self->priv;
8086 const GList *constraints, *l;
8088 if (priv->constraints == NULL)
8091 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8092 for (l = constraints; l != NULL; l = l->next)
8094 ClutterConstraint *constraint = l->data;
8095 ClutterActorMeta *meta = l->data;
8097 if (clutter_actor_meta_get_enabled (meta))
8099 _clutter_constraint_update_allocation (constraint,
8107 * clutter_actor_adjust_allocation:
8108 * @self: a #ClutterActor
8109 * @allocation: (inout): the allocation to adjust
8111 * Adjusts the passed allocation box taking into account the actor's
8112 * layout information, like alignment, expansion, and margin.
8115 clutter_actor_adjust_allocation (ClutterActor *self,
8116 ClutterActorBox *allocation)
8118 ClutterActorBox adj_allocation;
8119 float alloc_width, alloc_height;
8120 float min_width, min_height;
8121 float nat_width, nat_height;
8122 ClutterRequestMode req_mode;
8124 adj_allocation = *allocation;
8126 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8128 /* we want to hit the cache, so we use the public API */
8129 req_mode = clutter_actor_get_request_mode (self);
8131 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8133 clutter_actor_get_preferred_width (self, -1,
8136 clutter_actor_get_preferred_height (self, alloc_width,
8140 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8142 clutter_actor_get_preferred_height (self, -1,
8145 clutter_actor_get_preferred_height (self, alloc_height,
8150 #ifdef CLUTTER_ENABLE_DEBUG
8151 /* warn about underallocations */
8152 if (_clutter_diagnostic_enabled () &&
8153 (floorf (min_width - alloc_width) > 0 ||
8154 floorf (min_height - alloc_height) > 0))
8156 ClutterActor *parent = clutter_actor_get_parent (self);
8158 /* the only actors that are allowed to be underallocated are the Stage,
8159 * as it doesn't have an implicit size, and Actors that specifically
8160 * told us that they want to opt-out from layout control mechanisms
8161 * through the NO_LAYOUT escape hatch.
8163 if (parent != NULL &&
8164 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8166 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8167 "of %.2f x %.2f from its parent actor '%s', but its "
8168 "requested minimum size is of %.2f x %.2f",
8169 _clutter_actor_get_debug_name (self),
8170 alloc_width, alloc_height,
8171 _clutter_actor_get_debug_name (parent),
8172 min_width, min_height);
8177 clutter_actor_adjust_width (self,
8181 &adj_allocation.x2);
8183 clutter_actor_adjust_height (self,
8187 &adj_allocation.y2);
8189 /* we maintain the invariant that an allocation cannot be adjusted
8190 * to be outside the parent-given box
8192 if (adj_allocation.x1 < allocation->x1 ||
8193 adj_allocation.y1 < allocation->y1 ||
8194 adj_allocation.x2 > allocation->x2 ||
8195 adj_allocation.y2 > allocation->y2)
8197 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8198 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8199 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8200 _clutter_actor_get_debug_name (self),
8201 adj_allocation.x1, adj_allocation.y1,
8202 adj_allocation.x2 - adj_allocation.x1,
8203 adj_allocation.y2 - adj_allocation.y1,
8204 allocation->x1, allocation->y1,
8205 allocation->x2 - allocation->x1,
8206 allocation->y2 - allocation->y1);
8210 *allocation = adj_allocation;
8214 * clutter_actor_allocate:
8215 * @self: A #ClutterActor
8216 * @box: new allocation of the actor, in parent-relative coordinates
8217 * @flags: flags that control the allocation
8219 * Called by the parent of an actor to assign the actor its size.
8220 * Should never be called by applications (except when implementing
8221 * a container or layout manager).
8223 * Actors can know from their allocation box whether they have moved
8224 * with respect to their parent actor. The @flags parameter describes
8225 * additional information about the allocation, for instance whether
8226 * the parent has moved with respect to the stage, for example because
8227 * a grandparent's origin has moved.
8232 clutter_actor_allocate (ClutterActor *self,
8233 const ClutterActorBox *box,
8234 ClutterAllocationFlags flags)
8236 ClutterActorPrivate *priv;
8237 ClutterActorClass *klass;
8238 ClutterActorBox old_allocation, real_allocation;
8239 gboolean origin_changed, child_moved, size_changed;
8240 gboolean stage_allocation_changed;
8242 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8243 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8245 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8246 "which isn't a descendent of the stage!\n",
8247 self, _clutter_actor_get_debug_name (self));
8253 old_allocation = priv->allocation;
8254 real_allocation = *box;
8256 /* constraints are allowed to modify the allocation only here; we do
8257 * this prior to all the other checks so that we can bail out if the
8258 * allocation did not change
8260 clutter_actor_update_constraints (self, &real_allocation);
8262 /* adjust the allocation depending on the align/margin properties */
8263 clutter_actor_adjust_allocation (self, &real_allocation);
8265 if (real_allocation.x2 < real_allocation.x1 ||
8266 real_allocation.y2 < real_allocation.y1)
8268 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8269 _clutter_actor_get_debug_name (self),
8270 real_allocation.x2 - real_allocation.x1,
8271 real_allocation.y2 - real_allocation.y1);
8274 /* we allow 0-sized actors, but not negative-sized ones */
8275 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8276 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8278 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8280 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8281 real_allocation.y1 != old_allocation.y1);
8283 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8284 real_allocation.y2 != old_allocation.y2);
8286 if (origin_changed || child_moved || size_changed)
8287 stage_allocation_changed = TRUE;
8289 stage_allocation_changed = FALSE;
8291 /* If we get an allocation "out of the blue"
8292 * (we did not queue relayout), then we want to
8293 * ignore it. But if we have needs_allocation set,
8294 * we want to guarantee that allocate() virtual
8295 * method is always called, i.e. that queue_relayout()
8296 * always results in an allocate() invocation on
8299 * The optimization here is to avoid re-allocating
8300 * actors that did not queue relayout and were
8303 if (!priv->needs_allocation && !stage_allocation_changed)
8305 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8309 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8310 * clutter_actor_allocate(), it indicates whether the parent has its
8311 * absolute origin moved; when passed in to ClutterActor::allocate()
8312 * virtual method though, it indicates whether the child has its
8313 * absolute origin moved. So we set it when child_moved is TRUE
8316 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8318 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8320 klass = CLUTTER_ACTOR_GET_CLASS (self);
8321 klass->allocate (self, &real_allocation, flags);
8323 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8325 if (stage_allocation_changed)
8326 clutter_actor_queue_redraw (self);
8330 * clutter_actor_set_allocation:
8331 * @self: a #ClutterActor
8332 * @box: a #ClutterActorBox
8333 * @flags: allocation flags
8335 * Stores the allocation of @self as defined by @box.
8337 * This function can only be called from within the implementation of
8338 * the #ClutterActorClass.allocate() virtual function.
8340 * The allocation should have been adjusted to take into account constraints,
8341 * alignment, and margin properties. If you are implementing a #ClutterActor
8342 * subclass that provides its own layout management policy for its children
8343 * instead of using a #ClutterLayoutManager delegate, you should not call
8344 * this function on the children of @self; instead, you should call
8345 * clutter_actor_allocate(), which will adjust the allocation box for
8348 * This function should only be used by subclasses of #ClutterActor
8349 * that wish to store their allocation but cannot chain up to the
8350 * parent's implementation; the default implementation of the
8351 * #ClutterActorClass.allocate() virtual function will call this
8354 * It is important to note that, while chaining up was the recommended
8355 * behaviour for #ClutterActor subclasses prior to the introduction of
8356 * this function, it is recommended to call clutter_actor_set_allocation()
8359 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8360 * to handle the allocation of its children, this function will call
8361 * the clutter_layout_manager_allocate() function only if the
8362 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8363 * expected that the subclass will call clutter_layout_manager_allocate()
8364 * by itself. For instance, the following code:
8368 * my_actor_allocate (ClutterActor *actor,
8369 * const ClutterActorBox *allocation,
8370 * ClutterAllocationFlags flags)
8372 * ClutterActorBox new_alloc;
8373 * ClutterAllocationFlags new_flags;
8375 * adjust_allocation (allocation, &new_alloc);
8377 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8379 * /* this will use the layout manager set on the actor */
8380 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8384 * is equivalent to this:
8388 * my_actor_allocate (ClutterActor *actor,
8389 * const ClutterActorBox *allocation,
8390 * ClutterAllocationFlags flags)
8392 * ClutterLayoutManager *layout;
8393 * ClutterActorBox new_alloc;
8395 * adjust_allocation (allocation, &new_alloc);
8397 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8399 * layout = clutter_actor_get_layout_manager (actor);
8400 * clutter_layout_manager_allocate (layout,
8401 * CLUTTER_CONTAINER (actor),
8410 clutter_actor_set_allocation (ClutterActor *self,
8411 const ClutterActorBox *box,
8412 ClutterAllocationFlags flags)
8414 ClutterActorPrivate *priv;
8417 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8418 g_return_if_fail (box != NULL);
8420 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8422 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8423 "can only be called from within the implementation of "
8424 "the ClutterActor::allocate() virtual function.");
8430 g_object_freeze_notify (G_OBJECT (self));
8432 changed = clutter_actor_set_allocation_internal (self, box, flags);
8434 /* we allocate our children before we notify changes in our geometry,
8435 * so that people connecting to properties will be able to get valid
8436 * data out of the sub-tree of the scene graph that has this actor at
8439 clutter_actor_maybe_layout_children (self, box, flags);
8443 ClutterActorBox signal_box = priv->allocation;
8444 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8446 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8451 g_object_thaw_notify (G_OBJECT (self));
8455 * clutter_actor_set_geometry:
8456 * @self: A #ClutterActor
8457 * @geometry: A #ClutterGeometry
8459 * Sets the actor's fixed position and forces its minimum and natural
8460 * size, in pixels. This means the untransformed actor will have the
8461 * given geometry. This is the same as calling clutter_actor_set_position()
8462 * and clutter_actor_set_size().
8464 * Deprecated: 1.10: Use clutter_actor_set_position() and
8465 * clutter_actor_set_size() instead.
8468 clutter_actor_set_geometry (ClutterActor *self,
8469 const ClutterGeometry *geometry)
8471 g_object_freeze_notify (G_OBJECT (self));
8473 clutter_actor_set_position (self, geometry->x, geometry->y);
8474 clutter_actor_set_size (self, geometry->width, geometry->height);
8476 g_object_thaw_notify (G_OBJECT (self));
8480 * clutter_actor_get_geometry:
8481 * @self: A #ClutterActor
8482 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8484 * Gets the size and position of an actor relative to its parent
8485 * actor. This is the same as calling clutter_actor_get_position() and
8486 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8487 * requested size and position if the actor's allocation is invalid.
8489 * Deprecated: 1.10: Use clutter_actor_get_position() and
8490 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8494 clutter_actor_get_geometry (ClutterActor *self,
8495 ClutterGeometry *geometry)
8497 gfloat x, y, width, height;
8499 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8500 g_return_if_fail (geometry != NULL);
8502 clutter_actor_get_position (self, &x, &y);
8503 clutter_actor_get_size (self, &width, &height);
8505 geometry->x = (int) x;
8506 geometry->y = (int) y;
8507 geometry->width = (int) width;
8508 geometry->height = (int) height;
8512 * clutter_actor_set_position:
8513 * @self: A #ClutterActor
8514 * @x: New left position of actor in pixels.
8515 * @y: New top position of actor in pixels.
8517 * Sets the actor's fixed position in pixels relative to any parent
8520 * If a layout manager is in use, this position will override the
8521 * layout manager and force a fixed position.
8524 clutter_actor_set_position (ClutterActor *self,
8528 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8530 g_object_freeze_notify (G_OBJECT (self));
8532 clutter_actor_set_x (self, x);
8533 clutter_actor_set_y (self, y);
8535 g_object_thaw_notify (G_OBJECT (self));
8539 * clutter_actor_get_fixed_position_set:
8540 * @self: A #ClutterActor
8542 * Checks whether an actor has a fixed position set (and will thus be
8543 * unaffected by any layout manager).
8545 * Return value: %TRUE if the fixed position is set on the actor
8550 clutter_actor_get_fixed_position_set (ClutterActor *self)
8552 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8554 return self->priv->position_set;
8558 * clutter_actor_set_fixed_position_set:
8559 * @self: A #ClutterActor
8560 * @is_set: whether to use fixed position
8562 * Sets whether an actor has a fixed position set (and will thus be
8563 * unaffected by any layout manager).
8568 clutter_actor_set_fixed_position_set (ClutterActor *self,
8571 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8573 if (self->priv->position_set == (is_set != FALSE))
8576 self->priv->position_set = is_set != FALSE;
8577 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8579 clutter_actor_queue_relayout (self);
8583 * clutter_actor_move_by:
8584 * @self: A #ClutterActor
8585 * @dx: Distance to move Actor on X axis.
8586 * @dy: Distance to move Actor on Y axis.
8588 * Moves an actor by the specified distance relative to its current
8589 * position in pixels.
8591 * This function modifies the fixed position of an actor and thus removes
8592 * it from any layout management. Another way to move an actor is with an
8593 * anchor point, see clutter_actor_set_anchor_point().
8598 clutter_actor_move_by (ClutterActor *self,
8602 const ClutterLayoutInfo *info;
8605 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8607 info = _clutter_actor_get_layout_info_or_defaults (self);
8611 clutter_actor_set_position (self, x + dx, y + dy);
8615 clutter_actor_set_min_width (ClutterActor *self,
8618 ClutterActorPrivate *priv = self->priv;
8619 ClutterActorBox old = { 0, };
8620 ClutterLayoutInfo *info;
8622 /* if we are setting the size on a top-level actor and the
8623 * backend only supports static top-levels (e.g. framebuffers)
8624 * then we ignore the passed value and we override it with
8625 * the stage implementation's preferred size.
8627 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8628 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8631 info = _clutter_actor_get_layout_info (self);
8633 if (priv->min_width_set && min_width == info->min_width)
8636 g_object_freeze_notify (G_OBJECT (self));
8638 clutter_actor_store_old_geometry (self, &old);
8640 info->min_width = min_width;
8641 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8642 clutter_actor_set_min_width_set (self, TRUE);
8644 clutter_actor_notify_if_geometry_changed (self, &old);
8646 g_object_thaw_notify (G_OBJECT (self));
8648 clutter_actor_queue_relayout (self);
8652 clutter_actor_set_min_height (ClutterActor *self,
8656 ClutterActorPrivate *priv = self->priv;
8657 ClutterActorBox old = { 0, };
8658 ClutterLayoutInfo *info;
8660 /* if we are setting the size on a top-level actor and the
8661 * backend only supports static top-levels (e.g. framebuffers)
8662 * then we ignore the passed value and we override it with
8663 * the stage implementation's preferred size.
8665 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8666 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8669 info = _clutter_actor_get_layout_info (self);
8671 if (priv->min_height_set && min_height == info->min_height)
8674 g_object_freeze_notify (G_OBJECT (self));
8676 clutter_actor_store_old_geometry (self, &old);
8678 info->min_height = min_height;
8679 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8680 clutter_actor_set_min_height_set (self, TRUE);
8682 clutter_actor_notify_if_geometry_changed (self, &old);
8684 g_object_thaw_notify (G_OBJECT (self));
8686 clutter_actor_queue_relayout (self);
8690 clutter_actor_set_natural_width (ClutterActor *self,
8691 gfloat natural_width)
8693 ClutterActorPrivate *priv = self->priv;
8694 ClutterActorBox old = { 0, };
8695 ClutterLayoutInfo *info;
8697 /* if we are setting the size on a top-level actor and the
8698 * backend only supports static top-levels (e.g. framebuffers)
8699 * then we ignore the passed value and we override it with
8700 * the stage implementation's preferred size.
8702 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8703 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8706 info = _clutter_actor_get_layout_info (self);
8708 if (priv->natural_width_set && natural_width == info->natural_width)
8711 g_object_freeze_notify (G_OBJECT (self));
8713 clutter_actor_store_old_geometry (self, &old);
8715 info->natural_width = natural_width;
8716 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8717 clutter_actor_set_natural_width_set (self, TRUE);
8719 clutter_actor_notify_if_geometry_changed (self, &old);
8721 g_object_thaw_notify (G_OBJECT (self));
8723 clutter_actor_queue_relayout (self);
8727 clutter_actor_set_natural_height (ClutterActor *self,
8728 gfloat natural_height)
8730 ClutterActorPrivate *priv = self->priv;
8731 ClutterActorBox old = { 0, };
8732 ClutterLayoutInfo *info;
8734 /* if we are setting the size on a top-level actor and the
8735 * backend only supports static top-levels (e.g. framebuffers)
8736 * then we ignore the passed value and we override it with
8737 * the stage implementation's preferred size.
8739 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8740 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8743 info = _clutter_actor_get_layout_info (self);
8745 if (priv->natural_height_set && natural_height == info->natural_height)
8748 g_object_freeze_notify (G_OBJECT (self));
8750 clutter_actor_store_old_geometry (self, &old);
8752 info->natural_height = natural_height;
8753 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8754 clutter_actor_set_natural_height_set (self, TRUE);
8756 clutter_actor_notify_if_geometry_changed (self, &old);
8758 g_object_thaw_notify (G_OBJECT (self));
8760 clutter_actor_queue_relayout (self);
8764 clutter_actor_set_min_width_set (ClutterActor *self,
8765 gboolean use_min_width)
8767 ClutterActorPrivate *priv = self->priv;
8768 ClutterActorBox old = { 0, };
8770 if (priv->min_width_set == (use_min_width != FALSE))
8773 clutter_actor_store_old_geometry (self, &old);
8775 priv->min_width_set = use_min_width != FALSE;
8776 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8778 clutter_actor_notify_if_geometry_changed (self, &old);
8780 clutter_actor_queue_relayout (self);
8784 clutter_actor_set_min_height_set (ClutterActor *self,
8785 gboolean use_min_height)
8787 ClutterActorPrivate *priv = self->priv;
8788 ClutterActorBox old = { 0, };
8790 if (priv->min_height_set == (use_min_height != FALSE))
8793 clutter_actor_store_old_geometry (self, &old);
8795 priv->min_height_set = use_min_height != FALSE;
8796 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8798 clutter_actor_notify_if_geometry_changed (self, &old);
8800 clutter_actor_queue_relayout (self);
8804 clutter_actor_set_natural_width_set (ClutterActor *self,
8805 gboolean use_natural_width)
8807 ClutterActorPrivate *priv = self->priv;
8808 ClutterActorBox old = { 0, };
8810 if (priv->natural_width_set == (use_natural_width != FALSE))
8813 clutter_actor_store_old_geometry (self, &old);
8815 priv->natural_width_set = use_natural_width != FALSE;
8816 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8818 clutter_actor_notify_if_geometry_changed (self, &old);
8820 clutter_actor_queue_relayout (self);
8824 clutter_actor_set_natural_height_set (ClutterActor *self,
8825 gboolean use_natural_height)
8827 ClutterActorPrivate *priv = self->priv;
8828 ClutterActorBox old = { 0, };
8830 if (priv->natural_height_set == (use_natural_height != FALSE))
8833 clutter_actor_store_old_geometry (self, &old);
8835 priv->natural_height_set = use_natural_height != FALSE;
8836 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8838 clutter_actor_notify_if_geometry_changed (self, &old);
8840 clutter_actor_queue_relayout (self);
8844 * clutter_actor_set_request_mode:
8845 * @self: a #ClutterActor
8846 * @mode: the request mode
8848 * Sets the geometry request mode of @self.
8850 * The @mode determines the order for invoking
8851 * clutter_actor_get_preferred_width() and
8852 * clutter_actor_get_preferred_height()
8857 clutter_actor_set_request_mode (ClutterActor *self,
8858 ClutterRequestMode mode)
8860 ClutterActorPrivate *priv;
8862 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8866 if (priv->request_mode == mode)
8869 priv->request_mode = mode;
8871 priv->needs_width_request = TRUE;
8872 priv->needs_height_request = TRUE;
8874 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8876 clutter_actor_queue_relayout (self);
8880 * clutter_actor_get_request_mode:
8881 * @self: a #ClutterActor
8883 * Retrieves the geometry request mode of @self
8885 * Return value: the request mode for the actor
8890 clutter_actor_get_request_mode (ClutterActor *self)
8892 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8893 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8895 return self->priv->request_mode;
8898 /* variant of set_width() without checks and without notification
8899 * freeze+thaw, for internal usage only
8902 clutter_actor_set_width_internal (ClutterActor *self,
8907 /* the Stage will use the :min-width to control the minimum
8908 * width to be resized to, so we should not be setting it
8909 * along with the :natural-width
8911 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8912 clutter_actor_set_min_width (self, width);
8914 clutter_actor_set_natural_width (self, width);
8918 /* we only unset the :natural-width for the Stage */
8919 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8920 clutter_actor_set_min_width_set (self, FALSE);
8922 clutter_actor_set_natural_width_set (self, FALSE);
8926 /* variant of set_height() without checks and without notification
8927 * freeze+thaw, for internal usage only
8930 clutter_actor_set_height_internal (ClutterActor *self,
8935 /* see the comment above in set_width_internal() */
8936 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8937 clutter_actor_set_min_height (self, height);
8939 clutter_actor_set_natural_height (self, height);
8943 /* see the comment above in set_width_internal() */
8944 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8945 clutter_actor_set_min_height_set (self, FALSE);
8947 clutter_actor_set_natural_height_set (self, FALSE);
8952 * clutter_actor_set_size:
8953 * @self: A #ClutterActor
8954 * @width: New width of actor in pixels, or -1
8955 * @height: New height of actor in pixels, or -1
8957 * Sets the actor's size request in pixels. This overrides any
8958 * "normal" size request the actor would have. For example
8959 * a text actor might normally request the size of the text;
8960 * this function would force a specific size instead.
8962 * If @width and/or @height are -1 the actor will use its
8963 * "normal" size request instead of overriding it, i.e.
8964 * you can "unset" the size with -1.
8966 * This function sets or unsets both the minimum and natural size.
8969 clutter_actor_set_size (ClutterActor *self,
8973 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8975 g_object_freeze_notify (G_OBJECT (self));
8977 clutter_actor_set_width (self, width);
8978 clutter_actor_set_height (self, height);
8980 g_object_thaw_notify (G_OBJECT (self));
8984 * clutter_actor_get_size:
8985 * @self: A #ClutterActor
8986 * @width: (out) (allow-none): return location for the width, or %NULL.
8987 * @height: (out) (allow-none): return location for the height, or %NULL.
8989 * This function tries to "do what you mean" and return
8990 * the size an actor will have. If the actor has a valid
8991 * allocation, the allocation will be returned; otherwise,
8992 * the actors natural size request will be returned.
8994 * If you care whether you get the request vs. the allocation, you
8995 * should probably call a different function like
8996 * clutter_actor_get_allocation_box() or
8997 * clutter_actor_get_preferred_width().
9002 clutter_actor_get_size (ClutterActor *self,
9006 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9009 *width = clutter_actor_get_width (self);
9012 *height = clutter_actor_get_height (self);
9016 * clutter_actor_get_position:
9017 * @self: a #ClutterActor
9018 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9019 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9021 * This function tries to "do what you mean" and tell you where the
9022 * actor is, prior to any transformations. Retrieves the fixed
9023 * position of an actor in pixels, if one has been set; otherwise, if
9024 * the allocation is valid, returns the actor's allocated position;
9025 * otherwise, returns 0,0.
9027 * The returned position is in pixels.
9032 clutter_actor_get_position (ClutterActor *self,
9036 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9039 *x = clutter_actor_get_x (self);
9042 *y = clutter_actor_get_y (self);
9046 * clutter_actor_get_transformed_position:
9047 * @self: A #ClutterActor
9048 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9049 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9051 * Gets the absolute position of an actor, in pixels relative to the stage.
9056 clutter_actor_get_transformed_position (ClutterActor *self,
9063 v1.x = v1.y = v1.z = 0;
9064 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9074 * clutter_actor_get_transformed_size:
9075 * @self: A #ClutterActor
9076 * @width: (out) (allow-none): return location for the width, or %NULL
9077 * @height: (out) (allow-none): return location for the height, or %NULL
9079 * Gets the absolute size of an actor in pixels, taking into account the
9082 * If the actor has a valid allocation, the allocated size will be used.
9083 * If the actor has not a valid allocation then the preferred size will
9084 * be transformed and returned.
9086 * If you want the transformed allocation, see
9087 * clutter_actor_get_abs_allocation_vertices() instead.
9089 * <note>When the actor (or one of its ancestors) is rotated around the
9090 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9091 * as a generic quadrangle; in that case this function returns the size
9092 * of the smallest rectangle that encapsulates the entire quad. Please
9093 * note that in this case no assumptions can be made about the relative
9094 * position of this envelope to the absolute position of the actor, as
9095 * returned by clutter_actor_get_transformed_position(); if you need this
9096 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9097 * to get the coords of the actual quadrangle.</note>
9102 clutter_actor_get_transformed_size (ClutterActor *self,
9106 ClutterActorPrivate *priv;
9108 gfloat x_min, x_max, y_min, y_max;
9111 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9115 /* if the actor hasn't been allocated yet, get the preferred
9116 * size and transform that
9118 if (priv->needs_allocation)
9120 gfloat natural_width, natural_height;
9121 ClutterActorBox box;
9123 /* Make a fake allocation to transform.
9125 * NB: _clutter_actor_transform_and_project_box expects a box in
9126 * the actor's coordinate space... */
9131 natural_width = natural_height = 0;
9132 clutter_actor_get_preferred_size (self, NULL, NULL,
9136 box.x2 = natural_width;
9137 box.y2 = natural_height;
9139 _clutter_actor_transform_and_project_box (self, &box, v);
9142 clutter_actor_get_abs_allocation_vertices (self, v);
9144 x_min = x_max = v[0].x;
9145 y_min = y_max = v[0].y;
9147 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9163 *width = x_max - x_min;
9166 *height = y_max - y_min;
9170 * clutter_actor_get_width:
9171 * @self: A #ClutterActor
9173 * Retrieves the width of a #ClutterActor.
9175 * If the actor has a valid allocation, this function will return the
9176 * width of the allocated area given to the actor.
9178 * If the actor does not have a valid allocation, this function will
9179 * return the actor's natural width, that is the preferred width of
9182 * If you care whether you get the preferred width or the width that
9183 * has been assigned to the actor, you should probably call a different
9184 * function like clutter_actor_get_allocation_box() to retrieve the
9185 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9188 * If an actor has a fixed width, for instance a width that has been
9189 * assigned using clutter_actor_set_width(), the width returned will
9190 * be the same value.
9192 * Return value: the width of the actor, in pixels
9195 clutter_actor_get_width (ClutterActor *self)
9197 ClutterActorPrivate *priv;
9199 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9203 if (priv->needs_allocation)
9205 gfloat natural_width = 0;
9207 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9208 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9211 gfloat natural_height = 0;
9213 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9214 clutter_actor_get_preferred_width (self, natural_height,
9219 return natural_width;
9222 return priv->allocation.x2 - priv->allocation.x1;
9226 * clutter_actor_get_height:
9227 * @self: A #ClutterActor
9229 * Retrieves the height of a #ClutterActor.
9231 * If the actor has a valid allocation, this function will return the
9232 * height of the allocated area given to the actor.
9234 * If the actor does not have a valid allocation, this function will
9235 * return the actor's natural height, that is the preferred height of
9238 * If you care whether you get the preferred height or the height that
9239 * has been assigned to the actor, you should probably call a different
9240 * function like clutter_actor_get_allocation_box() to retrieve the
9241 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9244 * If an actor has a fixed height, for instance a height that has been
9245 * assigned using clutter_actor_set_height(), the height returned will
9246 * be the same value.
9248 * Return value: the height of the actor, in pixels
9251 clutter_actor_get_height (ClutterActor *self)
9253 ClutterActorPrivate *priv;
9255 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9259 if (priv->needs_allocation)
9261 gfloat natural_height = 0;
9263 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9265 gfloat natural_width = 0;
9267 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9268 clutter_actor_get_preferred_height (self, natural_width,
9269 NULL, &natural_height);
9272 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9274 return natural_height;
9277 return priv->allocation.y2 - priv->allocation.y1;
9281 * clutter_actor_set_width:
9282 * @self: A #ClutterActor
9283 * @width: Requested new width for the actor, in pixels, or -1
9285 * Forces a width on an actor, causing the actor's preferred width
9286 * and height (if any) to be ignored.
9288 * If @width is -1 the actor will use its preferred width request
9289 * instead of overriding it, i.e. you can "unset" the width with -1.
9291 * This function sets both the minimum and natural size of the actor.
9296 clutter_actor_set_width (ClutterActor *self,
9299 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9301 if (clutter_actor_get_easing_duration (self) != 0)
9303 ClutterTransition *transition;
9305 transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9306 if (transition == NULL)
9308 float old_width = clutter_actor_get_width (self);
9310 transition = _clutter_actor_create_transition (self,
9311 obj_props[PROP_WIDTH],
9314 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9317 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9319 clutter_actor_queue_relayout (self);
9323 g_object_freeze_notify (G_OBJECT (self));
9325 clutter_actor_set_width_internal (self, width);
9327 g_object_thaw_notify (G_OBJECT (self));
9332 * clutter_actor_set_height:
9333 * @self: A #ClutterActor
9334 * @height: Requested new height for the actor, in pixels, or -1
9336 * Forces a height on an actor, causing the actor's preferred width
9337 * and height (if any) to be ignored.
9339 * If @height is -1 the actor will use its preferred height instead of
9340 * overriding it, i.e. you can "unset" the height with -1.
9342 * This function sets both the minimum and natural size of the actor.
9347 clutter_actor_set_height (ClutterActor *self,
9350 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9352 if (clutter_actor_get_easing_duration (self) != 0)
9354 ClutterTransition *transition;
9356 transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9357 if (transition == NULL)
9359 float old_height = clutter_actor_get_height (self);
9361 transition = _clutter_actor_create_transition (self,
9362 obj_props[PROP_HEIGHT],
9365 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9368 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9370 clutter_actor_queue_relayout (self);
9374 g_object_freeze_notify (G_OBJECT (self));
9376 clutter_actor_set_height_internal (self, height);
9378 g_object_thaw_notify (G_OBJECT (self));
9383 clutter_actor_set_x_internal (ClutterActor *self,
9386 ClutterActorPrivate *priv = self->priv;
9387 ClutterLayoutInfo *linfo;
9388 ClutterActorBox old = { 0, };
9390 linfo = _clutter_actor_get_layout_info (self);
9392 if (priv->position_set && linfo->fixed_x == x)
9395 clutter_actor_store_old_geometry (self, &old);
9398 clutter_actor_set_fixed_position_set (self, TRUE);
9400 clutter_actor_notify_if_geometry_changed (self, &old);
9402 clutter_actor_queue_relayout (self);
9406 clutter_actor_set_y_internal (ClutterActor *self,
9409 ClutterActorPrivate *priv = self->priv;
9410 ClutterLayoutInfo *linfo;
9411 ClutterActorBox old = { 0, };
9413 linfo = _clutter_actor_get_layout_info (self);
9415 if (priv->position_set && linfo->fixed_y == y)
9418 clutter_actor_store_old_geometry (self, &old);
9421 clutter_actor_set_fixed_position_set (self, TRUE);
9423 clutter_actor_notify_if_geometry_changed (self, &old);
9427 * clutter_actor_set_x:
9428 * @self: a #ClutterActor
9429 * @x: the actor's position on the X axis
9431 * Sets the actor's X coordinate, relative to its parent, in pixels.
9433 * Overrides any layout manager and forces a fixed position for
9436 * The #ClutterActor:x property is animatable.
9441 clutter_actor_set_x (ClutterActor *self,
9444 const ClutterLayoutInfo *linfo;
9446 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9448 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9450 if (clutter_actor_get_easing_duration (self) != 0)
9452 ClutterTransition *transition;
9454 transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9455 if (transition == NULL)
9457 transition = _clutter_actor_create_transition (self,
9462 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9465 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9467 clutter_actor_queue_relayout (self);
9470 clutter_actor_set_x_internal (self, x);
9474 * clutter_actor_set_y:
9475 * @self: a #ClutterActor
9476 * @y: the actor's position on the Y axis
9478 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9480 * Overrides any layout manager and forces a fixed position for
9483 * The #ClutterActor:y property is animatable.
9488 clutter_actor_set_y (ClutterActor *self,
9491 const ClutterLayoutInfo *linfo;
9493 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9495 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9497 if (clutter_actor_get_easing_duration (self) != 0)
9499 ClutterTransition *transition;
9501 transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9502 if (transition == NULL)
9504 transition = _clutter_actor_create_transition (self,
9509 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9512 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9514 clutter_actor_queue_relayout (self);
9517 clutter_actor_set_y_internal (self, y);
9519 clutter_actor_queue_relayout (self);
9523 * clutter_actor_get_x:
9524 * @self: A #ClutterActor
9526 * Retrieves the X coordinate of a #ClutterActor.
9528 * This function tries to "do what you mean", by returning the
9529 * correct value depending on the actor's state.
9531 * If the actor has a valid allocation, this function will return
9532 * the X coordinate of the origin of the allocation box.
9534 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9535 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9536 * function will return that coordinate.
9538 * If both the allocation and a fixed position are missing, this function
9541 * Return value: the X coordinate, in pixels, ignoring any
9542 * transformation (i.e. scaling, rotation)
9545 clutter_actor_get_x (ClutterActor *self)
9547 ClutterActorPrivate *priv;
9549 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9553 if (priv->needs_allocation)
9555 if (priv->position_set)
9557 const ClutterLayoutInfo *info;
9559 info = _clutter_actor_get_layout_info_or_defaults (self);
9561 return info->fixed_x;
9567 return priv->allocation.x1;
9571 * clutter_actor_get_y:
9572 * @self: A #ClutterActor
9574 * Retrieves the Y coordinate of a #ClutterActor.
9576 * This function tries to "do what you mean", by returning the
9577 * correct value depending on the actor's state.
9579 * If the actor has a valid allocation, this function will return
9580 * the Y coordinate of the origin of the allocation box.
9582 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9583 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9584 * function will return that coordinate.
9586 * If both the allocation and a fixed position are missing, this function
9589 * Return value: the Y coordinate, in pixels, ignoring any
9590 * transformation (i.e. scaling, rotation)
9593 clutter_actor_get_y (ClutterActor *self)
9595 ClutterActorPrivate *priv;
9597 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9601 if (priv->needs_allocation)
9603 if (priv->position_set)
9605 const ClutterLayoutInfo *info;
9607 info = _clutter_actor_get_layout_info_or_defaults (self);
9609 return info->fixed_y;
9615 return priv->allocation.y1;
9619 * clutter_actor_set_scale:
9620 * @self: A #ClutterActor
9621 * @scale_x: double factor to scale actor by horizontally.
9622 * @scale_y: double factor to scale actor by vertically.
9624 * Scales an actor with the given factors. The scaling is relative to
9625 * the scale center and the anchor point. The scale center is
9626 * unchanged by this function and defaults to 0,0.
9628 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9634 clutter_actor_set_scale (ClutterActor *self,
9638 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9640 g_object_freeze_notify (G_OBJECT (self));
9642 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9643 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9645 g_object_thaw_notify (G_OBJECT (self));
9649 * clutter_actor_set_scale_full:
9650 * @self: A #ClutterActor
9651 * @scale_x: double factor to scale actor by horizontally.
9652 * @scale_y: double factor to scale actor by vertically.
9653 * @center_x: X coordinate of the center of the scale.
9654 * @center_y: Y coordinate of the center of the scale
9656 * Scales an actor with the given factors around the given center
9657 * point. The center point is specified in pixels relative to the
9658 * anchor point (usually the top left corner of the actor).
9660 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9666 clutter_actor_set_scale_full (ClutterActor *self,
9672 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9674 g_object_freeze_notify (G_OBJECT (self));
9676 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9677 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9678 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9679 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9681 g_object_thaw_notify (G_OBJECT (self));
9685 * clutter_actor_set_scale_with_gravity:
9686 * @self: A #ClutterActor
9687 * @scale_x: double factor to scale actor by horizontally.
9688 * @scale_y: double factor to scale actor by vertically.
9689 * @gravity: the location of the scale center expressed as a compass
9692 * Scales an actor with the given factors around the given
9693 * center point. The center point is specified as one of the compass
9694 * directions in #ClutterGravity. For example, setting it to north
9695 * will cause the top of the actor to remain unchanged and the rest of
9696 * the actor to expand left, right and downwards.
9698 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9704 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9707 ClutterGravity gravity)
9709 ClutterTransformInfo *info;
9712 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9714 obj = G_OBJECT (self);
9716 g_object_freeze_notify (obj);
9718 info = _clutter_actor_get_transform_info (self);
9719 info->scale_x = scale_x;
9720 info->scale_y = scale_y;
9722 if (gravity == CLUTTER_GRAVITY_NONE)
9723 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9725 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9727 self->priv->transform_valid = FALSE;
9729 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9730 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9731 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9732 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9733 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9735 clutter_actor_queue_redraw (self);
9737 g_object_thaw_notify (obj);
9741 * clutter_actor_get_scale:
9742 * @self: A #ClutterActor
9743 * @scale_x: (out) (allow-none): Location to store horizonal
9744 * scale factor, or %NULL.
9745 * @scale_y: (out) (allow-none): Location to store vertical
9746 * scale factor, or %NULL.
9748 * Retrieves an actors scale factors.
9753 clutter_actor_get_scale (ClutterActor *self,
9757 const ClutterTransformInfo *info;
9759 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9761 info = _clutter_actor_get_transform_info_or_defaults (self);
9764 *scale_x = info->scale_x;
9767 *scale_y = info->scale_y;
9771 * clutter_actor_get_scale_center:
9772 * @self: A #ClutterActor
9773 * @center_x: (out) (allow-none): Location to store the X position
9774 * of the scale center, or %NULL.
9775 * @center_y: (out) (allow-none): Location to store the Y position
9776 * of the scale center, or %NULL.
9778 * Retrieves the scale center coordinate in pixels relative to the top
9779 * left corner of the actor. If the scale center was specified using a
9780 * #ClutterGravity this will calculate the pixel offset using the
9781 * current size of the actor.
9786 clutter_actor_get_scale_center (ClutterActor *self,
9790 const ClutterTransformInfo *info;
9792 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9794 info = _clutter_actor_get_transform_info_or_defaults (self);
9796 clutter_anchor_coord_get_units (self, &info->scale_center,
9803 * clutter_actor_get_scale_gravity:
9804 * @self: A #ClutterActor
9806 * Retrieves the scale center as a compass direction. If the scale
9807 * center was specified in pixels or units this will return
9808 * %CLUTTER_GRAVITY_NONE.
9810 * Return value: the scale gravity
9815 clutter_actor_get_scale_gravity (ClutterActor *self)
9817 const ClutterTransformInfo *info;
9819 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9821 info = _clutter_actor_get_transform_info_or_defaults (self);
9823 return clutter_anchor_coord_get_gravity (&info->scale_center);
9827 clutter_actor_set_opacity_internal (ClutterActor *self,
9830 ClutterActorPrivate *priv = self->priv;
9832 if (priv->opacity != opacity)
9834 priv->opacity = opacity;
9836 /* Queue a redraw from the flatten effect so that it can use
9837 its cached image if available instead of having to redraw the
9838 actual actor. If it doesn't end up using the FBO then the
9839 effect is still able to continue the paint anyway. If there
9840 is no flatten effect yet then this is equivalent to queueing
9842 _clutter_actor_queue_redraw_full (self,
9845 priv->flatten_effect);
9847 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9852 * clutter_actor_set_opacity:
9853 * @self: A #ClutterActor
9854 * @opacity: New opacity value for the actor.
9856 * Sets the actor's opacity, with zero being completely transparent and
9857 * 255 (0xff) being fully opaque.
9859 * The #ClutterActor:opacity property is animatable.
9862 clutter_actor_set_opacity (ClutterActor *self,
9865 ClutterActorPrivate *priv;
9867 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9871 if (clutter_actor_get_easing_duration (self) != 0)
9873 ClutterTransition *transition;
9875 transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9876 if (transition == NULL)
9878 transition = _clutter_actor_create_transition (self,
9879 obj_props[PROP_OPACITY],
9882 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9885 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9887 clutter_actor_queue_redraw (self);
9890 clutter_actor_set_opacity_internal (self, opacity);
9894 * clutter_actor_get_paint_opacity_internal:
9895 * @self: a #ClutterActor
9897 * Retrieves the absolute opacity of the actor, as it appears on the stage
9899 * This function does not do type checks
9901 * Return value: the absolute opacity of the actor
9904 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9906 ClutterActorPrivate *priv = self->priv;
9907 ClutterActor *parent;
9909 /* override the top-level opacity to always be 255; even in
9910 * case of ClutterStage:use-alpha being TRUE we want the rest
9911 * of the scene to be painted
9913 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9916 if (priv->opacity_override >= 0)
9917 return priv->opacity_override;
9919 parent = priv->parent;
9921 /* Factor in the actual actors opacity with parents */
9924 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9926 if (opacity != 0xff)
9927 return (opacity * priv->opacity) / 0xff;
9930 return priv->opacity;
9935 * clutter_actor_get_paint_opacity:
9936 * @self: A #ClutterActor
9938 * Retrieves the absolute opacity of the actor, as it appears on the stage.
9940 * This function traverses the hierarchy chain and composites the opacity of
9941 * the actor with that of its parents.
9943 * This function is intended for subclasses to use in the paint virtual
9944 * function, to paint themselves with the correct opacity.
9946 * Return value: The actor opacity value.
9951 clutter_actor_get_paint_opacity (ClutterActor *self)
9953 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9955 return clutter_actor_get_paint_opacity_internal (self);
9959 * clutter_actor_get_opacity:
9960 * @self: a #ClutterActor
9962 * Retrieves the opacity value of an actor, as set by
9963 * clutter_actor_set_opacity().
9965 * For retrieving the absolute opacity of the actor inside a paint
9966 * virtual function, see clutter_actor_get_paint_opacity().
9968 * Return value: the opacity of the actor
9971 clutter_actor_get_opacity (ClutterActor *self)
9973 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9975 return self->priv->opacity;
9979 * clutter_actor_set_offscreen_redirect:
9980 * @self: A #ClutterActor
9981 * @redirect: New offscreen redirect flags for the actor.
9983 * Defines the circumstances where the actor should be redirected into
9984 * an offscreen image. The offscreen image is used to flatten the
9985 * actor into a single image while painting for two main reasons.
9986 * Firstly, when the actor is painted a second time without any of its
9987 * contents changing it can simply repaint the cached image without
9988 * descending further down the actor hierarchy. Secondly, it will make
9989 * the opacity look correct even if there are overlapping primitives
9992 * Caching the actor could in some cases be a performance win and in
9993 * some cases be a performance lose so it is important to determine
9994 * which value is right for an actor before modifying this value. For
9995 * example, there is never any reason to flatten an actor that is just
9996 * a single texture (such as a #ClutterTexture) because it is
9997 * effectively already cached in an image so the offscreen would be
9998 * redundant. Also if the actor contains primitives that are far apart
9999 * with a large transparent area in the middle (such as a large
10000 * CluterGroup with a small actor in the top left and a small actor in
10001 * the bottom right) then the cached image will contain the entire
10002 * image of the large area and the paint will waste time blending all
10003 * of the transparent pixels in the middle.
10005 * The default method of implementing opacity on a container simply
10006 * forwards on the opacity to all of the children. If the children are
10007 * overlapping then it will appear as if they are two separate glassy
10008 * objects and there will be a break in the color where they
10009 * overlap. By redirecting to an offscreen buffer it will be as if the
10010 * two opaque objects are combined into one and then made transparent
10011 * which is usually what is expected.
10013 * The image below demonstrates the difference between redirecting and
10014 * not. The image shows two Clutter groups, each containing a red and
10015 * a green rectangle which overlap. The opacity on the group is set to
10016 * 128 (which is 50%). When the offscreen redirect is not used, the
10017 * red rectangle can be seen through the blue rectangle as if the two
10018 * rectangles were separately transparent. When the redirect is used
10019 * the group as a whole is transparent instead so the red rectangle is
10020 * not visible where they overlap.
10022 * <figure id="offscreen-redirect">
10023 * <title>Sample of using an offscreen redirect for transparency</title>
10024 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10027 * The default value for this property is 0, so we effectively will
10028 * never redirect an actor offscreen by default. This means that there
10029 * are times that transparent actors may look glassy as described
10030 * above. The reason this is the default is because there is a
10031 * performance trade off between quality and performance here. In many
10032 * cases the default form of glassy opacity looks good enough, but if
10033 * it's not you will need to set the
10034 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10035 * redirection for opacity.
10037 * Custom actors that don't contain any overlapping primitives are
10038 * recommended to override the has_overlaps() virtual to return %FALSE
10039 * for maximum efficiency.
10044 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10045 ClutterOffscreenRedirect redirect)
10047 ClutterActorPrivate *priv;
10049 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10053 if (priv->offscreen_redirect != redirect)
10055 priv->offscreen_redirect = redirect;
10057 /* Queue a redraw from the effect so that it can use its cached
10058 image if available instead of having to redraw the actual
10059 actor. If it doesn't end up using the FBO then the effect is
10060 still able to continue the paint anyway. If there is no
10061 effect then this is equivalent to queuing a full redraw */
10062 _clutter_actor_queue_redraw_full (self,
10065 priv->flatten_effect);
10067 g_object_notify_by_pspec (G_OBJECT (self),
10068 obj_props[PROP_OFFSCREEN_REDIRECT]);
10073 * clutter_actor_get_offscreen_redirect:
10074 * @self: a #ClutterActor
10076 * Retrieves whether to redirect the actor to an offscreen buffer, as
10077 * set by clutter_actor_set_offscreen_redirect().
10079 * Return value: the value of the offscreen-redirect property of the actor
10083 ClutterOffscreenRedirect
10084 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10086 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10088 return self->priv->offscreen_redirect;
10092 * clutter_actor_set_name:
10093 * @self: A #ClutterActor
10094 * @name: Textual tag to apply to actor
10096 * Sets the given name to @self. The name can be used to identify
10100 clutter_actor_set_name (ClutterActor *self,
10103 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10105 g_free (self->priv->name);
10106 self->priv->name = g_strdup (name);
10108 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10112 * clutter_actor_get_name:
10113 * @self: A #ClutterActor
10115 * Retrieves the name of @self.
10117 * Return value: the name of the actor, or %NULL. The returned string is
10118 * owned by the actor and should not be modified or freed.
10121 clutter_actor_get_name (ClutterActor *self)
10123 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10125 return self->priv->name;
10129 * clutter_actor_get_gid:
10130 * @self: A #ClutterActor
10132 * Retrieves the unique id for @self.
10134 * Return value: Globally unique value for this object instance.
10138 * Deprecated: 1.8: The id is not used any longer.
10141 clutter_actor_get_gid (ClutterActor *self)
10143 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10145 return self->priv->id;
10149 clutter_actor_set_depth_internal (ClutterActor *self,
10152 ClutterTransformInfo *info;
10154 info = _clutter_actor_get_transform_info (self);
10156 if (info->depth != depth)
10158 /* Sets Z value - XXX 2.0: should we invert? */
10159 info->depth = depth;
10161 self->priv->transform_valid = FALSE;
10163 /* FIXME - remove this crap; sadly, there are still containers
10164 * in Clutter that depend on this utter brain damage
10166 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10168 clutter_actor_queue_redraw (self);
10170 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10175 * clutter_actor_set_depth:
10176 * @self: a #ClutterActor
10179 * Sets the Z coordinate of @self to @depth.
10181 * The unit used by @depth is dependant on the perspective setup. See
10182 * also clutter_stage_set_perspective().
10185 clutter_actor_set_depth (ClutterActor *self,
10188 const ClutterTransformInfo *tinfo;
10190 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10192 tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10194 if (clutter_actor_get_easing_duration (self) != 0)
10196 ClutterTransition *transition;
10198 transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10199 if (transition == NULL)
10201 transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10204 clutter_timeline_start (CLUTTER_TIMELINE (transition));
10207 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10209 clutter_actor_queue_redraw (self);
10212 clutter_actor_set_depth_internal (self, depth);
10216 * clutter_actor_get_depth:
10217 * @self: a #ClutterActor
10219 * Retrieves the depth of @self.
10221 * Return value: the depth of the actor
10224 clutter_actor_get_depth (ClutterActor *self)
10226 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10228 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10232 * clutter_actor_set_rotation:
10233 * @self: a #ClutterActor
10234 * @axis: the axis of rotation
10235 * @angle: the angle of rotation
10236 * @x: X coordinate of the rotation center
10237 * @y: Y coordinate of the rotation center
10238 * @z: Z coordinate of the rotation center
10240 * Sets the rotation angle of @self around the given axis.
10242 * The rotation center coordinates used depend on the value of @axis:
10244 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10245 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10246 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10249 * The rotation coordinates are relative to the anchor point of the
10250 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10251 * point is set, the upper left corner is assumed as the origin.
10256 clutter_actor_set_rotation (ClutterActor *self,
10257 ClutterRotateAxis axis,
10265 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10271 g_object_freeze_notify (G_OBJECT (self));
10273 clutter_actor_set_rotation_angle (self, axis, angle);
10274 clutter_actor_set_rotation_center_internal (self, axis, &v);
10276 g_object_thaw_notify (G_OBJECT (self));
10280 * clutter_actor_set_z_rotation_from_gravity:
10281 * @self: a #ClutterActor
10282 * @angle: the angle of rotation
10283 * @gravity: the center point of the rotation
10285 * Sets the rotation angle of @self around the Z axis using the center
10286 * point specified as a compass point. For example to rotate such that
10287 * the center of the actor remains static you can use
10288 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10289 * will move accordingly.
10294 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10296 ClutterGravity gravity)
10298 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10300 if (gravity == CLUTTER_GRAVITY_NONE)
10301 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10304 GObject *obj = G_OBJECT (self);
10305 ClutterTransformInfo *info;
10307 info = _clutter_actor_get_transform_info (self);
10309 g_object_freeze_notify (obj);
10311 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10313 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10314 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10315 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10317 g_object_thaw_notify (obj);
10322 * clutter_actor_get_rotation:
10323 * @self: a #ClutterActor
10324 * @axis: the axis of rotation
10325 * @x: (out): return value for the X coordinate of the center of rotation
10326 * @y: (out): return value for the Y coordinate of the center of rotation
10327 * @z: (out): return value for the Z coordinate of the center of rotation
10329 * Retrieves the angle and center of rotation on the given axis,
10330 * set using clutter_actor_set_rotation().
10332 * Return value: the angle of rotation
10337 clutter_actor_get_rotation (ClutterActor *self,
10338 ClutterRotateAxis axis,
10343 const ClutterTransformInfo *info;
10344 const AnchorCoord *anchor_coord;
10345 gdouble retval = 0;
10347 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10349 info = _clutter_actor_get_transform_info_or_defaults (self);
10353 case CLUTTER_X_AXIS:
10354 anchor_coord = &info->rx_center;
10355 retval = info->rx_angle;
10358 case CLUTTER_Y_AXIS:
10359 anchor_coord = &info->ry_center;
10360 retval = info->ry_angle;
10363 case CLUTTER_Z_AXIS:
10364 anchor_coord = &info->rz_center;
10365 retval = info->rz_angle;
10369 anchor_coord = NULL;
10374 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10380 * clutter_actor_get_z_rotation_gravity:
10381 * @self: A #ClutterActor
10383 * Retrieves the center for the rotation around the Z axis as a
10384 * compass direction. If the center was specified in pixels or units
10385 * this will return %CLUTTER_GRAVITY_NONE.
10387 * Return value: the Z rotation center
10392 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10394 const ClutterTransformInfo *info;
10396 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10398 info = _clutter_actor_get_transform_info_or_defaults (self);
10400 return clutter_anchor_coord_get_gravity (&info->rz_center);
10404 * clutter_actor_set_clip:
10405 * @self: A #ClutterActor
10406 * @xoff: X offset of the clip rectangle
10407 * @yoff: Y offset of the clip rectangle
10408 * @width: Width of the clip rectangle
10409 * @height: Height of the clip rectangle
10411 * Sets clip area for @self. The clip area is always computed from the
10412 * upper left corner of the actor, even if the anchor point is set
10418 clutter_actor_set_clip (ClutterActor *self,
10424 ClutterActorPrivate *priv;
10426 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10430 if (priv->has_clip &&
10431 priv->clip.x == xoff &&
10432 priv->clip.y == yoff &&
10433 priv->clip.width == width &&
10434 priv->clip.height == height)
10437 priv->clip.x = xoff;
10438 priv->clip.y = yoff;
10439 priv->clip.width = width;
10440 priv->clip.height = height;
10442 priv->has_clip = TRUE;
10444 clutter_actor_queue_redraw (self);
10446 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10447 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10451 * clutter_actor_remove_clip:
10452 * @self: A #ClutterActor
10454 * Removes clip area from @self.
10457 clutter_actor_remove_clip (ClutterActor *self)
10459 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10461 if (!self->priv->has_clip)
10464 self->priv->has_clip = FALSE;
10466 clutter_actor_queue_redraw (self);
10468 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10472 * clutter_actor_has_clip:
10473 * @self: a #ClutterActor
10475 * Determines whether the actor has a clip area set or not.
10477 * Return value: %TRUE if the actor has a clip area set.
10482 clutter_actor_has_clip (ClutterActor *self)
10484 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10486 return self->priv->has_clip;
10490 * clutter_actor_get_clip:
10491 * @self: a #ClutterActor
10492 * @xoff: (out) (allow-none): return location for the X offset of
10493 * the clip rectangle, or %NULL
10494 * @yoff: (out) (allow-none): return location for the Y offset of
10495 * the clip rectangle, or %NULL
10496 * @width: (out) (allow-none): return location for the width of
10497 * the clip rectangle, or %NULL
10498 * @height: (out) (allow-none): return location for the height of
10499 * the clip rectangle, or %NULL
10501 * Gets the clip area for @self, if any is set
10506 clutter_actor_get_clip (ClutterActor *self,
10512 ClutterActorPrivate *priv;
10514 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10518 if (!priv->has_clip)
10522 *xoff = priv->clip.x;
10525 *yoff = priv->clip.y;
10528 *width = priv->clip.width;
10530 if (height != NULL)
10531 *height = priv->clip.height;
10535 * clutter_actor_get_children:
10536 * @self: a #ClutterActor
10538 * Retrieves the list of children of @self.
10540 * Return value: (transfer container) (element-type ClutterActor): A newly
10541 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10547 clutter_actor_get_children (ClutterActor *self)
10549 ClutterActor *iter;
10552 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10554 /* we walk the list backward so that we can use prepend(),
10557 for (iter = self->priv->last_child, res = NULL;
10559 iter = iter->priv->prev_sibling)
10561 res = g_list_prepend (res, iter);
10568 * insert_child_at_depth:
10569 * @self: a #ClutterActor
10570 * @child: a #ClutterActor
10572 * Inserts @child inside the list of children held by @self, using
10573 * the depth as the insertion criteria.
10575 * This sadly makes the insertion not O(1), but we can keep the
10576 * list sorted so that the painters algorithm we use for painting
10577 * the children will work correctly.
10580 insert_child_at_depth (ClutterActor *self,
10581 ClutterActor *child,
10582 gpointer dummy G_GNUC_UNUSED)
10584 ClutterActor *iter;
10587 child->priv->parent = self;
10590 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10592 /* special-case the first child */
10593 if (self->priv->n_children == 0)
10595 self->priv->first_child = child;
10596 self->priv->last_child = child;
10598 child->priv->next_sibling = NULL;
10599 child->priv->prev_sibling = NULL;
10604 /* Find the right place to insert the child so that it will still be
10605 sorted and the child will be after all of the actors at the same
10607 for (iter = self->priv->first_child;
10609 iter = iter->priv->next_sibling)
10614 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10616 if (iter_depth > child_depth)
10622 ClutterActor *tmp = iter->priv->prev_sibling;
10625 tmp->priv->next_sibling = child;
10627 /* Insert the node before the found one */
10628 child->priv->prev_sibling = iter->priv->prev_sibling;
10629 child->priv->next_sibling = iter;
10630 iter->priv->prev_sibling = child;
10634 ClutterActor *tmp = self->priv->last_child;
10637 tmp->priv->next_sibling = child;
10639 /* insert the node at the end of the list */
10640 child->priv->prev_sibling = self->priv->last_child;
10641 child->priv->next_sibling = NULL;
10644 if (child->priv->prev_sibling == NULL)
10645 self->priv->first_child = child;
10647 if (child->priv->next_sibling == NULL)
10648 self->priv->last_child = child;
10652 insert_child_at_index (ClutterActor *self,
10653 ClutterActor *child,
10656 gint index_ = GPOINTER_TO_INT (data_);
10658 child->priv->parent = self;
10662 ClutterActor *tmp = self->priv->first_child;
10665 tmp->priv->prev_sibling = child;
10667 child->priv->prev_sibling = NULL;
10668 child->priv->next_sibling = tmp;
10670 else if (index_ < 0 || index_ >= self->priv->n_children)
10672 ClutterActor *tmp = self->priv->last_child;
10675 tmp->priv->next_sibling = child;
10677 child->priv->prev_sibling = tmp;
10678 child->priv->next_sibling = NULL;
10682 ClutterActor *iter;
10685 for (iter = self->priv->first_child, i = 0;
10687 iter = iter->priv->next_sibling, i += 1)
10691 ClutterActor *tmp = iter->priv->prev_sibling;
10693 child->priv->prev_sibling = tmp;
10694 child->priv->next_sibling = iter;
10696 iter->priv->prev_sibling = child;
10699 tmp->priv->next_sibling = child;
10706 if (child->priv->prev_sibling == NULL)
10707 self->priv->first_child = child;
10709 if (child->priv->next_sibling == NULL)
10710 self->priv->last_child = child;
10714 insert_child_above (ClutterActor *self,
10715 ClutterActor *child,
10718 ClutterActor *sibling = data;
10720 child->priv->parent = self;
10722 if (sibling == NULL)
10723 sibling = self->priv->last_child;
10725 child->priv->prev_sibling = sibling;
10727 if (sibling != NULL)
10729 ClutterActor *tmp = sibling->priv->next_sibling;
10731 child->priv->next_sibling = tmp;
10734 tmp->priv->prev_sibling = child;
10736 sibling->priv->next_sibling = child;
10739 child->priv->next_sibling = NULL;
10741 if (child->priv->prev_sibling == NULL)
10742 self->priv->first_child = child;
10744 if (child->priv->next_sibling == NULL)
10745 self->priv->last_child = child;
10749 insert_child_below (ClutterActor *self,
10750 ClutterActor *child,
10753 ClutterActor *sibling = data;
10755 child->priv->parent = self;
10757 if (sibling == NULL)
10758 sibling = self->priv->first_child;
10760 child->priv->next_sibling = sibling;
10762 if (sibling != NULL)
10764 ClutterActor *tmp = sibling->priv->prev_sibling;
10766 child->priv->prev_sibling = tmp;
10769 tmp->priv->next_sibling = child;
10771 sibling->priv->prev_sibling = child;
10774 child->priv->prev_sibling = NULL;
10776 if (child->priv->prev_sibling == NULL)
10777 self->priv->first_child = child;
10779 if (child->priv->next_sibling == NULL)
10780 self->priv->last_child = child;
10783 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10784 ClutterActor *child,
10788 ADD_CHILD_CREATE_META = 1 << 0,
10789 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10790 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10791 ADD_CHILD_CHECK_STATE = 1 << 3,
10792 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10794 /* default flags for public API */
10795 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10796 ADD_CHILD_EMIT_PARENT_SET |
10797 ADD_CHILD_EMIT_ACTOR_ADDED |
10798 ADD_CHILD_CHECK_STATE |
10799 ADD_CHILD_NOTIFY_FIRST_LAST,
10801 /* flags for legacy/deprecated API */
10802 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10803 ADD_CHILD_CHECK_STATE |
10804 ADD_CHILD_NOTIFY_FIRST_LAST
10805 } ClutterActorAddChildFlags;
10808 * clutter_actor_add_child_internal:
10809 * @self: a #ClutterActor
10810 * @child: a #ClutterActor
10811 * @flags: control flags for actions
10812 * @add_func: delegate function
10813 * @data: (closure): data to pass to @add_func
10815 * Adds @child to the list of children of @self.
10817 * The actual insertion inside the list is delegated to @add_func: this
10818 * function will just set up the state, perform basic checks, and emit
10821 * The @flags argument is used to perform additional operations.
10824 clutter_actor_add_child_internal (ClutterActor *self,
10825 ClutterActor *child,
10826 ClutterActorAddChildFlags flags,
10827 ClutterActorAddChildFunc add_func,
10830 ClutterTextDirection text_dir;
10831 gboolean create_meta;
10832 gboolean emit_parent_set, emit_actor_added;
10833 gboolean check_state;
10834 gboolean notify_first_last;
10835 ClutterActor *old_first_child, *old_last_child;
10837 if (child->priv->parent != NULL)
10839 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10840 "use clutter_actor_remove_child() first.",
10841 _clutter_actor_get_debug_name (child),
10842 _clutter_actor_get_debug_name (child->priv->parent));
10846 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10848 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10849 "a child of another actor.",
10850 _clutter_actor_get_debug_name (child));
10855 /* XXX - this check disallows calling methods that change the stacking
10856 * order within the destruction sequence, by triggering a critical
10857 * warning first, and leaving the actor in an undefined state, which
10858 * then ends up being caught by an assertion.
10860 * the reproducible sequence is:
10862 * - actor gets destroyed;
10863 * - another actor, linked to the first, will try to change the
10864 * stacking order of the first actor;
10865 * - changing the stacking order is a composite operation composed
10866 * by the following steps:
10867 * 1. ref() the child;
10868 * 2. remove_child_internal(), which removes the reference;
10869 * 3. add_child_internal(), which adds a reference;
10870 * - the state of the actor is not changed between (2) and (3), as
10871 * it could be an expensive recomputation;
10872 * - if (3) bails out, then the actor is in an undefined state, but
10874 * - the destruction sequence terminates, but the actor is unparented
10875 * while its state indicates being parented instead.
10876 * - assertion failure.
10878 * the obvious fix would be to decompose each set_child_*_sibling()
10879 * method into proper remove_child()/add_child(), with state validation;
10880 * this may cause excessive work, though, and trigger a cascade of other
10881 * bugs in code that assumes that a change in the stacking order is an
10882 * atomic operation.
10884 * another potential fix is to just remove this check here, and let
10885 * code doing stacking order changes inside the destruction sequence
10886 * of an actor continue doing the work.
10888 * the third fix is to silently bail out early from every
10889 * set_child_*_sibling() and set_child_at_index() method, and avoid
10892 * I have a preference for the second solution, since it involves the
10893 * least amount of work, and the least amount of code duplication.
10895 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10897 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10899 g_warning ("The actor '%s' is currently being destroyed, and "
10900 "cannot be added as a child of another actor.",
10901 _clutter_actor_get_debug_name (child));
10906 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10907 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10908 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10909 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10910 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10912 old_first_child = self->priv->first_child;
10913 old_last_child = self->priv->last_child;
10915 g_object_freeze_notify (G_OBJECT (self));
10918 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10920 g_object_ref_sink (child);
10921 child->priv->parent = NULL;
10922 child->priv->next_sibling = NULL;
10923 child->priv->prev_sibling = NULL;
10925 /* delegate the actual insertion */
10926 add_func (self, child, data);
10928 g_assert (child->priv->parent == self);
10930 self->priv->n_children += 1;
10932 self->priv->age += 1;
10934 /* if push_internal() has been called then we automatically set
10935 * the flag on the actor
10937 if (self->priv->internal_child)
10938 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10940 /* clutter_actor_reparent() will emit ::parent-set for us */
10941 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10942 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10946 /* If parent is mapped or realized, we need to also be mapped or
10947 * realized once we're inside the parent.
10949 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10951 /* propagate the parent's text direction to the child */
10952 text_dir = clutter_actor_get_text_direction (self);
10953 clutter_actor_set_text_direction (child, text_dir);
10956 if (child->priv->show_on_set_parent)
10957 clutter_actor_show (child);
10959 if (CLUTTER_ACTOR_IS_MAPPED (child))
10960 clutter_actor_queue_redraw (child);
10962 /* maintain the invariant that if an actor needs layout,
10963 * its parents do as well
10965 if (child->priv->needs_width_request ||
10966 child->priv->needs_height_request ||
10967 child->priv->needs_allocation)
10969 /* we work around the short-circuiting we do
10970 * in clutter_actor_queue_relayout() since we
10971 * want to force a relayout
10973 child->priv->needs_width_request = TRUE;
10974 child->priv->needs_height_request = TRUE;
10975 child->priv->needs_allocation = TRUE;
10977 clutter_actor_queue_relayout (child->priv->parent);
10980 if (emit_actor_added)
10981 g_signal_emit_by_name (self, "actor-added", child);
10983 if (notify_first_last)
10985 if (old_first_child != self->priv->first_child)
10986 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10988 if (old_last_child != self->priv->last_child)
10989 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10992 g_object_thaw_notify (G_OBJECT (self));
10996 * clutter_actor_add_child:
10997 * @self: a #ClutterActor
10998 * @child: a #ClutterActor
11000 * Adds @child to the children of @self.
11002 * This function will acquire a reference on @child that will only
11003 * be released when calling clutter_actor_remove_child().
11005 * This function will take into consideration the #ClutterActor:depth
11006 * of @child, and will keep the list of children sorted.
11008 * This function will emit the #ClutterContainer::actor-added signal
11014 clutter_actor_add_child (ClutterActor *self,
11015 ClutterActor *child)
11017 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11018 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11019 g_return_if_fail (self != child);
11020 g_return_if_fail (child->priv->parent == NULL);
11022 clutter_actor_add_child_internal (self, child,
11023 ADD_CHILD_DEFAULT_FLAGS,
11024 insert_child_at_depth,
11029 * clutter_actor_insert_child_at_index:
11030 * @self: a #ClutterActor
11031 * @child: a #ClutterActor
11032 * @index_: the index
11034 * Inserts @child into the list of children of @self, using the
11035 * given @index_. If @index_ is greater than the number of children
11036 * in @self, or is less than 0, then the new child is added at the end.
11038 * This function will acquire a reference on @child that will only
11039 * be released when calling clutter_actor_remove_child().
11041 * This function will not take into consideration the #ClutterActor:depth
11044 * This function will emit the #ClutterContainer::actor-added signal
11050 clutter_actor_insert_child_at_index (ClutterActor *self,
11051 ClutterActor *child,
11054 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11055 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11056 g_return_if_fail (self != child);
11057 g_return_if_fail (child->priv->parent == NULL);
11059 clutter_actor_add_child_internal (self, child,
11060 ADD_CHILD_DEFAULT_FLAGS,
11061 insert_child_at_index,
11062 GINT_TO_POINTER (index_));
11066 * clutter_actor_insert_child_above:
11067 * @self: a #ClutterActor
11068 * @child: a #ClutterActor
11069 * @sibling: (allow-none): a child of @self, or %NULL
11071 * Inserts @child into the list of children of @self, above another
11072 * child of @self or, if @sibling is %NULL, above all the children
11075 * This function will acquire a reference on @child that will only
11076 * be released when calling clutter_actor_remove_child().
11078 * This function will not take into consideration the #ClutterActor:depth
11081 * This function will emit the #ClutterContainer::actor-added signal
11087 clutter_actor_insert_child_above (ClutterActor *self,
11088 ClutterActor *child,
11089 ClutterActor *sibling)
11091 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11092 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11093 g_return_if_fail (self != child);
11094 g_return_if_fail (child != sibling);
11095 g_return_if_fail (child->priv->parent == NULL);
11096 g_return_if_fail (sibling == NULL ||
11097 (CLUTTER_IS_ACTOR (sibling) &&
11098 sibling->priv->parent == self));
11100 clutter_actor_add_child_internal (self, child,
11101 ADD_CHILD_DEFAULT_FLAGS,
11102 insert_child_above,
11107 * clutter_actor_insert_child_below:
11108 * @self: a #ClutterActor
11109 * @child: a #ClutterActor
11110 * @sibling: (allow-none): a child of @self, or %NULL
11112 * Inserts @child into the list of children of @self, below another
11113 * child of @self or, if @sibling is %NULL, below all the children
11116 * This function will acquire a reference on @child that will only
11117 * be released when calling clutter_actor_remove_child().
11119 * This function will not take into consideration the #ClutterActor:depth
11122 * This function will emit the #ClutterContainer::actor-added signal
11128 clutter_actor_insert_child_below (ClutterActor *self,
11129 ClutterActor *child,
11130 ClutterActor *sibling)
11132 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11133 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11134 g_return_if_fail (self != child);
11135 g_return_if_fail (child != sibling);
11136 g_return_if_fail (child->priv->parent == NULL);
11137 g_return_if_fail (sibling == NULL ||
11138 (CLUTTER_IS_ACTOR (sibling) &&
11139 sibling->priv->parent == self));
11141 clutter_actor_add_child_internal (self, child,
11142 ADD_CHILD_DEFAULT_FLAGS,
11143 insert_child_below,
11148 * clutter_actor_set_parent:
11149 * @self: A #ClutterActor
11150 * @parent: A new #ClutterActor parent
11152 * Sets the parent of @self to @parent.
11154 * This function will result in @parent acquiring a reference on @self,
11155 * eventually by sinking its floating reference first. The reference
11156 * will be released by clutter_actor_unparent().
11158 * This function should only be called by legacy #ClutterActor<!-- -->s
11159 * implementing the #ClutterContainer interface.
11161 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11164 clutter_actor_set_parent (ClutterActor *self,
11165 ClutterActor *parent)
11167 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11168 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11169 g_return_if_fail (self != parent);
11170 g_return_if_fail (self->priv->parent == NULL);
11172 /* as this function will be called inside ClutterContainer::add
11173 * implementations or when building up a composite actor, we have
11174 * to preserve the old behaviour, and not create child meta or
11175 * emit the ::actor-added signal, to avoid recursion or double
11178 clutter_actor_add_child_internal (parent, self,
11179 ADD_CHILD_LEGACY_FLAGS,
11180 insert_child_at_depth,
11185 * clutter_actor_get_parent:
11186 * @self: A #ClutterActor
11188 * Retrieves the parent of @self.
11190 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11191 * if no parent is set
11194 clutter_actor_get_parent (ClutterActor *self)
11196 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11198 return self->priv->parent;
11202 * clutter_actor_get_paint_visibility:
11203 * @self: A #ClutterActor
11205 * Retrieves the 'paint' visibility of an actor recursively checking for non
11208 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11210 * Return Value: %TRUE if the actor is visibile and will be painted.
11215 clutter_actor_get_paint_visibility (ClutterActor *actor)
11217 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11219 return CLUTTER_ACTOR_IS_MAPPED (actor);
11223 * clutter_actor_remove_child:
11224 * @self: a #ClutterActor
11225 * @child: a #ClutterActor
11227 * Removes @child from the children of @self.
11229 * This function will release the reference added by
11230 * clutter_actor_add_child(), so if you want to keep using @child
11231 * you will have to acquire a referenced on it before calling this
11234 * This function will emit the #ClutterContainer::actor-removed
11240 clutter_actor_remove_child (ClutterActor *self,
11241 ClutterActor *child)
11243 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11244 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11245 g_return_if_fail (self != child);
11246 g_return_if_fail (child->priv->parent != NULL);
11247 g_return_if_fail (child->priv->parent == self);
11249 clutter_actor_remove_child_internal (self, child,
11250 REMOVE_CHILD_DEFAULT_FLAGS);
11254 * clutter_actor_remove_all_children:
11255 * @self: a #ClutterActor
11257 * Removes all children of @self.
11259 * This function releases the reference added by inserting a child actor
11260 * in the list of children of @self.
11262 * If the reference count of a child drops to zero, the child will be
11263 * destroyed. If you want to ensure the destruction of all the children
11264 * of @self, use clutter_actor_destroy_all_children().
11269 clutter_actor_remove_all_children (ClutterActor *self)
11271 ClutterActorIter iter;
11273 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11275 if (self->priv->n_children == 0)
11278 g_object_freeze_notify (G_OBJECT (self));
11280 clutter_actor_iter_init (&iter, self);
11281 while (clutter_actor_iter_next (&iter, NULL))
11282 clutter_actor_iter_remove (&iter);
11284 g_object_thaw_notify (G_OBJECT (self));
11287 g_assert (self->priv->first_child == NULL);
11288 g_assert (self->priv->last_child == NULL);
11289 g_assert (self->priv->n_children == 0);
11293 * clutter_actor_destroy_all_children:
11294 * @self: a #ClutterActor
11296 * Destroys all children of @self.
11298 * This function releases the reference added by inserting a child
11299 * actor in the list of children of @self, and ensures that the
11300 * #ClutterActor::destroy signal is emitted on each child of the
11303 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11304 * when its reference count drops to 0; the default handler of the
11305 * #ClutterActor::destroy signal will destroy all the children of an
11306 * actor. This function ensures that all children are destroyed, instead
11307 * of just removed from @self, unlike clutter_actor_remove_all_children()
11308 * which will merely release the reference and remove each child.
11310 * Unless you acquired an additional reference on each child of @self
11311 * prior to calling clutter_actor_remove_all_children() and want to reuse
11312 * the actors, you should use clutter_actor_destroy_all_children() in
11313 * order to make sure that children are destroyed and signal handlers
11314 * are disconnected even in cases where circular references prevent this
11315 * from automatically happening through reference counting alone.
11320 clutter_actor_destroy_all_children (ClutterActor *self)
11322 ClutterActorIter iter;
11324 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11326 if (self->priv->n_children == 0)
11329 g_object_freeze_notify (G_OBJECT (self));
11331 clutter_actor_iter_init (&iter, self);
11332 while (clutter_actor_iter_next (&iter, NULL))
11333 clutter_actor_iter_destroy (&iter);
11335 g_object_thaw_notify (G_OBJECT (self));
11338 g_assert (self->priv->first_child == NULL);
11339 g_assert (self->priv->last_child == NULL);
11340 g_assert (self->priv->n_children == 0);
11343 typedef struct _InsertBetweenData {
11344 ClutterActor *prev_sibling;
11345 ClutterActor *next_sibling;
11346 } InsertBetweenData;
11349 insert_child_between (ClutterActor *self,
11350 ClutterActor *child,
11353 InsertBetweenData *data = data_;
11354 ClutterActor *prev_sibling = data->prev_sibling;
11355 ClutterActor *next_sibling = data->next_sibling;
11357 child->priv->parent = self;
11358 child->priv->prev_sibling = prev_sibling;
11359 child->priv->next_sibling = next_sibling;
11361 if (prev_sibling != NULL)
11362 prev_sibling->priv->next_sibling = child;
11364 if (next_sibling != NULL)
11365 next_sibling->priv->prev_sibling = child;
11367 if (child->priv->prev_sibling == NULL)
11368 self->priv->first_child = child;
11370 if (child->priv->next_sibling == NULL)
11371 self->priv->last_child = child;
11375 * clutter_actor_replace_child:
11376 * @self: a #ClutterActor
11377 * @old_child: the child of @self to replace
11378 * @new_child: the #ClutterActor to replace @old_child
11380 * Replaces @old_child with @new_child in the list of children of @self.
11385 clutter_actor_replace_child (ClutterActor *self,
11386 ClutterActor *old_child,
11387 ClutterActor *new_child)
11389 ClutterActor *prev_sibling, *next_sibling;
11390 InsertBetweenData clos;
11392 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11393 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11394 g_return_if_fail (old_child->priv->parent == self);
11395 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11396 g_return_if_fail (old_child != new_child);
11397 g_return_if_fail (new_child != self);
11398 g_return_if_fail (new_child->priv->parent == NULL);
11400 prev_sibling = old_child->priv->prev_sibling;
11401 next_sibling = old_child->priv->next_sibling;
11402 clutter_actor_remove_child_internal (self, old_child,
11403 REMOVE_CHILD_DEFAULT_FLAGS);
11405 clos.prev_sibling = prev_sibling;
11406 clos.next_sibling = next_sibling;
11407 clutter_actor_add_child_internal (self, new_child,
11408 ADD_CHILD_DEFAULT_FLAGS,
11409 insert_child_between,
11414 * clutter_actor_unparent:
11415 * @self: a #ClutterActor
11417 * Removes the parent of @self.
11419 * This will cause the parent of @self to release the reference
11420 * acquired when calling clutter_actor_set_parent(), so if you
11421 * want to keep @self you will have to acquire a reference of
11422 * your own, through g_object_ref().
11424 * This function should only be called by legacy #ClutterActor<!-- -->s
11425 * implementing the #ClutterContainer interface.
11429 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11432 clutter_actor_unparent (ClutterActor *self)
11434 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11436 if (self->priv->parent == NULL)
11439 clutter_actor_remove_child_internal (self->priv->parent, self,
11440 REMOVE_CHILD_LEGACY_FLAGS);
11444 * clutter_actor_reparent:
11445 * @self: a #ClutterActor
11446 * @new_parent: the new #ClutterActor parent
11448 * Resets the parent actor of @self.
11450 * This function is logically equivalent to calling clutter_actor_unparent()
11451 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11452 * ensures the child is not finalized when unparented, and emits the
11453 * #ClutterActor::parent-set signal only once.
11455 * In reality, calling this function is less useful than it sounds, as some
11456 * application code may rely on changes in the intermediate state between
11457 * removal and addition of the actor from its old parent to the @new_parent.
11458 * Thus, it is strongly encouraged to avoid using this function in application
11463 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11464 * clutter_actor_add_child() instead; remember to take a reference on
11465 * the actor being removed before calling clutter_actor_remove_child()
11466 * to avoid the reference count dropping to zero and the actor being
11470 clutter_actor_reparent (ClutterActor *self,
11471 ClutterActor *new_parent)
11473 ClutterActorPrivate *priv;
11475 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11476 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11477 g_return_if_fail (self != new_parent);
11479 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11481 g_warning ("Cannot set a parent on a toplevel actor");
11485 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11487 g_warning ("Cannot set a parent currently being destroyed");
11493 if (priv->parent != new_parent)
11495 ClutterActor *old_parent;
11497 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11499 old_parent = priv->parent;
11501 g_object_ref (self);
11503 if (old_parent != NULL)
11505 /* go through the Container implementation if this is a regular
11506 * child and not an internal one
11508 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11510 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11512 /* this will have to call unparent() */
11513 clutter_container_remove_actor (parent, self);
11516 clutter_actor_remove_child_internal (old_parent, self,
11517 REMOVE_CHILD_LEGACY_FLAGS);
11520 /* Note, will call set_parent() */
11521 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11522 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11524 clutter_actor_add_child_internal (new_parent, self,
11525 ADD_CHILD_LEGACY_FLAGS,
11526 insert_child_at_depth,
11529 /* we emit the ::parent-set signal once */
11530 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11532 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11534 /* the IN_REPARENT flag suspends state updates */
11535 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11537 g_object_unref (self);
11542 * clutter_actor_contains:
11543 * @self: A #ClutterActor
11544 * @descendant: A #ClutterActor, possibly contained in @self
11546 * Determines if @descendant is contained inside @self (either as an
11547 * immediate child, or as a deeper descendant). If @self and
11548 * @descendant point to the same actor then it will also return %TRUE.
11550 * Return value: whether @descendent is contained within @self
11555 clutter_actor_contains (ClutterActor *self,
11556 ClutterActor *descendant)
11558 ClutterActor *actor;
11560 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11561 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11563 for (actor = descendant; actor; actor = actor->priv->parent)
11571 * clutter_actor_set_child_above_sibling:
11572 * @self: a #ClutterActor
11573 * @child: a #ClutterActor child of @self
11574 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11576 * Sets @child to be above @sibling in the list of children of @self.
11578 * If @sibling is %NULL, @child will be the new last child of @self.
11580 * This function is logically equivalent to removing @child and using
11581 * clutter_actor_insert_child_above(), but it will not emit signals
11582 * or change state on @child.
11587 clutter_actor_set_child_above_sibling (ClutterActor *self,
11588 ClutterActor *child,
11589 ClutterActor *sibling)
11591 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11592 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11593 g_return_if_fail (child->priv->parent == self);
11594 g_return_if_fail (child != sibling);
11595 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11597 if (sibling != NULL)
11598 g_return_if_fail (sibling->priv->parent == self);
11600 /* we don't want to change the state of child, or emit signals, or
11601 * regenerate ChildMeta instances here, but we still want to follow
11602 * the correct sequence of steps encoded in remove_child() and
11603 * add_child(), so that correctness is ensured, and we only go
11604 * through one known code path.
11606 g_object_ref (child);
11607 clutter_actor_remove_child_internal (self, child, 0);
11608 clutter_actor_add_child_internal (self, child,
11609 ADD_CHILD_NOTIFY_FIRST_LAST,
11610 insert_child_above,
11613 clutter_actor_queue_relayout (self);
11617 * clutter_actor_set_child_below_sibling:
11618 * @self: a #ClutterActor
11619 * @child: a #ClutterActor child of @self
11620 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11622 * Sets @child to be below @sibling in the list of children of @self.
11624 * If @sibling is %NULL, @child will be the new first child of @self.
11626 * This function is logically equivalent to removing @self and using
11627 * clutter_actor_insert_child_below(), but it will not emit signals
11628 * or change state on @child.
11633 clutter_actor_set_child_below_sibling (ClutterActor *self,
11634 ClutterActor *child,
11635 ClutterActor *sibling)
11637 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11638 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11639 g_return_if_fail (child->priv->parent == self);
11640 g_return_if_fail (child != sibling);
11641 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11643 if (sibling != NULL)
11644 g_return_if_fail (sibling->priv->parent == self);
11646 /* see the comment in set_child_above_sibling() */
11647 g_object_ref (child);
11648 clutter_actor_remove_child_internal (self, child, 0);
11649 clutter_actor_add_child_internal (self, child,
11650 ADD_CHILD_NOTIFY_FIRST_LAST,
11651 insert_child_below,
11654 clutter_actor_queue_relayout (self);
11658 * clutter_actor_set_child_at_index:
11659 * @self: a #ClutterActor
11660 * @child: a #ClutterActor child of @self
11661 * @index_: the new index for @child
11663 * Changes the index of @child in the list of children of @self.
11665 * This function is logically equivalent to removing @child and
11666 * calling clutter_actor_insert_child_at_index(), but it will not
11667 * emit signals or change state on @child.
11672 clutter_actor_set_child_at_index (ClutterActor *self,
11673 ClutterActor *child,
11676 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11677 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11678 g_return_if_fail (child->priv->parent == self);
11679 g_return_if_fail (index_ <= self->priv->n_children);
11681 g_object_ref (child);
11682 clutter_actor_remove_child_internal (self, child, 0);
11683 clutter_actor_add_child_internal (self, child,
11684 ADD_CHILD_NOTIFY_FIRST_LAST,
11685 insert_child_at_index,
11686 GINT_TO_POINTER (index_));
11688 clutter_actor_queue_relayout (self);
11692 * clutter_actor_raise:
11693 * @self: A #ClutterActor
11694 * @below: (allow-none): A #ClutterActor to raise above.
11696 * Puts @self above @below.
11698 * Both actors must have the same parent, and the parent must implement
11699 * the #ClutterContainer interface
11701 * This function calls clutter_container_raise_child() internally.
11703 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11706 clutter_actor_raise (ClutterActor *self,
11707 ClutterActor *below)
11709 ClutterActor *parent;
11711 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11713 parent = clutter_actor_get_parent (self);
11714 if (parent == NULL)
11716 g_warning ("%s: Actor '%s' is not inside a container",
11718 _clutter_actor_get_debug_name (self));
11724 if (parent != clutter_actor_get_parent (below))
11726 g_warning ("%s Actor '%s' is not in the same container as "
11729 _clutter_actor_get_debug_name (self),
11730 _clutter_actor_get_debug_name (below));
11735 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11739 * clutter_actor_lower:
11740 * @self: A #ClutterActor
11741 * @above: (allow-none): A #ClutterActor to lower below
11743 * Puts @self below @above.
11745 * Both actors must have the same parent, and the parent must implement
11746 * the #ClutterContainer interface.
11748 * This function calls clutter_container_lower_child() internally.
11750 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11753 clutter_actor_lower (ClutterActor *self,
11754 ClutterActor *above)
11756 ClutterActor *parent;
11758 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11760 parent = clutter_actor_get_parent (self);
11761 if (parent == NULL)
11763 g_warning ("%s: Actor of type %s is not inside a container",
11765 _clutter_actor_get_debug_name (self));
11771 if (parent != clutter_actor_get_parent (above))
11773 g_warning ("%s: Actor '%s' is not in the same container as "
11776 _clutter_actor_get_debug_name (self),
11777 _clutter_actor_get_debug_name (above));
11782 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11786 * clutter_actor_raise_top:
11787 * @self: A #ClutterActor
11789 * Raises @self to the top.
11791 * This function calls clutter_actor_raise() internally.
11793 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11794 * a %NULL sibling, instead.
11797 clutter_actor_raise_top (ClutterActor *self)
11799 clutter_actor_raise (self, NULL);
11803 * clutter_actor_lower_bottom:
11804 * @self: A #ClutterActor
11806 * Lowers @self to the bottom.
11808 * This function calls clutter_actor_lower() internally.
11810 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11811 * a %NULL sibling, instead.
11814 clutter_actor_lower_bottom (ClutterActor *self)
11816 clutter_actor_lower (self, NULL);
11824 * clutter_actor_event:
11825 * @actor: a #ClutterActor
11826 * @event: a #ClutterEvent
11827 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11829 * This function is used to emit an event on the main stage.
11830 * You should rarely need to use this function, except for
11831 * synthetising events.
11833 * Return value: the return value from the signal emission: %TRUE
11834 * if the actor handled the event, or %FALSE if the event was
11840 clutter_actor_event (ClutterActor *actor,
11841 ClutterEvent *event,
11844 gboolean retval = FALSE;
11845 gint signal_num = -1;
11847 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11848 g_return_val_if_fail (event != NULL, FALSE);
11850 g_object_ref (actor);
11854 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11860 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11864 switch (event->type)
11866 case CLUTTER_NOTHING:
11868 case CLUTTER_BUTTON_PRESS:
11869 signal_num = BUTTON_PRESS_EVENT;
11871 case CLUTTER_BUTTON_RELEASE:
11872 signal_num = BUTTON_RELEASE_EVENT;
11874 case CLUTTER_SCROLL:
11875 signal_num = SCROLL_EVENT;
11877 case CLUTTER_KEY_PRESS:
11878 signal_num = KEY_PRESS_EVENT;
11880 case CLUTTER_KEY_RELEASE:
11881 signal_num = KEY_RELEASE_EVENT;
11883 case CLUTTER_MOTION:
11884 signal_num = MOTION_EVENT;
11886 case CLUTTER_ENTER:
11887 signal_num = ENTER_EVENT;
11889 case CLUTTER_LEAVE:
11890 signal_num = LEAVE_EVENT;
11892 case CLUTTER_DELETE:
11893 case CLUTTER_DESTROY_NOTIFY:
11894 case CLUTTER_CLIENT_MESSAGE:
11900 if (signal_num != -1)
11901 g_signal_emit (actor, actor_signals[signal_num], 0,
11906 g_object_unref (actor);
11912 * clutter_actor_set_reactive:
11913 * @actor: a #ClutterActor
11914 * @reactive: whether the actor should be reactive to events
11916 * Sets @actor as reactive. Reactive actors will receive events.
11921 clutter_actor_set_reactive (ClutterActor *actor,
11924 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11926 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11930 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11932 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11934 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11938 * clutter_actor_get_reactive:
11939 * @actor: a #ClutterActor
11941 * Checks whether @actor is marked as reactive.
11943 * Return value: %TRUE if the actor is reactive
11948 clutter_actor_get_reactive (ClutterActor *actor)
11950 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11952 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11956 * clutter_actor_get_anchor_point:
11957 * @self: a #ClutterActor
11958 * @anchor_x: (out): return location for the X coordinate of the anchor point
11959 * @anchor_y: (out): return location for the Y coordinate of the anchor point
11961 * Gets the current anchor point of the @actor in pixels.
11966 clutter_actor_get_anchor_point (ClutterActor *self,
11970 const ClutterTransformInfo *info;
11972 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11974 info = _clutter_actor_get_transform_info_or_defaults (self);
11975 clutter_anchor_coord_get_units (self, &info->anchor,
11982 * clutter_actor_set_anchor_point:
11983 * @self: a #ClutterActor
11984 * @anchor_x: X coordinate of the anchor point
11985 * @anchor_y: Y coordinate of the anchor point
11987 * Sets an anchor point for @self. The anchor point is a point in the
11988 * coordinate space of an actor to which the actor position within its
11989 * parent is relative; the default is (0, 0), i.e. the top-left corner
11995 clutter_actor_set_anchor_point (ClutterActor *self,
11999 ClutterTransformInfo *info;
12000 ClutterActorPrivate *priv;
12001 gboolean changed = FALSE;
12002 gfloat old_anchor_x, old_anchor_y;
12005 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12007 obj = G_OBJECT (self);
12009 info = _clutter_actor_get_transform_info (self);
12011 g_object_freeze_notify (obj);
12013 clutter_anchor_coord_get_units (self, &info->anchor,
12018 if (info->anchor.is_fractional)
12019 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12021 if (old_anchor_x != anchor_x)
12023 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12027 if (old_anchor_y != anchor_y)
12029 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12033 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12037 priv->transform_valid = FALSE;
12038 clutter_actor_queue_redraw (self);
12041 g_object_thaw_notify (obj);
12045 * clutter_actor_get_anchor_point_gravity:
12046 * @self: a #ClutterActor
12048 * Retrieves the anchor position expressed as a #ClutterGravity. If
12049 * the anchor point was specified using pixels or units this will
12050 * return %CLUTTER_GRAVITY_NONE.
12052 * Return value: the #ClutterGravity used by the anchor point
12057 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12059 const ClutterTransformInfo *info;
12061 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12063 info = _clutter_actor_get_transform_info_or_defaults (self);
12065 return clutter_anchor_coord_get_gravity (&info->anchor);
12069 * clutter_actor_move_anchor_point:
12070 * @self: a #ClutterActor
12071 * @anchor_x: X coordinate of the anchor point
12072 * @anchor_y: Y coordinate of the anchor point
12074 * Sets an anchor point for the actor, and adjusts the actor postion so that
12075 * the relative position of the actor toward its parent remains the same.
12080 clutter_actor_move_anchor_point (ClutterActor *self,
12084 gfloat old_anchor_x, old_anchor_y;
12085 const ClutterTransformInfo *info;
12087 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12089 info = _clutter_actor_get_transform_info (self);
12090 clutter_anchor_coord_get_units (self, &info->anchor,
12095 g_object_freeze_notify (G_OBJECT (self));
12097 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12099 if (self->priv->position_set)
12100 clutter_actor_move_by (self,
12101 anchor_x - old_anchor_x,
12102 anchor_y - old_anchor_y);
12104 g_object_thaw_notify (G_OBJECT (self));
12108 * clutter_actor_move_anchor_point_from_gravity:
12109 * @self: a #ClutterActor
12110 * @gravity: #ClutterGravity.
12112 * Sets an anchor point on the actor based on the given gravity, adjusting the
12113 * actor postion so that its relative position within its parent remains
12116 * Since version 1.0 the anchor point will be stored as a gravity so
12117 * that if the actor changes size then the anchor point will move. For
12118 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12119 * and later double the size of the actor, the anchor point will move
12120 * to the bottom right.
12125 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12126 ClutterGravity gravity)
12128 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12129 const ClutterTransformInfo *info;
12130 ClutterActorPrivate *priv;
12132 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12135 info = _clutter_actor_get_transform_info (self);
12137 g_object_freeze_notify (G_OBJECT (self));
12139 clutter_anchor_coord_get_units (self, &info->anchor,
12143 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12144 clutter_anchor_coord_get_units (self, &info->anchor,
12149 if (priv->position_set)
12150 clutter_actor_move_by (self,
12151 new_anchor_x - old_anchor_x,
12152 new_anchor_y - old_anchor_y);
12154 g_object_thaw_notify (G_OBJECT (self));
12158 * clutter_actor_set_anchor_point_from_gravity:
12159 * @self: a #ClutterActor
12160 * @gravity: #ClutterGravity.
12162 * Sets an anchor point on the actor, based on the given gravity (this is a
12163 * convenience function wrapping clutter_actor_set_anchor_point()).
12165 * Since version 1.0 the anchor point will be stored as a gravity so
12166 * that if the actor changes size then the anchor point will move. For
12167 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12168 * and later double the size of the actor, the anchor point will move
12169 * to the bottom right.
12174 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12175 ClutterGravity gravity)
12177 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12179 if (gravity == CLUTTER_GRAVITY_NONE)
12180 clutter_actor_set_anchor_point (self, 0, 0);
12183 GObject *obj = G_OBJECT (self);
12184 ClutterTransformInfo *info;
12186 g_object_freeze_notify (obj);
12188 info = _clutter_actor_get_transform_info (self);
12189 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12191 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12192 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12193 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12195 self->priv->transform_valid = FALSE;
12197 clutter_actor_queue_redraw (self);
12199 g_object_thaw_notify (obj);
12204 clutter_container_iface_init (ClutterContainerIface *iface)
12206 /* we don't override anything, as ClutterContainer already has a default
12207 * implementation that we can use, and which calls into our own API.
12222 parse_units (ClutterActor *self,
12223 ParseDimension dimension,
12226 GValue value = { 0, };
12229 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12232 json_node_get_value (node, &value);
12234 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12236 retval = (gfloat) g_value_get_int64 (&value);
12238 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12240 retval = g_value_get_double (&value);
12242 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12244 ClutterUnits units;
12247 res = clutter_units_from_string (&units, g_value_get_string (&value));
12249 retval = clutter_units_to_pixels (&units);
12252 g_warning ("Invalid value '%s': integers, strings or floating point "
12253 "values can be used for the x, y, width and height "
12254 "properties. Valid modifiers for strings are 'px', 'mm', "
12256 g_value_get_string (&value));
12262 g_warning ("Invalid value of type '%s': integers, strings of floating "
12263 "point values can be used for the x, y, width, height "
12264 "anchor-x and anchor-y properties.",
12265 g_type_name (G_VALUE_TYPE (&value)));
12268 g_value_unset (&value);
12274 ClutterRotateAxis axis;
12283 static inline gboolean
12284 parse_rotation_array (ClutterActor *actor,
12286 RotationInfo *info)
12290 if (json_array_get_length (array) != 2)
12294 element = json_array_get_element (array, 0);
12295 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12296 info->angle = json_node_get_double (element);
12301 element = json_array_get_element (array, 1);
12302 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12304 JsonArray *center = json_node_get_array (element);
12306 if (json_array_get_length (center) != 2)
12309 switch (info->axis)
12311 case CLUTTER_X_AXIS:
12312 info->center_y = parse_units (actor, PARSE_Y,
12313 json_array_get_element (center, 0));
12314 info->center_z = parse_units (actor, PARSE_Y,
12315 json_array_get_element (center, 1));
12318 case CLUTTER_Y_AXIS:
12319 info->center_x = parse_units (actor, PARSE_X,
12320 json_array_get_element (center, 0));
12321 info->center_z = parse_units (actor, PARSE_X,
12322 json_array_get_element (center, 1));
12325 case CLUTTER_Z_AXIS:
12326 info->center_x = parse_units (actor, PARSE_X,
12327 json_array_get_element (center, 0));
12328 info->center_y = parse_units (actor, PARSE_Y,
12329 json_array_get_element (center, 1));
12338 parse_rotation (ClutterActor *actor,
12340 RotationInfo *info)
12344 gboolean retval = FALSE;
12346 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12348 g_warning ("Invalid node of type '%s' found, expecting an array",
12349 json_node_type_name (node));
12353 array = json_node_get_array (node);
12354 len = json_array_get_length (array);
12356 for (i = 0; i < len; i++)
12358 JsonNode *element = json_array_get_element (array, i);
12359 JsonObject *object;
12362 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12364 g_warning ("Invalid node of type '%s' found, expecting an object",
12365 json_node_type_name (element));
12369 object = json_node_get_object (element);
12371 if (json_object_has_member (object, "x-axis"))
12373 member = json_object_get_member (object, "x-axis");
12375 info->axis = CLUTTER_X_AXIS;
12377 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12379 info->angle = json_node_get_double (member);
12382 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12383 retval = parse_rotation_array (actor,
12384 json_node_get_array (member),
12389 else if (json_object_has_member (object, "y-axis"))
12391 member = json_object_get_member (object, "y-axis");
12393 info->axis = CLUTTER_Y_AXIS;
12395 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12397 info->angle = json_node_get_double (member);
12400 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12401 retval = parse_rotation_array (actor,
12402 json_node_get_array (member),
12407 else if (json_object_has_member (object, "z-axis"))
12409 member = json_object_get_member (object, "z-axis");
12411 info->axis = CLUTTER_Z_AXIS;
12413 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12415 info->angle = json_node_get_double (member);
12418 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12419 retval = parse_rotation_array (actor,
12420 json_node_get_array (member),
12431 parse_actor_metas (ClutterScript *script,
12432 ClutterActor *actor,
12435 GList *elements, *l;
12436 GSList *retval = NULL;
12438 if (!JSON_NODE_HOLDS_ARRAY (node))
12441 elements = json_array_get_elements (json_node_get_array (node));
12443 for (l = elements; l != NULL; l = l->next)
12445 JsonNode *element = l->data;
12446 const gchar *id_ = _clutter_script_get_id_from_node (element);
12449 if (id_ == NULL || *id_ == '\0')
12452 meta = clutter_script_get_object (script, id_);
12456 retval = g_slist_prepend (retval, meta);
12459 g_list_free (elements);
12461 return g_slist_reverse (retval);
12465 parse_behaviours (ClutterScript *script,
12466 ClutterActor *actor,
12469 GList *elements, *l;
12470 GSList *retval = NULL;
12472 if (!JSON_NODE_HOLDS_ARRAY (node))
12475 elements = json_array_get_elements (json_node_get_array (node));
12477 for (l = elements; l != NULL; l = l->next)
12479 JsonNode *element = l->data;
12480 const gchar *id_ = _clutter_script_get_id_from_node (element);
12481 GObject *behaviour;
12483 if (id_ == NULL || *id_ == '\0')
12486 behaviour = clutter_script_get_object (script, id_);
12487 if (behaviour == NULL)
12490 retval = g_slist_prepend (retval, behaviour);
12493 g_list_free (elements);
12495 return g_slist_reverse (retval);
12499 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12500 ClutterScript *script,
12505 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12506 gboolean retval = FALSE;
12508 if ((name[0] == 'x' && name[1] == '\0') ||
12509 (name[0] == 'y' && name[1] == '\0') ||
12510 (strcmp (name, "width") == 0) ||
12511 (strcmp (name, "height") == 0) ||
12512 (strcmp (name, "anchor_x") == 0) ||
12513 (strcmp (name, "anchor_y") == 0))
12515 ParseDimension dimension;
12518 if (name[0] == 'x')
12519 dimension = PARSE_X;
12520 else if (name[0] == 'y')
12521 dimension = PARSE_Y;
12522 else if (name[0] == 'w')
12523 dimension = PARSE_WIDTH;
12524 else if (name[0] == 'h')
12525 dimension = PARSE_HEIGHT;
12526 else if (name[0] == 'a' && name[7] == 'x')
12527 dimension = PARSE_ANCHOR_X;
12528 else if (name[0] == 'a' && name[7] == 'y')
12529 dimension = PARSE_ANCHOR_Y;
12533 units = parse_units (actor, dimension, node);
12535 /* convert back to pixels: all properties are pixel-based */
12536 g_value_init (value, G_TYPE_FLOAT);
12537 g_value_set_float (value, units);
12541 else if (strcmp (name, "rotation") == 0)
12543 RotationInfo *info;
12545 info = g_slice_new0 (RotationInfo);
12546 retval = parse_rotation (actor, node, info);
12550 g_value_init (value, G_TYPE_POINTER);
12551 g_value_set_pointer (value, info);
12554 g_slice_free (RotationInfo, info);
12556 else if (strcmp (name, "behaviours") == 0)
12560 #ifdef CLUTTER_ENABLE_DEBUG
12561 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12562 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12563 "and it should not be used in newly "
12564 "written ClutterScript definitions.");
12567 l = parse_behaviours (script, actor, node);
12569 g_value_init (value, G_TYPE_POINTER);
12570 g_value_set_pointer (value, l);
12574 else if (strcmp (name, "actions") == 0 ||
12575 strcmp (name, "constraints") == 0 ||
12576 strcmp (name, "effects") == 0)
12580 l = parse_actor_metas (script, actor, node);
12582 g_value_init (value, G_TYPE_POINTER);
12583 g_value_set_pointer (value, l);
12592 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12593 ClutterScript *script,
12595 const GValue *value)
12597 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12599 #ifdef CLUTTER_ENABLE_DEBUG
12600 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12602 gchar *tmp = g_strdup_value_contents (value);
12604 CLUTTER_NOTE (SCRIPT,
12605 "in ClutterActor::set_custom_property('%s') = %s",
12611 #endif /* CLUTTER_ENABLE_DEBUG */
12613 if (strcmp (name, "rotation") == 0)
12615 RotationInfo *info;
12617 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12620 info = g_value_get_pointer (value);
12622 clutter_actor_set_rotation (actor,
12623 info->axis, info->angle,
12628 g_slice_free (RotationInfo, info);
12633 if (strcmp (name, "behaviours") == 0)
12635 GSList *behaviours, *l;
12637 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12640 behaviours = g_value_get_pointer (value);
12641 for (l = behaviours; l != NULL; l = l->next)
12643 ClutterBehaviour *behaviour = l->data;
12645 clutter_behaviour_apply (behaviour, actor);
12648 g_slist_free (behaviours);
12653 if (strcmp (name, "actions") == 0 ||
12654 strcmp (name, "constraints") == 0 ||
12655 strcmp (name, "effects") == 0)
12659 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12662 metas = g_value_get_pointer (value);
12663 for (l = metas; l != NULL; l = l->next)
12665 if (name[0] == 'a')
12666 clutter_actor_add_action (actor, l->data);
12668 if (name[0] == 'c')
12669 clutter_actor_add_constraint (actor, l->data);
12671 if (name[0] == 'e')
12672 clutter_actor_add_effect (actor, l->data);
12675 g_slist_free (metas);
12680 g_object_set_property (G_OBJECT (scriptable), name, value);
12684 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12686 iface->parse_custom_node = clutter_actor_parse_custom_node;
12687 iface->set_custom_property = clutter_actor_set_custom_property;
12690 static ClutterActorMeta *
12691 get_meta_from_animation_property (ClutterActor *actor,
12695 ClutterActorPrivate *priv = actor->priv;
12696 ClutterActorMeta *meta = NULL;
12699 /* if this is not a special property, fall through */
12700 if (name[0] != '@')
12703 /* detect the properties named using the following spec:
12705 * @<section>.<meta-name>.<property-name>
12707 * where <section> can be one of the following:
12713 * and <meta-name> is the name set on a specific ActorMeta
12716 tokens = g_strsplit (name + 1, ".", -1);
12717 if (tokens == NULL || g_strv_length (tokens) != 3)
12719 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12721 g_strfreev (tokens);
12725 if (strcmp (tokens[0], "actions") == 0)
12726 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12728 if (strcmp (tokens[0], "constraints") == 0)
12729 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12731 if (strcmp (tokens[0], "effects") == 0)
12732 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12734 if (name_p != NULL)
12735 *name_p = g_strdup (tokens[2]);
12737 CLUTTER_NOTE (ANIMATION,
12738 "Looking for property '%s' of object '%s' in section '%s'",
12743 g_strfreev (tokens);
12748 static GParamSpec *
12749 clutter_actor_find_property (ClutterAnimatable *animatable,
12750 const gchar *property_name)
12752 ClutterActorMeta *meta = NULL;
12753 GObjectClass *klass = NULL;
12754 GParamSpec *pspec = NULL;
12755 gchar *p_name = NULL;
12757 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12763 klass = G_OBJECT_GET_CLASS (meta);
12765 pspec = g_object_class_find_property (klass, p_name);
12769 klass = G_OBJECT_GET_CLASS (animatable);
12771 pspec = g_object_class_find_property (klass, property_name);
12780 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12781 const gchar *property_name,
12784 ClutterActorMeta *meta = NULL;
12785 gchar *p_name = NULL;
12787 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12792 g_object_get_property (G_OBJECT (meta), p_name, initial);
12794 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12800 * clutter_actor_set_animatable_property:
12801 * @actor: a #ClutterActor
12802 * @prop_id: the paramspec id
12803 * @value: the value to set
12804 * @pspec: the paramspec
12806 * Sets values of animatable properties.
12808 * This is a variant of clutter_actor_set_property() that gets called
12809 * by the #ClutterAnimatable implementation of #ClutterActor for the
12810 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12813 * Unlike the implementation of #GObjectClass.set_property(), this
12814 * function will not update the interval if a transition involving an
12815 * animatable property is in progress - this avoids cycles with the
12816 * transition API calling the public API.
12819 clutter_actor_set_animatable_property (ClutterActor *actor,
12821 const GValue *value,
12827 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12831 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12835 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12839 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12843 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12847 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12850 case PROP_BACKGROUND_COLOR:
12851 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12855 clutter_actor_set_scale_factor_internal (actor,
12856 g_value_get_double (value),
12861 clutter_actor_set_scale_factor_internal (actor,
12862 g_value_get_double (value),
12866 case PROP_ROTATION_ANGLE_X:
12867 clutter_actor_set_rotation_angle_internal (actor,
12869 g_value_get_double (value));
12872 case PROP_ROTATION_ANGLE_Y:
12873 clutter_actor_set_rotation_angle_internal (actor,
12875 g_value_get_double (value));
12878 case PROP_ROTATION_ANGLE_Z:
12879 clutter_actor_set_rotation_angle_internal (actor,
12881 g_value_get_double (value));
12885 g_object_set_property (G_OBJECT (actor), pspec->name, value);
12891 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12892 const gchar *property_name,
12893 const GValue *final)
12895 ClutterActor *actor = CLUTTER_ACTOR (animatable);
12896 ClutterActorMeta *meta = NULL;
12897 gchar *p_name = NULL;
12899 meta = get_meta_from_animation_property (actor,
12903 g_object_set_property (G_OBJECT (meta), p_name, final);
12906 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12909 pspec = g_object_class_find_property (obj_class, property_name);
12911 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12913 /* XXX - I'm going to the special hell for this */
12914 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12917 g_object_set_property (G_OBJECT (animatable), property_name, final);
12924 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12926 iface->find_property = clutter_actor_find_property;
12927 iface->get_initial_state = clutter_actor_get_initial_state;
12928 iface->set_final_state = clutter_actor_set_final_state;
12932 * clutter_actor_transform_stage_point:
12933 * @self: A #ClutterActor
12934 * @x: (in): x screen coordinate of the point to unproject
12935 * @y: (in): y screen coordinate of the point to unproject
12936 * @x_out: (out): return location for the unprojected x coordinance
12937 * @y_out: (out): return location for the unprojected y coordinance
12939 * This function translates screen coordinates (@x, @y) to
12940 * coordinates relative to the actor. For example, it can be used to translate
12941 * screen events from global screen coordinates into actor-local coordinates.
12943 * The conversion can fail, notably if the transform stack results in the
12944 * actor being projected on the screen as a mere line.
12946 * The conversion should not be expected to be pixel-perfect due to the
12947 * nature of the operation. In general the error grows when the skewing
12948 * of the actor rectangle on screen increases.
12950 * <note><para>This function can be computationally intensive.</para></note>
12952 * <note><para>This function only works when the allocation is up-to-date,
12953 * i.e. inside of paint().</para></note>
12955 * Return value: %TRUE if conversion was successful.
12960 clutter_actor_transform_stage_point (ClutterActor *self,
12966 ClutterVertex v[4];
12969 int du, dv, xi, yi;
12971 float xf, yf, wf, det;
12972 ClutterActorPrivate *priv;
12974 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12978 /* This implementation is based on the quad -> quad projection algorithm
12979 * described by Paul Heckbert in:
12981 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12983 * and the sample implementation at:
12985 * http://www.cs.cmu.edu/~ph/src/texfund/
12987 * Our texture is a rectangle with origin [0, 0], so we are mapping from
12988 * quad to rectangle only, which significantly simplifies things; the
12989 * function calls have been unrolled, and most of the math is done in fixed
12993 clutter_actor_get_abs_allocation_vertices (self, v);
12995 /* Keeping these as ints simplifies the multiplication (no significant
12996 * loss of precision here).
12998 du = (int) (priv->allocation.x2 - priv->allocation.x1);
12999 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13004 #define UX2FP(x) (x)
13005 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13007 /* First, find mapping from unit uv square to xy quadrilateral; this
13008 * equivalent to the pmap_square_quad() functions in the sample
13009 * implementation, which we can simplify, since our target is always
13012 px = v[0].x - v[1].x + v[3].x - v[2].x;
13013 py = v[0].y - v[1].y + v[3].y - v[2].y;
13017 /* affine transform */
13018 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13019 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13020 RQ[2][0] = UX2FP (v[0].x);
13021 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13022 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13023 RQ[2][1] = UX2FP (v[0].y);
13030 /* projective transform */
13031 double dx1, dx2, dy1, dy2, del;
13033 dx1 = UX2FP (v[1].x - v[3].x);
13034 dx2 = UX2FP (v[2].x - v[3].x);
13035 dy1 = UX2FP (v[1].y - v[3].y);
13036 dy2 = UX2FP (v[2].y - v[3].y);
13038 del = DET2FP (dx1, dx2, dy1, dy2);
13043 * The division here needs to be done in floating point for
13044 * precisions reasons.
13046 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13047 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13048 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13050 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13051 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13052 RQ[2][0] = UX2FP (v[0].x);
13053 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13054 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13055 RQ[2][1] = UX2FP (v[0].y);
13059 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13060 * square. Since our rectangle is based at 0,0 we only need to scale.
13070 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13073 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13074 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13075 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13076 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13077 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13078 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13079 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13080 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13081 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13084 * Check the resulting matrix is OK.
13086 det = (RQ[0][0] * ST[0][0])
13087 + (RQ[0][1] * ST[0][1])
13088 + (RQ[0][2] * ST[0][2]);
13093 * Now transform our point with the ST matrix; the notional w
13094 * coordinate is 1, hence the last part is simply added.
13099 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13100 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13101 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13119 static ClutterGeometry*
13120 clutter_geometry_copy (const ClutterGeometry *geometry)
13122 return g_slice_dup (ClutterGeometry, geometry);
13126 clutter_geometry_free (ClutterGeometry *geometry)
13128 if (G_LIKELY (geometry != NULL))
13129 g_slice_free (ClutterGeometry, geometry);
13133 * clutter_geometry_union:
13134 * @geometry_a: a #ClutterGeometry
13135 * @geometry_b: another #ClutterGeometry
13136 * @result: (out): location to store the result
13138 * Find the union of two rectangles represented as #ClutterGeometry.
13143 clutter_geometry_union (const ClutterGeometry *geometry_a,
13144 const ClutterGeometry *geometry_b,
13145 ClutterGeometry *result)
13147 /* We don't try to handle rectangles that can't be represented
13148 * as a signed integer box */
13149 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13150 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13151 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13152 geometry_b->x + (gint)geometry_b->width);
13153 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13154 geometry_b->y + (gint)geometry_b->height);
13157 result->width = x_2 - x_1;
13158 result->height = y_2 - y_1;
13162 * clutter_geometry_intersects:
13163 * @geometry0: The first geometry to test
13164 * @geometry1: The second geometry to test
13166 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13167 * they do else %FALSE.
13169 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13175 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13176 const ClutterGeometry *geometry1)
13178 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13179 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13180 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13181 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13188 clutter_geometry_progress (const GValue *a,
13193 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13194 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13195 ClutterGeometry res = { 0, };
13196 gint a_width = a_geom->width;
13197 gint b_width = b_geom->width;
13198 gint a_height = a_geom->height;
13199 gint b_height = b_geom->height;
13201 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13202 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13204 res.width = a_width + (b_width - a_width) * progress;
13205 res.height = a_height + (b_height - a_height) * progress;
13207 g_value_set_boxed (retval, &res);
13212 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13213 clutter_geometry_copy,
13214 clutter_geometry_free,
13215 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13222 * clutter_vertex_new:
13227 * Creates a new #ClutterVertex for the point in 3D space
13228 * identified by the 3 coordinates @x, @y, @z
13230 * Return value: the newly allocate #ClutterVertex. Use
13231 * clutter_vertex_free() to free the resources
13236 clutter_vertex_new (gfloat x,
13240 ClutterVertex *vertex;
13242 vertex = g_slice_new (ClutterVertex);
13251 * clutter_vertex_copy:
13252 * @vertex: a #ClutterVertex
13256 * Return value: a newly allocated copy of #ClutterVertex. Use
13257 * clutter_vertex_free() to free the allocated resources
13262 clutter_vertex_copy (const ClutterVertex *vertex)
13264 if (G_LIKELY (vertex != NULL))
13265 return g_slice_dup (ClutterVertex, vertex);
13271 * clutter_vertex_free:
13272 * @vertex: a #ClutterVertex
13274 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13279 clutter_vertex_free (ClutterVertex *vertex)
13281 if (G_UNLIKELY (vertex != NULL))
13282 g_slice_free (ClutterVertex, vertex);
13286 * clutter_vertex_equal:
13287 * @vertex_a: a #ClutterVertex
13288 * @vertex_b: a #ClutterVertex
13290 * Compares @vertex_a and @vertex_b for equality
13292 * Return value: %TRUE if the passed #ClutterVertex are equal
13297 clutter_vertex_equal (const ClutterVertex *vertex_a,
13298 const ClutterVertex *vertex_b)
13300 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13302 if (vertex_a == vertex_b)
13305 return vertex_a->x == vertex_b->x &&
13306 vertex_a->y == vertex_b->y &&
13307 vertex_a->z == vertex_b->z;
13311 clutter_vertex_progress (const GValue *a,
13316 const ClutterVertex *av = g_value_get_boxed (a);
13317 const ClutterVertex *bv = g_value_get_boxed (b);
13318 ClutterVertex res = { 0, };
13320 res.x = av->x + (bv->x - av->x) * progress;
13321 res.y = av->y + (bv->y - av->y) * progress;
13322 res.z = av->z + (bv->z - av->z) * progress;
13324 g_value_set_boxed (retval, &res);
13329 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13330 clutter_vertex_copy,
13331 clutter_vertex_free,
13332 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13335 * clutter_actor_is_rotated:
13336 * @self: a #ClutterActor
13338 * Checks whether any rotation is applied to the actor.
13340 * Return value: %TRUE if the actor is rotated.
13345 clutter_actor_is_rotated (ClutterActor *self)
13347 const ClutterTransformInfo *info;
13349 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13351 info = _clutter_actor_get_transform_info_or_defaults (self);
13353 if (info->rx_angle || info->ry_angle || info->rz_angle)
13360 * clutter_actor_is_scaled:
13361 * @self: a #ClutterActor
13363 * Checks whether the actor is scaled in either dimension.
13365 * Return value: %TRUE if the actor is scaled.
13370 clutter_actor_is_scaled (ClutterActor *self)
13372 const ClutterTransformInfo *info;
13374 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13376 info = _clutter_actor_get_transform_info_or_defaults (self);
13378 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13385 _clutter_actor_get_stage_internal (ClutterActor *actor)
13387 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13388 actor = actor->priv->parent;
13394 * clutter_actor_get_stage:
13395 * @actor: a #ClutterActor
13397 * Retrieves the #ClutterStage where @actor is contained.
13399 * Return value: (transfer none) (type Clutter.Stage): the stage
13400 * containing the actor, or %NULL
13405 clutter_actor_get_stage (ClutterActor *actor)
13407 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13409 return _clutter_actor_get_stage_internal (actor);
13413 * clutter_actor_allocate_available_size:
13414 * @self: a #ClutterActor
13415 * @x: the actor's X coordinate
13416 * @y: the actor's Y coordinate
13417 * @available_width: the maximum available width, or -1 to use the
13418 * actor's natural width
13419 * @available_height: the maximum available height, or -1 to use the
13420 * actor's natural height
13421 * @flags: flags controlling the allocation
13423 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13424 * preferred size, but limiting it to the maximum available width
13425 * and height provided.
13427 * This function will do the right thing when dealing with the
13428 * actor's request mode.
13430 * The implementation of this function is equivalent to:
13433 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13435 * clutter_actor_get_preferred_width (self, available_height,
13437 * &natural_width);
13438 * width = CLAMP (natural_width, min_width, available_width);
13440 * clutter_actor_get_preferred_height (self, width,
13442 * &natural_height);
13443 * height = CLAMP (natural_height, min_height, available_height);
13447 * clutter_actor_get_preferred_height (self, available_width,
13449 * &natural_height);
13450 * height = CLAMP (natural_height, min_height, available_height);
13452 * clutter_actor_get_preferred_width (self, height,
13454 * &natural_width);
13455 * width = CLAMP (natural_width, min_width, available_width);
13458 * box.x1 = x; box.y1 = y;
13459 * box.x2 = box.x1 + available_width;
13460 * box.y2 = box.y1 + available_height;
13461 * clutter_actor_allocate (self, &box, flags);
13464 * This function can be used by fluid layout managers to allocate
13465 * an actor's preferred size without making it bigger than the area
13466 * available for the container.
13471 clutter_actor_allocate_available_size (ClutterActor *self,
13474 gfloat available_width,
13475 gfloat available_height,
13476 ClutterAllocationFlags flags)
13478 ClutterActorPrivate *priv;
13479 gfloat width, height;
13480 gfloat min_width, min_height;
13481 gfloat natural_width, natural_height;
13482 ClutterActorBox box;
13484 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13488 width = height = 0.0;
13490 switch (priv->request_mode)
13492 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13493 clutter_actor_get_preferred_width (self, available_height,
13496 width = CLAMP (natural_width, min_width, available_width);
13498 clutter_actor_get_preferred_height (self, width,
13501 height = CLAMP (natural_height, min_height, available_height);
13504 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13505 clutter_actor_get_preferred_height (self, available_width,
13508 height = CLAMP (natural_height, min_height, available_height);
13510 clutter_actor_get_preferred_width (self, height,
13513 width = CLAMP (natural_width, min_width, available_width);
13520 box.x2 = box.x1 + width;
13521 box.y2 = box.y1 + height;
13522 clutter_actor_allocate (self, &box, flags);
13526 * clutter_actor_allocate_preferred_size:
13527 * @self: a #ClutterActor
13528 * @flags: flags controlling the allocation
13530 * Allocates the natural size of @self.
13532 * This function is a utility call for #ClutterActor implementations
13533 * that allocates the actor's preferred natural size. It can be used
13534 * by fixed layout managers (like #ClutterGroup or so called
13535 * 'composite actors') inside the ClutterActor::allocate
13536 * implementation to give each child exactly how much space it
13539 * This function is not meant to be used by applications. It is also
13540 * not meant to be used outside the implementation of the
13541 * ClutterActor::allocate virtual function.
13546 clutter_actor_allocate_preferred_size (ClutterActor *self,
13547 ClutterAllocationFlags flags)
13549 gfloat actor_x, actor_y;
13550 gfloat natural_width, natural_height;
13551 ClutterActorBox actor_box;
13553 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13555 actor_x = clutter_actor_get_x (self);
13556 actor_y = clutter_actor_get_y (self);
13558 clutter_actor_get_preferred_size (self,
13563 actor_box.x1 = actor_x;
13564 actor_box.y1 = actor_y;
13565 actor_box.x2 = actor_box.x1 + natural_width;
13566 actor_box.y2 = actor_box.y1 + natural_height;
13568 clutter_actor_allocate (self, &actor_box, flags);
13572 * clutter_actor_allocate_align_fill:
13573 * @self: a #ClutterActor
13574 * @box: a #ClutterActorBox, containing the available width and height
13575 * @x_align: the horizontal alignment, between 0 and 1
13576 * @y_align: the vertical alignment, between 0 and 1
13577 * @x_fill: whether the actor should fill horizontally
13578 * @y_fill: whether the actor should fill vertically
13579 * @flags: allocation flags to be passed to clutter_actor_allocate()
13581 * Allocates @self by taking into consideration the available allocation
13582 * area; an alignment factor on either axis; and whether the actor should
13583 * fill the allocation on either axis.
13585 * The @box should contain the available allocation width and height;
13586 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13587 * allocation will be offset by their value.
13589 * This function takes into consideration the geometry request specified by
13590 * the #ClutterActor:request-mode property, and the text direction.
13592 * This function is useful for fluid layout managers, like #ClutterBinLayout
13593 * or #ClutterTableLayout
13598 clutter_actor_allocate_align_fill (ClutterActor *self,
13599 const ClutterActorBox *box,
13604 ClutterAllocationFlags flags)
13606 ClutterActorPrivate *priv;
13607 ClutterActorBox allocation = { 0, };
13608 gfloat x_offset, y_offset;
13609 gfloat available_width, available_height;
13610 gfloat child_width, child_height;
13612 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13613 g_return_if_fail (box != NULL);
13614 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13615 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13619 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13620 clutter_actor_box_get_size (box, &available_width, &available_height);
13622 if (available_width < 0)
13623 available_width = 0;
13625 if (available_height < 0)
13626 available_height = 0;
13630 allocation.x1 = x_offset;
13631 allocation.x2 = allocation.x1 + available_width;
13636 allocation.y1 = y_offset;
13637 allocation.y2 = allocation.y1 + available_height;
13640 /* if we are filling horizontally and vertically then we're done */
13641 if (x_fill && y_fill)
13644 child_width = child_height = 0.0f;
13646 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13648 gfloat min_width, natural_width;
13649 gfloat min_height, natural_height;
13651 clutter_actor_get_preferred_width (self, available_height,
13655 child_width = CLAMP (natural_width, min_width, available_width);
13659 clutter_actor_get_preferred_height (self, child_width,
13663 child_height = CLAMP (natural_height, min_height, available_height);
13668 gfloat min_width, natural_width;
13669 gfloat min_height, natural_height;
13671 clutter_actor_get_preferred_height (self, available_width,
13675 child_height = CLAMP (natural_height, min_height, available_height);
13679 clutter_actor_get_preferred_width (self, child_height,
13683 child_width = CLAMP (natural_width, min_width, available_width);
13687 /* invert the horizontal alignment for RTL languages */
13688 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13689 x_align = 1.0 - x_align;
13693 allocation.x1 = x_offset
13694 + ((available_width - child_width) * x_align);
13695 allocation.x2 = allocation.x1 + child_width;
13700 allocation.y1 = y_offset
13701 + ((available_height - child_height) * y_align);
13702 allocation.y2 = allocation.y1 + child_height;
13706 clutter_actor_box_clamp_to_pixel (&allocation);
13707 clutter_actor_allocate (self, &allocation, flags);
13711 * clutter_actor_grab_key_focus:
13712 * @self: a #ClutterActor
13714 * Sets the key focus of the #ClutterStage including @self
13715 * to this #ClutterActor.
13720 clutter_actor_grab_key_focus (ClutterActor *self)
13722 ClutterActor *stage;
13724 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13726 stage = _clutter_actor_get_stage_internal (self);
13728 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13732 * clutter_actor_get_pango_context:
13733 * @self: a #ClutterActor
13735 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13736 * is already configured using the appropriate font map, resolution
13737 * and font options.
13739 * Unlike clutter_actor_create_pango_context(), this context is owend
13740 * by the #ClutterActor and it will be updated each time the options
13741 * stored by the #ClutterBackend change.
13743 * You can use the returned #PangoContext to create a #PangoLayout
13744 * and render text using cogl_pango_render_layout() to reuse the
13745 * glyphs cache also used by Clutter.
13747 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13748 * The returned #PangoContext is owned by the actor and should not be
13749 * unreferenced by the application code
13754 clutter_actor_get_pango_context (ClutterActor *self)
13756 ClutterActorPrivate *priv;
13758 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13762 if (priv->pango_context != NULL)
13763 return priv->pango_context;
13765 priv->pango_context = _clutter_context_get_pango_context ();
13766 g_object_ref (priv->pango_context);
13768 return priv->pango_context;
13772 * clutter_actor_create_pango_context:
13773 * @self: a #ClutterActor
13775 * Creates a #PangoContext for the given actor. The #PangoContext
13776 * is already configured using the appropriate font map, resolution
13777 * and font options.
13779 * See also clutter_actor_get_pango_context().
13781 * Return value: (transfer full): the newly created #PangoContext.
13782 * Use g_object_unref() on the returned value to deallocate its
13788 clutter_actor_create_pango_context (ClutterActor *self)
13790 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13792 return _clutter_context_create_pango_context ();
13796 * clutter_actor_create_pango_layout:
13797 * @self: a #ClutterActor
13798 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13800 * Creates a new #PangoLayout from the same #PangoContext used
13801 * by the #ClutterActor. The #PangoLayout is already configured
13802 * with the font map, resolution and font options, and the
13805 * If you want to keep around a #PangoLayout created by this
13806 * function you will have to connect to the #ClutterBackend::font-changed
13807 * and #ClutterBackend::resolution-changed signals, and call
13808 * pango_layout_context_changed() in response to them.
13810 * Return value: (transfer full): the newly created #PangoLayout.
13811 * Use g_object_unref() when done
13816 clutter_actor_create_pango_layout (ClutterActor *self,
13819 PangoContext *context;
13820 PangoLayout *layout;
13822 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13824 context = clutter_actor_get_pango_context (self);
13825 layout = pango_layout_new (context);
13828 pango_layout_set_text (layout, text, -1);
13833 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13834 * ClutterOffscreenEffect.
13837 _clutter_actor_set_opacity_override (ClutterActor *self,
13840 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13842 self->priv->opacity_override = opacity;
13846 _clutter_actor_get_opacity_override (ClutterActor *self)
13848 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13850 return self->priv->opacity_override;
13853 /* Allows you to disable applying the actors model view transform during
13854 * a paint. Used by ClutterClone. */
13856 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13859 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13861 self->priv->enable_model_view_transform = enable;
13865 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13868 ClutterActorPrivate *priv;
13870 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13874 priv->enable_paint_unmapped = enable;
13876 if (priv->enable_paint_unmapped)
13878 /* Make sure that the parents of the widget are realized first;
13879 * otherwise checks in clutter_actor_update_map_state() will
13882 clutter_actor_realize (self);
13884 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13888 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13893 clutter_anchor_coord_get_units (ClutterActor *self,
13894 const AnchorCoord *coord,
13899 if (coord->is_fractional)
13901 gfloat actor_width, actor_height;
13903 clutter_actor_get_size (self, &actor_width, &actor_height);
13906 *x = actor_width * coord->v.fraction.x;
13909 *y = actor_height * coord->v.fraction.y;
13917 *x = coord->v.units.x;
13920 *y = coord->v.units.y;
13923 *z = coord->v.units.z;
13928 clutter_anchor_coord_set_units (AnchorCoord *coord,
13933 coord->is_fractional = FALSE;
13934 coord->v.units.x = x;
13935 coord->v.units.y = y;
13936 coord->v.units.z = z;
13939 static ClutterGravity
13940 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13942 if (coord->is_fractional)
13944 if (coord->v.fraction.x == 0.0)
13946 if (coord->v.fraction.y == 0.0)
13947 return CLUTTER_GRAVITY_NORTH_WEST;
13948 else if (coord->v.fraction.y == 0.5)
13949 return CLUTTER_GRAVITY_WEST;
13950 else if (coord->v.fraction.y == 1.0)
13951 return CLUTTER_GRAVITY_SOUTH_WEST;
13953 return CLUTTER_GRAVITY_NONE;
13955 else if (coord->v.fraction.x == 0.5)
13957 if (coord->v.fraction.y == 0.0)
13958 return CLUTTER_GRAVITY_NORTH;
13959 else if (coord->v.fraction.y == 0.5)
13960 return CLUTTER_GRAVITY_CENTER;
13961 else if (coord->v.fraction.y == 1.0)
13962 return CLUTTER_GRAVITY_SOUTH;
13964 return CLUTTER_GRAVITY_NONE;
13966 else if (coord->v.fraction.x == 1.0)
13968 if (coord->v.fraction.y == 0.0)
13969 return CLUTTER_GRAVITY_NORTH_EAST;
13970 else if (coord->v.fraction.y == 0.5)
13971 return CLUTTER_GRAVITY_EAST;
13972 else if (coord->v.fraction.y == 1.0)
13973 return CLUTTER_GRAVITY_SOUTH_EAST;
13975 return CLUTTER_GRAVITY_NONE;
13978 return CLUTTER_GRAVITY_NONE;
13981 return CLUTTER_GRAVITY_NONE;
13985 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
13986 ClutterGravity gravity)
13990 case CLUTTER_GRAVITY_NORTH:
13991 coord->v.fraction.x = 0.5;
13992 coord->v.fraction.y = 0.0;
13995 case CLUTTER_GRAVITY_NORTH_EAST:
13996 coord->v.fraction.x = 1.0;
13997 coord->v.fraction.y = 0.0;
14000 case CLUTTER_GRAVITY_EAST:
14001 coord->v.fraction.x = 1.0;
14002 coord->v.fraction.y = 0.5;
14005 case CLUTTER_GRAVITY_SOUTH_EAST:
14006 coord->v.fraction.x = 1.0;
14007 coord->v.fraction.y = 1.0;
14010 case CLUTTER_GRAVITY_SOUTH:
14011 coord->v.fraction.x = 0.5;
14012 coord->v.fraction.y = 1.0;
14015 case CLUTTER_GRAVITY_SOUTH_WEST:
14016 coord->v.fraction.x = 0.0;
14017 coord->v.fraction.y = 1.0;
14020 case CLUTTER_GRAVITY_WEST:
14021 coord->v.fraction.x = 0.0;
14022 coord->v.fraction.y = 0.5;
14025 case CLUTTER_GRAVITY_NORTH_WEST:
14026 coord->v.fraction.x = 0.0;
14027 coord->v.fraction.y = 0.0;
14030 case CLUTTER_GRAVITY_CENTER:
14031 coord->v.fraction.x = 0.5;
14032 coord->v.fraction.y = 0.5;
14036 coord->v.fraction.x = 0.0;
14037 coord->v.fraction.y = 0.0;
14041 coord->is_fractional = TRUE;
14045 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14047 if (coord->is_fractional)
14048 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14050 return (coord->v.units.x == 0.0
14051 && coord->v.units.y == 0.0
14052 && coord->v.units.z == 0.0);
14056 * clutter_actor_get_flags:
14057 * @self: a #ClutterActor
14059 * Retrieves the flags set on @self
14061 * Return value: a bitwise or of #ClutterActorFlags or 0
14066 clutter_actor_get_flags (ClutterActor *self)
14068 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14070 return self->flags;
14074 * clutter_actor_set_flags:
14075 * @self: a #ClutterActor
14076 * @flags: the flags to set
14078 * Sets @flags on @self
14080 * This function will emit notifications for the changed properties
14085 clutter_actor_set_flags (ClutterActor *self,
14086 ClutterActorFlags flags)
14088 ClutterActorFlags old_flags;
14090 gboolean was_reactive_set, reactive_set;
14091 gboolean was_realized_set, realized_set;
14092 gboolean was_mapped_set, mapped_set;
14093 gboolean was_visible_set, visible_set;
14095 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14097 if (self->flags == flags)
14100 obj = G_OBJECT (self);
14101 g_object_ref (obj);
14102 g_object_freeze_notify (obj);
14104 old_flags = self->flags;
14106 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14107 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14108 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14109 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14111 self->flags |= flags;
14113 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14114 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14115 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14116 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14118 if (reactive_set != was_reactive_set)
14119 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14121 if (realized_set != was_realized_set)
14122 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14124 if (mapped_set != was_mapped_set)
14125 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14127 if (visible_set != was_visible_set)
14128 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14130 g_object_thaw_notify (obj);
14131 g_object_unref (obj);
14135 * clutter_actor_unset_flags:
14136 * @self: a #ClutterActor
14137 * @flags: the flags to unset
14139 * Unsets @flags on @self
14141 * This function will emit notifications for the changed properties
14146 clutter_actor_unset_flags (ClutterActor *self,
14147 ClutterActorFlags flags)
14149 ClutterActorFlags old_flags;
14151 gboolean was_reactive_set, reactive_set;
14152 gboolean was_realized_set, realized_set;
14153 gboolean was_mapped_set, mapped_set;
14154 gboolean was_visible_set, visible_set;
14156 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14158 obj = G_OBJECT (self);
14159 g_object_freeze_notify (obj);
14161 old_flags = self->flags;
14163 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14164 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14165 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14166 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14168 self->flags &= ~flags;
14170 if (self->flags == old_flags)
14173 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14174 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14175 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14176 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14178 if (reactive_set != was_reactive_set)
14179 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14181 if (realized_set != was_realized_set)
14182 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14184 if (mapped_set != was_mapped_set)
14185 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14187 if (visible_set != was_visible_set)
14188 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14190 g_object_thaw_notify (obj);
14194 * clutter_actor_get_transformation_matrix:
14195 * @self: a #ClutterActor
14196 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14198 * Retrieves the transformations applied to @self relative to its
14204 clutter_actor_get_transformation_matrix (ClutterActor *self,
14205 CoglMatrix *matrix)
14207 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14209 cogl_matrix_init_identity (matrix);
14211 _clutter_actor_apply_modelview_transform (self, matrix);
14215 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14216 gboolean is_in_clone_paint)
14218 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14219 self->priv->in_clone_paint = is_in_clone_paint;
14223 * clutter_actor_is_in_clone_paint:
14224 * @self: a #ClutterActor
14226 * Checks whether @self is being currently painted by a #ClutterClone
14228 * This function is useful only inside the ::paint virtual function
14229 * implementations or within handlers for the #ClutterActor::paint
14232 * This function should not be used by applications
14234 * Return value: %TRUE if the #ClutterActor is currently being painted
14235 * by a #ClutterClone, and %FALSE otherwise
14240 clutter_actor_is_in_clone_paint (ClutterActor *self)
14242 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14244 return self->priv->in_clone_paint;
14248 set_direction_recursive (ClutterActor *actor,
14249 gpointer user_data)
14251 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14253 clutter_actor_set_text_direction (actor, text_dir);
14259 * clutter_actor_set_text_direction:
14260 * @self: a #ClutterActor
14261 * @text_dir: the text direction for @self
14263 * Sets the #ClutterTextDirection for an actor
14265 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14267 * If @self implements #ClutterContainer then this function will recurse
14268 * inside all the children of @self (including the internal ones).
14270 * Composite actors not implementing #ClutterContainer, or actors requiring
14271 * special handling when the text direction changes, should connect to
14272 * the #GObject::notify signal for the #ClutterActor:text-direction property
14277 clutter_actor_set_text_direction (ClutterActor *self,
14278 ClutterTextDirection text_dir)
14280 ClutterActorPrivate *priv;
14282 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14283 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14287 if (priv->text_direction != text_dir)
14289 priv->text_direction = text_dir;
14291 /* we need to emit the notify::text-direction first, so that
14292 * the sub-classes can catch that and do specific handling of
14293 * the text direction; see clutter_text_direction_changed_cb()
14294 * inside clutter-text.c
14296 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14298 _clutter_actor_foreach_child (self, set_direction_recursive,
14299 GINT_TO_POINTER (text_dir));
14301 clutter_actor_queue_relayout (self);
14306 _clutter_actor_set_has_pointer (ClutterActor *self,
14307 gboolean has_pointer)
14309 ClutterActorPrivate *priv = self->priv;
14311 if (priv->has_pointer != has_pointer)
14313 priv->has_pointer = has_pointer;
14315 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14320 * clutter_actor_get_text_direction:
14321 * @self: a #ClutterActor
14323 * Retrieves the value set using clutter_actor_set_text_direction()
14325 * If no text direction has been previously set, the default text
14326 * direction, as returned by clutter_get_default_text_direction(), will
14327 * be returned instead
14329 * Return value: the #ClutterTextDirection for the actor
14333 ClutterTextDirection
14334 clutter_actor_get_text_direction (ClutterActor *self)
14336 ClutterActorPrivate *priv;
14338 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14339 CLUTTER_TEXT_DIRECTION_LTR);
14343 /* if no direction has been set yet use the default */
14344 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14345 priv->text_direction = clutter_get_default_text_direction ();
14347 return priv->text_direction;
14351 * clutter_actor_push_internal:
14352 * @self: a #ClutterActor
14354 * Should be used by actors implementing the #ClutterContainer and with
14355 * internal children added through clutter_actor_set_parent(), for instance:
14359 * my_actor_init (MyActor *self)
14361 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14363 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14365 * /* calling clutter_actor_set_parent() now will result in
14366 * * the internal flag being set on a child of MyActor
14369 * /* internal child - a background texture */
14370 * self->priv->background_tex = clutter_texture_new ();
14371 * clutter_actor_set_parent (self->priv->background_tex,
14372 * CLUTTER_ACTOR (self));
14374 * /* internal child - a label */
14375 * self->priv->label = clutter_text_new ();
14376 * clutter_actor_set_parent (self->priv->label,
14377 * CLUTTER_ACTOR (self));
14379 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14381 * /* calling clutter_actor_set_parent() now will not result in
14382 * * the internal flag being set on a child of MyActor
14387 * This function will be used by Clutter to toggle an "internal child"
14388 * flag whenever clutter_actor_set_parent() is called; internal children
14389 * are handled differently by Clutter, specifically when destroying their
14392 * Call clutter_actor_pop_internal() when you finished adding internal
14395 * Nested calls to clutter_actor_push_internal() are allowed, but each
14396 * one must by followed by a clutter_actor_pop_internal() call.
14400 * Deprecated: 1.10: All children of an actor are accessible through
14401 * the #ClutterActor API, and #ClutterActor implements the
14402 * #ClutterContainer interface, so this function is only useful
14403 * for legacy containers overriding the default implementation.
14406 clutter_actor_push_internal (ClutterActor *self)
14408 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14410 self->priv->internal_child += 1;
14414 * clutter_actor_pop_internal:
14415 * @self: a #ClutterActor
14417 * Disables the effects of clutter_actor_push_internal().
14421 * Deprecated: 1.10: All children of an actor are accessible through
14422 * the #ClutterActor API. This function is only useful for legacy
14423 * containers overriding the default implementation of the
14424 * #ClutterContainer interface.
14427 clutter_actor_pop_internal (ClutterActor *self)
14429 ClutterActorPrivate *priv;
14431 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14435 if (priv->internal_child == 0)
14437 g_warning ("Mismatched %s: you need to call "
14438 "clutter_actor_push_composite() at least once before "
14439 "calling this function", G_STRFUNC);
14443 priv->internal_child -= 1;
14447 * clutter_actor_has_pointer:
14448 * @self: a #ClutterActor
14450 * Checks whether an actor contains the pointer of a
14451 * #ClutterInputDevice
14453 * Return value: %TRUE if the actor contains the pointer, and
14459 clutter_actor_has_pointer (ClutterActor *self)
14461 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14463 return self->priv->has_pointer;
14466 /* XXX: This is a workaround for not being able to break the ABI of
14467 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14468 * clutter_actor_queue_clipped_redraw() for details.
14470 ClutterPaintVolume *
14471 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14473 return g_object_get_data (G_OBJECT (self),
14474 "-clutter-actor-queue-redraw-clip");
14478 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14479 ClutterPaintVolume *clip)
14481 g_object_set_data (G_OBJECT (self),
14482 "-clutter-actor-queue-redraw-clip",
14487 * clutter_actor_has_allocation:
14488 * @self: a #ClutterActor
14490 * Checks if the actor has an up-to-date allocation assigned to
14491 * it. This means that the actor should have an allocation: it's
14492 * visible and has a parent. It also means that there is no
14493 * outstanding relayout request in progress for the actor or its
14494 * children (There might be other outstanding layout requests in
14495 * progress that will cause the actor to get a new allocation
14496 * when the stage is laid out, however).
14498 * If this function returns %FALSE, then the actor will normally
14499 * be allocated before it is next drawn on the screen.
14501 * Return value: %TRUE if the actor has an up-to-date allocation
14506 clutter_actor_has_allocation (ClutterActor *self)
14508 ClutterActorPrivate *priv;
14510 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14514 return priv->parent != NULL &&
14515 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14516 !priv->needs_allocation;
14520 * clutter_actor_add_action:
14521 * @self: a #ClutterActor
14522 * @action: a #ClutterAction
14524 * Adds @action to the list of actions applied to @self
14526 * A #ClutterAction can only belong to one actor at a time
14528 * The #ClutterActor will hold a reference on @action until either
14529 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14535 clutter_actor_add_action (ClutterActor *self,
14536 ClutterAction *action)
14538 ClutterActorPrivate *priv;
14540 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14541 g_return_if_fail (CLUTTER_IS_ACTION (action));
14545 if (priv->actions == NULL)
14547 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14548 priv->actions->actor = self;
14551 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14553 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14557 * clutter_actor_add_action_with_name:
14558 * @self: a #ClutterActor
14559 * @name: the name to set on the action
14560 * @action: a #ClutterAction
14562 * A convenience function for setting the name of a #ClutterAction
14563 * while adding it to the list of actions applied to @self
14565 * This function is the logical equivalent of:
14568 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14569 * clutter_actor_add_action (self, action);
14575 clutter_actor_add_action_with_name (ClutterActor *self,
14577 ClutterAction *action)
14579 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14580 g_return_if_fail (name != NULL);
14581 g_return_if_fail (CLUTTER_IS_ACTION (action));
14583 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14584 clutter_actor_add_action (self, action);
14588 * clutter_actor_remove_action:
14589 * @self: a #ClutterActor
14590 * @action: a #ClutterAction
14592 * Removes @action from the list of actions applied to @self
14594 * The reference held by @self on the #ClutterAction will be released
14599 clutter_actor_remove_action (ClutterActor *self,
14600 ClutterAction *action)
14602 ClutterActorPrivate *priv;
14604 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14605 g_return_if_fail (CLUTTER_IS_ACTION (action));
14609 if (priv->actions == NULL)
14612 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14614 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14618 * clutter_actor_remove_action_by_name:
14619 * @self: a #ClutterActor
14620 * @name: the name of the action to remove
14622 * Removes the #ClutterAction with the given name from the list
14623 * of actions applied to @self
14628 clutter_actor_remove_action_by_name (ClutterActor *self,
14631 ClutterActorPrivate *priv;
14632 ClutterActorMeta *meta;
14634 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14635 g_return_if_fail (name != NULL);
14639 if (priv->actions == NULL)
14642 meta = _clutter_meta_group_get_meta (priv->actions, name);
14646 _clutter_meta_group_remove_meta (priv->actions, meta);
14648 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14652 * clutter_actor_get_actions:
14653 * @self: a #ClutterActor
14655 * Retrieves the list of actions applied to @self
14657 * Return value: (transfer container) (element-type Clutter.Action): a copy
14658 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14659 * owned by the #ClutterActor. Use g_list_free() to free the resources
14660 * allocated by the returned #GList
14665 clutter_actor_get_actions (ClutterActor *self)
14667 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14669 if (self->priv->actions == NULL)
14672 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14676 * clutter_actor_get_action:
14677 * @self: a #ClutterActor
14678 * @name: the name of the action to retrieve
14680 * Retrieves the #ClutterAction with the given name in the list
14681 * of actions applied to @self
14683 * Return value: (transfer none): a #ClutterAction for the given
14684 * name, or %NULL. The returned #ClutterAction is owned by the
14685 * actor and it should not be unreferenced directly
14690 clutter_actor_get_action (ClutterActor *self,
14693 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14694 g_return_val_if_fail (name != NULL, NULL);
14696 if (self->priv->actions == NULL)
14699 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14703 * clutter_actor_clear_actions:
14704 * @self: a #ClutterActor
14706 * Clears the list of actions applied to @self
14711 clutter_actor_clear_actions (ClutterActor *self)
14713 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14715 if (self->priv->actions == NULL)
14718 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14722 * clutter_actor_add_constraint:
14723 * @self: a #ClutterActor
14724 * @constraint: a #ClutterConstraint
14726 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14729 * The #ClutterActor will hold a reference on the @constraint until
14730 * either clutter_actor_remove_constraint() or
14731 * clutter_actor_clear_constraints() is called.
14736 clutter_actor_add_constraint (ClutterActor *self,
14737 ClutterConstraint *constraint)
14739 ClutterActorPrivate *priv;
14741 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14742 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14746 if (priv->constraints == NULL)
14748 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14749 priv->constraints->actor = self;
14752 _clutter_meta_group_add_meta (priv->constraints,
14753 CLUTTER_ACTOR_META (constraint));
14754 clutter_actor_queue_relayout (self);
14756 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14760 * clutter_actor_add_constraint_with_name:
14761 * @self: a #ClutterActor
14762 * @name: the name to set on the constraint
14763 * @constraint: a #ClutterConstraint
14765 * A convenience function for setting the name of a #ClutterConstraint
14766 * while adding it to the list of constraints applied to @self
14768 * This function is the logical equivalent of:
14771 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14772 * clutter_actor_add_constraint (self, constraint);
14778 clutter_actor_add_constraint_with_name (ClutterActor *self,
14780 ClutterConstraint *constraint)
14782 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14783 g_return_if_fail (name != NULL);
14784 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14786 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14787 clutter_actor_add_constraint (self, constraint);
14791 * clutter_actor_remove_constraint:
14792 * @self: a #ClutterActor
14793 * @constraint: a #ClutterConstraint
14795 * Removes @constraint from the list of constraints applied to @self
14797 * The reference held by @self on the #ClutterConstraint will be released
14802 clutter_actor_remove_constraint (ClutterActor *self,
14803 ClutterConstraint *constraint)
14805 ClutterActorPrivate *priv;
14807 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14808 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14812 if (priv->constraints == NULL)
14815 _clutter_meta_group_remove_meta (priv->constraints,
14816 CLUTTER_ACTOR_META (constraint));
14817 clutter_actor_queue_relayout (self);
14819 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14823 * clutter_actor_remove_constraint_by_name:
14824 * @self: a #ClutterActor
14825 * @name: the name of the constraint to remove
14827 * Removes the #ClutterConstraint with the given name from the list
14828 * of constraints applied to @self
14833 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14836 ClutterActorPrivate *priv;
14837 ClutterActorMeta *meta;
14839 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14840 g_return_if_fail (name != NULL);
14844 if (priv->constraints == NULL)
14847 meta = _clutter_meta_group_get_meta (priv->constraints, name);
14851 _clutter_meta_group_remove_meta (priv->constraints, meta);
14852 clutter_actor_queue_relayout (self);
14856 * clutter_actor_get_constraints:
14857 * @self: a #ClutterActor
14859 * Retrieves the list of constraints applied to @self
14861 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14862 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14863 * owned by the #ClutterActor. Use g_list_free() to free the resources
14864 * allocated by the returned #GList
14869 clutter_actor_get_constraints (ClutterActor *self)
14871 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14873 if (self->priv->constraints == NULL)
14876 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14880 * clutter_actor_get_constraint:
14881 * @self: a #ClutterActor
14882 * @name: the name of the constraint to retrieve
14884 * Retrieves the #ClutterConstraint with the given name in the list
14885 * of constraints applied to @self
14887 * Return value: (transfer none): a #ClutterConstraint for the given
14888 * name, or %NULL. The returned #ClutterConstraint is owned by the
14889 * actor and it should not be unreferenced directly
14893 ClutterConstraint *
14894 clutter_actor_get_constraint (ClutterActor *self,
14897 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14898 g_return_val_if_fail (name != NULL, NULL);
14900 if (self->priv->constraints == NULL)
14903 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14907 * clutter_actor_clear_constraints:
14908 * @self: a #ClutterActor
14910 * Clears the list of constraints applied to @self
14915 clutter_actor_clear_constraints (ClutterActor *self)
14917 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14919 if (self->priv->constraints == NULL)
14922 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14924 clutter_actor_queue_relayout (self);
14928 * clutter_actor_set_clip_to_allocation:
14929 * @self: a #ClutterActor
14930 * @clip_set: %TRUE to apply a clip tracking the allocation
14932 * Sets whether @self should be clipped to the same size as its
14938 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14941 ClutterActorPrivate *priv;
14943 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14945 clip_set = !!clip_set;
14949 if (priv->clip_to_allocation != clip_set)
14951 priv->clip_to_allocation = clip_set;
14953 clutter_actor_queue_redraw (self);
14955 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14960 * clutter_actor_get_clip_to_allocation:
14961 * @self: a #ClutterActor
14963 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14965 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14970 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14972 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14974 return self->priv->clip_to_allocation;
14978 * clutter_actor_add_effect:
14979 * @self: a #ClutterActor
14980 * @effect: a #ClutterEffect
14982 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14984 * The #ClutterActor will hold a reference on the @effect until either
14985 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14991 clutter_actor_add_effect (ClutterActor *self,
14992 ClutterEffect *effect)
14994 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14995 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14997 _clutter_actor_add_effect_internal (self, effect);
14999 clutter_actor_queue_redraw (self);
15001 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15005 * clutter_actor_add_effect_with_name:
15006 * @self: a #ClutterActor
15007 * @name: the name to set on the effect
15008 * @effect: a #ClutterEffect
15010 * A convenience function for setting the name of a #ClutterEffect
15011 * while adding it to the list of effectss applied to @self
15013 * This function is the logical equivalent of:
15016 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15017 * clutter_actor_add_effect (self, effect);
15023 clutter_actor_add_effect_with_name (ClutterActor *self,
15025 ClutterEffect *effect)
15027 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15028 g_return_if_fail (name != NULL);
15029 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15031 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15032 clutter_actor_add_effect (self, effect);
15036 * clutter_actor_remove_effect:
15037 * @self: a #ClutterActor
15038 * @effect: a #ClutterEffect
15040 * Removes @effect from the list of effects applied to @self
15042 * The reference held by @self on the #ClutterEffect will be released
15047 clutter_actor_remove_effect (ClutterActor *self,
15048 ClutterEffect *effect)
15050 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15051 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15053 _clutter_actor_remove_effect_internal (self, effect);
15055 clutter_actor_queue_redraw (self);
15057 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15061 * clutter_actor_remove_effect_by_name:
15062 * @self: a #ClutterActor
15063 * @name: the name of the effect to remove
15065 * Removes the #ClutterEffect with the given name from the list
15066 * of effects applied to @self
15071 clutter_actor_remove_effect_by_name (ClutterActor *self,
15074 ClutterActorPrivate *priv;
15075 ClutterActorMeta *meta;
15077 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15078 g_return_if_fail (name != NULL);
15082 if (priv->effects == NULL)
15085 meta = _clutter_meta_group_get_meta (priv->effects, name);
15089 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15093 * clutter_actor_get_effects:
15094 * @self: a #ClutterActor
15096 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15098 * Return value: (transfer container) (element-type Clutter.Effect): a list
15099 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15100 * list are owned by Clutter and they should not be freed. You should
15101 * free the returned list using g_list_free() when done
15106 clutter_actor_get_effects (ClutterActor *self)
15108 ClutterActorPrivate *priv;
15110 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15114 if (priv->effects == NULL)
15117 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15121 * clutter_actor_get_effect:
15122 * @self: a #ClutterActor
15123 * @name: the name of the effect to retrieve
15125 * Retrieves the #ClutterEffect with the given name in the list
15126 * of effects applied to @self
15128 * Return value: (transfer none): a #ClutterEffect for the given
15129 * name, or %NULL. The returned #ClutterEffect is owned by the
15130 * actor and it should not be unreferenced directly
15135 clutter_actor_get_effect (ClutterActor *self,
15138 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15139 g_return_val_if_fail (name != NULL, NULL);
15141 if (self->priv->effects == NULL)
15144 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15148 * clutter_actor_clear_effects:
15149 * @self: a #ClutterActor
15151 * Clears the list of effects applied to @self
15156 clutter_actor_clear_effects (ClutterActor *self)
15158 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15160 if (self->priv->effects == NULL)
15163 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15165 clutter_actor_queue_redraw (self);
15169 * clutter_actor_has_key_focus:
15170 * @self: a #ClutterActor
15172 * Checks whether @self is the #ClutterActor that has key focus
15174 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15179 clutter_actor_has_key_focus (ClutterActor *self)
15181 ClutterActor *stage;
15183 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15185 stage = _clutter_actor_get_stage_internal (self);
15189 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15193 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15194 ClutterPaintVolume *pv)
15196 ClutterActorPrivate *priv = self->priv;
15198 /* Actors are only expected to report a valid paint volume
15199 * while they have a valid allocation. */
15200 if (G_UNLIKELY (priv->needs_allocation))
15202 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15203 "Actor needs allocation",
15204 _clutter_actor_get_debug_name (self));
15208 /* Check if there are any handlers connected to the paint
15209 * signal. If there are then all bets are off for what the paint
15210 * volume for this actor might possibly be!
15212 * XXX: It's expected that this is going to end up being quite a
15213 * costly check to have to do here, but we haven't come up with
15214 * another solution that can reliably catch paint signal handlers at
15215 * the right time to either avoid artefacts due to invalid stage
15216 * clipping or due to incorrect culling.
15218 * Previously we checked in clutter_actor_paint(), but at that time
15219 * we may already be using a stage clip that could be derived from
15220 * an invalid paint-volume. We used to try and handle that by
15221 * queuing a follow up, unclipped, redraw but still the previous
15222 * checking wasn't enough to catch invalid volumes involved in
15223 * culling (considering that containers may derive their volume from
15224 * children that haven't yet been painted)
15226 * Longer term, improved solutions could be:
15227 * - Disallow painting in the paint signal, only allow using it
15228 * for tracking when paints happen. We can add another API that
15229 * allows monkey patching the paint of arbitrary actors but in a
15230 * more controlled way and that also supports modifying the
15232 * - If we could be notified somehow when signal handlers are
15233 * connected we wouldn't have to poll for handlers like this.
15235 if (g_signal_has_handler_pending (self,
15236 actor_signals[PAINT],
15240 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15241 "Actor has \"paint\" signal handlers",
15242 _clutter_actor_get_debug_name (self));
15246 _clutter_paint_volume_init_static (pv, self);
15248 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15250 clutter_paint_volume_free (pv);
15251 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15252 "Actor failed to report a volume",
15253 _clutter_actor_get_debug_name (self));
15257 /* since effects can modify the paint volume, we allow them to actually
15258 * do this by making get_paint_volume() "context sensitive"
15260 if (priv->effects != NULL)
15262 if (priv->current_effect != NULL)
15264 const GList *effects, *l;
15266 /* if we are being called from within the paint sequence of
15267 * an actor, get the paint volume up to the current effect
15269 effects = _clutter_meta_group_peek_metas (priv->effects);
15271 l != NULL || (l != NULL && l->data != priv->current_effect);
15274 if (!_clutter_effect_get_paint_volume (l->data, pv))
15276 clutter_paint_volume_free (pv);
15277 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15278 "Effect (%s) failed to report a volume",
15279 _clutter_actor_get_debug_name (self),
15280 _clutter_actor_meta_get_debug_name (l->data));
15287 const GList *effects, *l;
15289 /* otherwise, get the cumulative volume */
15290 effects = _clutter_meta_group_peek_metas (priv->effects);
15291 for (l = effects; l != NULL; l = l->next)
15292 if (!_clutter_effect_get_paint_volume (l->data, pv))
15294 clutter_paint_volume_free (pv);
15295 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15296 "Effect (%s) failed to report a volume",
15297 _clutter_actor_get_debug_name (self),
15298 _clutter_actor_meta_get_debug_name (l->data));
15307 /* The public clutter_actor_get_paint_volume API returns a const
15308 * pointer since we return a pointer directly to the cached
15309 * PaintVolume associated with the actor and don't want the user to
15310 * inadvertently modify it, but for internal uses we sometimes need
15311 * access to the same PaintVolume but need to apply some book-keeping
15312 * modifications to it so we don't want a const pointer.
15314 static ClutterPaintVolume *
15315 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15317 ClutterActorPrivate *priv;
15321 if (priv->paint_volume_valid)
15322 clutter_paint_volume_free (&priv->paint_volume);
15324 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15326 priv->paint_volume_valid = TRUE;
15327 return &priv->paint_volume;
15331 priv->paint_volume_valid = FALSE;
15337 * clutter_actor_get_paint_volume:
15338 * @self: a #ClutterActor
15340 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15341 * when a paint volume can't be determined.
15343 * The paint volume is defined as the 3D space occupied by an actor
15344 * when being painted.
15346 * This function will call the <function>get_paint_volume()</function>
15347 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15348 * should not usually care about overriding the default implementation,
15349 * unless they are, for instance: painting outside their allocation, or
15350 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15353 * <note>2D actors overriding <function>get_paint_volume()</function>
15354 * ensure their volume has a depth of 0. (This will be true so long as
15355 * you don't call clutter_paint_volume_set_depth().)</note>
15357 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15358 * or %NULL if no volume could be determined. The returned pointer
15359 * is not guaranteed to be valid across multiple frames; if you want
15360 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15364 const ClutterPaintVolume *
15365 clutter_actor_get_paint_volume (ClutterActor *self)
15367 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15369 return _clutter_actor_get_paint_volume_mutable (self);
15373 * clutter_actor_get_transformed_paint_volume:
15374 * @self: a #ClutterActor
15375 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15376 * (or %NULL for the stage)
15378 * Retrieves the 3D paint volume of an actor like
15379 * clutter_actor_get_paint_volume() does (Please refer to the
15380 * documentation of clutter_actor_get_paint_volume() for more
15381 * details.) and it additionally transforms the paint volume into the
15382 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15383 * is passed for @relative_to_ancestor)
15385 * This can be used by containers that base their paint volume on
15386 * the volume of their children. Such containers can query the
15387 * transformed paint volume of all of its children and union them
15388 * together using clutter_paint_volume_union().
15390 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15391 * or %NULL if no volume could be determined. The returned pointer is
15392 * not guaranteed to be valid across multiple frames; if you wish to
15393 * keep it, you will have to copy it using clutter_paint_volume_copy().
15397 const ClutterPaintVolume *
15398 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15399 ClutterActor *relative_to_ancestor)
15401 const ClutterPaintVolume *volume;
15402 ClutterActor *stage;
15403 ClutterPaintVolume *transformed_volume;
15405 stage = _clutter_actor_get_stage_internal (self);
15406 if (G_UNLIKELY (stage == NULL))
15409 if (relative_to_ancestor == NULL)
15410 relative_to_ancestor = stage;
15412 volume = clutter_actor_get_paint_volume (self);
15413 if (volume == NULL)
15416 transformed_volume =
15417 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15419 _clutter_paint_volume_copy_static (volume, transformed_volume);
15421 _clutter_paint_volume_transform_relative (transformed_volume,
15422 relative_to_ancestor);
15424 return transformed_volume;
15428 * clutter_actor_get_paint_box:
15429 * @self: a #ClutterActor
15430 * @box: (out): return location for a #ClutterActorBox
15432 * Retrieves the paint volume of the passed #ClutterActor, and
15433 * transforms it into a 2D bounding box in stage coordinates.
15435 * This function is useful to determine the on screen area occupied by
15436 * the actor. The box is only an approximation and may often be
15437 * considerably larger due to the optimizations used to calculate the
15438 * box. The box is never smaller though, so it can reliably be used
15441 * There are times when a 2D paint box can't be determined, e.g.
15442 * because the actor isn't yet parented under a stage or because
15443 * the actor is unable to determine a paint volume.
15445 * Return value: %TRUE if a 2D paint box could be determined, else
15451 clutter_actor_get_paint_box (ClutterActor *self,
15452 ClutterActorBox *box)
15454 ClutterActor *stage;
15455 ClutterPaintVolume *pv;
15457 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15458 g_return_val_if_fail (box != NULL, FALSE);
15460 stage = _clutter_actor_get_stage_internal (self);
15461 if (G_UNLIKELY (!stage))
15464 pv = _clutter_actor_get_paint_volume_mutable (self);
15465 if (G_UNLIKELY (!pv))
15468 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15474 * clutter_actor_has_overlaps:
15475 * @self: A #ClutterActor
15477 * Asks the actor's implementation whether it may contain overlapping
15480 * For example; Clutter may use this to determine whether the painting
15481 * should be redirected to an offscreen buffer to correctly implement
15482 * the opacity property.
15484 * Custom actors can override the default response by implementing the
15485 * #ClutterActor <function>has_overlaps</function> virtual function. See
15486 * clutter_actor_set_offscreen_redirect() for more information.
15488 * Return value: %TRUE if the actor may have overlapping primitives, and
15494 clutter_actor_has_overlaps (ClutterActor *self)
15496 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15498 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15502 * clutter_actor_has_effects:
15503 * @self: A #ClutterActor
15505 * Returns whether the actor has any effects applied.
15507 * Return value: %TRUE if the actor has any effects,
15513 clutter_actor_has_effects (ClutterActor *self)
15515 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15517 if (self->priv->effects == NULL)
15520 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15524 * clutter_actor_has_constraints:
15525 * @self: A #ClutterActor
15527 * Returns whether the actor has any constraints applied.
15529 * Return value: %TRUE if the actor has any constraints,
15535 clutter_actor_has_constraints (ClutterActor *self)
15537 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15539 return self->priv->constraints != NULL;
15543 * clutter_actor_has_actions:
15544 * @self: A #ClutterActor
15546 * Returns whether the actor has any actions applied.
15548 * Return value: %TRUE if the actor has any actions,
15554 clutter_actor_has_actions (ClutterActor *self)
15556 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15558 return self->priv->actions != NULL;
15562 * clutter_actor_get_n_children:
15563 * @self: a #ClutterActor
15565 * Retrieves the number of children of @self.
15567 * Return value: the number of children of an actor
15572 clutter_actor_get_n_children (ClutterActor *self)
15574 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15576 return self->priv->n_children;
15580 * clutter_actor_get_child_at_index:
15581 * @self: a #ClutterActor
15582 * @index_: the position in the list of children
15584 * Retrieves the actor at the given @index_ inside the list of
15585 * children of @self.
15587 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15592 clutter_actor_get_child_at_index (ClutterActor *self,
15595 ClutterActor *iter;
15598 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15599 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15601 for (iter = self->priv->first_child, i = 0;
15602 iter != NULL && i < index_;
15603 iter = iter->priv->next_sibling, i += 1)
15610 * _clutter_actor_foreach_child:
15611 * @actor: The actor whos children you want to iterate
15612 * @callback: The function to call for each child
15613 * @user_data: Private data to pass to @callback
15615 * Calls a given @callback once for each child of the specified @actor and
15616 * passing the @user_data pointer each time.
15618 * Return value: returns %TRUE if all children were iterated, else
15619 * %FALSE if a callback broke out of iteration early.
15622 _clutter_actor_foreach_child (ClutterActor *self,
15623 ClutterForeachCallback callback,
15624 gpointer user_data)
15626 ClutterActorPrivate *priv = self->priv;
15627 ClutterActor *iter;
15630 for (cont = TRUE, iter = priv->first_child;
15631 cont && iter != NULL;
15632 iter = iter->priv->next_sibling)
15634 cont = callback (iter, user_data);
15641 /* For debugging purposes this gives us a simple way to print out
15642 * the scenegraph e.g in gdb using:
15644 * _clutter_actor_traverse (stage,
15646 * clutter_debug_print_actor_cb,
15651 static ClutterActorTraverseVisitFlags
15652 clutter_debug_print_actor_cb (ClutterActor *actor,
15656 g_print ("%*s%s:%p\n",
15658 _clutter_actor_get_debug_name (actor),
15661 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15666 _clutter_actor_traverse_breadth (ClutterActor *actor,
15667 ClutterTraverseCallback callback,
15668 gpointer user_data)
15670 GQueue *queue = g_queue_new ();
15671 ClutterActor dummy;
15672 int current_depth = 0;
15674 g_queue_push_tail (queue, actor);
15675 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15677 while ((actor = g_queue_pop_head (queue)))
15679 ClutterActorTraverseVisitFlags flags;
15681 if (actor == &dummy)
15684 g_queue_push_tail (queue, &dummy);
15688 flags = callback (actor, current_depth, user_data);
15689 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15691 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15693 ClutterActor *iter;
15695 for (iter = actor->priv->first_child;
15697 iter = iter->priv->next_sibling)
15699 g_queue_push_tail (queue, iter);
15704 g_queue_free (queue);
15707 static ClutterActorTraverseVisitFlags
15708 _clutter_actor_traverse_depth (ClutterActor *actor,
15709 ClutterTraverseCallback before_children_callback,
15710 ClutterTraverseCallback after_children_callback,
15712 gpointer user_data)
15714 ClutterActorTraverseVisitFlags flags;
15716 flags = before_children_callback (actor, current_depth, user_data);
15717 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15718 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15720 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15722 ClutterActor *iter;
15724 for (iter = actor->priv->first_child;
15726 iter = iter->priv->next_sibling)
15728 flags = _clutter_actor_traverse_depth (iter,
15729 before_children_callback,
15730 after_children_callback,
15734 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15735 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15739 if (after_children_callback)
15740 return after_children_callback (actor, current_depth, user_data);
15742 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15745 /* _clutter_actor_traverse:
15746 * @actor: The actor to start traversing the graph from
15747 * @flags: These flags may affect how the traversal is done
15748 * @before_children_callback: A function to call before visiting the
15749 * children of the current actor.
15750 * @after_children_callback: A function to call after visiting the
15751 * children of the current actor. (Ignored if
15752 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15753 * @user_data: The private data to pass to the callbacks
15755 * Traverses the scenegraph starting at the specified @actor and
15756 * descending through all its children and its children's children.
15757 * For each actor traversed @before_children_callback and
15758 * @after_children_callback are called with the specified
15759 * @user_data, before and after visiting that actor's children.
15761 * The callbacks can return flags that affect the ongoing traversal
15762 * such as by skipping over an actors children or bailing out of
15763 * any further traversing.
15766 _clutter_actor_traverse (ClutterActor *actor,
15767 ClutterActorTraverseFlags flags,
15768 ClutterTraverseCallback before_children_callback,
15769 ClutterTraverseCallback after_children_callback,
15770 gpointer user_data)
15772 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15773 _clutter_actor_traverse_breadth (actor,
15774 before_children_callback,
15776 else /* DEPTH_FIRST */
15777 _clutter_actor_traverse_depth (actor,
15778 before_children_callback,
15779 after_children_callback,
15780 0, /* start depth */
15785 on_layout_manager_changed (ClutterLayoutManager *manager,
15786 ClutterActor *self)
15788 clutter_actor_queue_relayout (self);
15792 * clutter_actor_set_layout_manager:
15793 * @self: a #ClutterActor
15794 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15796 * Sets the #ClutterLayoutManager delegate object that will be used to
15797 * lay out the children of @self.
15799 * The #ClutterActor will take a reference on the passed @manager which
15800 * will be released either when the layout manager is removed, or when
15801 * the actor is destroyed.
15806 clutter_actor_set_layout_manager (ClutterActor *self,
15807 ClutterLayoutManager *manager)
15809 ClutterActorPrivate *priv;
15811 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15812 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15816 if (priv->layout_manager != NULL)
15818 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15819 G_CALLBACK (on_layout_manager_changed),
15821 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15822 g_object_unref (priv->layout_manager);
15825 priv->layout_manager = manager;
15827 if (priv->layout_manager != NULL)
15829 g_object_ref_sink (priv->layout_manager);
15830 clutter_layout_manager_set_container (priv->layout_manager,
15831 CLUTTER_CONTAINER (self));
15832 g_signal_connect (priv->layout_manager, "layout-changed",
15833 G_CALLBACK (on_layout_manager_changed),
15837 clutter_actor_queue_relayout (self);
15839 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15843 * clutter_actor_get_layout_manager:
15844 * @self: a #ClutterActor
15846 * Retrieves the #ClutterLayoutManager used by @self.
15848 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15853 ClutterLayoutManager *
15854 clutter_actor_get_layout_manager (ClutterActor *self)
15856 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15858 return self->priv->layout_manager;
15861 static const ClutterLayoutInfo default_layout_info = {
15864 { 0, 0, 0, 0 }, /* margin */
15865 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
15866 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
15867 0.f, 0.f, /* min_width, natural_width */
15868 0.f, 0.f, /* natual_width, natural_height */
15872 layout_info_free (gpointer data)
15874 if (G_LIKELY (data != NULL))
15875 g_slice_free (ClutterLayoutInfo, data);
15879 * _clutter_actor_get_layout_info:
15880 * @self: a #ClutterActor
15882 * Retrieves a pointer to the ClutterLayoutInfo structure.
15884 * If the actor does not have a ClutterLayoutInfo associated to it, one
15885 * will be created and initialized to the default values.
15887 * This function should be used for setters.
15889 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15892 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15894 ClutterLayoutInfo *
15895 _clutter_actor_get_layout_info (ClutterActor *self)
15897 ClutterLayoutInfo *retval;
15899 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15900 if (retval == NULL)
15902 retval = g_slice_new (ClutterLayoutInfo);
15904 *retval = default_layout_info;
15906 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15915 * _clutter_actor_get_layout_info_or_defaults:
15916 * @self: a #ClutterActor
15918 * Retrieves the ClutterLayoutInfo structure associated to an actor.
15920 * If the actor does not have a ClutterLayoutInfo structure associated to it,
15921 * then the default structure will be returned.
15923 * This function should only be used for getters.
15925 * Return value: a const pointer to the ClutterLayoutInfo structure
15927 const ClutterLayoutInfo *
15928 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15930 const ClutterLayoutInfo *info;
15932 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15934 return &default_layout_info;
15940 * clutter_actor_set_x_align:
15941 * @self: a #ClutterActor
15942 * @x_align: the horizontal alignment policy
15944 * Sets the horizontal alignment policy of a #ClutterActor, in case the
15945 * actor received extra horizontal space.
15947 * See also the #ClutterActor:x-align property.
15952 clutter_actor_set_x_align (ClutterActor *self,
15953 ClutterActorAlign x_align)
15955 ClutterLayoutInfo *info;
15957 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15959 info = _clutter_actor_get_layout_info (self);
15961 if (info->x_align != x_align)
15963 info->x_align = x_align;
15965 clutter_actor_queue_relayout (self);
15967 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15972 * clutter_actor_get_x_align:
15973 * @self: a #ClutterActor
15975 * Retrieves the horizontal alignment policy set using
15976 * clutter_actor_set_x_align().
15978 * Return value: the horizontal alignment policy.
15983 clutter_actor_get_x_align (ClutterActor *self)
15985 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15987 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15991 * clutter_actor_set_y_align:
15992 * @self: a #ClutterActor
15993 * @y_align: the vertical alignment policy
15995 * Sets the vertical alignment policy of a #ClutterActor, in case the
15996 * actor received extra vertical space.
15998 * See also the #ClutterActor:y-align property.
16003 clutter_actor_set_y_align (ClutterActor *self,
16004 ClutterActorAlign y_align)
16006 ClutterLayoutInfo *info;
16008 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16010 info = _clutter_actor_get_layout_info (self);
16012 if (info->y_align != y_align)
16014 info->y_align = y_align;
16016 clutter_actor_queue_relayout (self);
16018 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16023 * clutter_actor_get_y_align:
16024 * @self: a #ClutterActor
16026 * Retrieves the vertical alignment policy set using
16027 * clutter_actor_set_y_align().
16029 * Return value: the vertical alignment policy.
16034 clutter_actor_get_y_align (ClutterActor *self)
16036 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16038 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16043 * clutter_margin_new:
16045 * Creates a new #ClutterMargin.
16047 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16048 * clutter_margin_free() to free the resources associated with it when
16054 clutter_margin_new (void)
16056 return g_slice_new0 (ClutterMargin);
16060 * clutter_margin_copy:
16061 * @margin_: a #ClutterMargin
16063 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16064 * the newly created structure.
16066 * Return value: (transfer full): a copy of the #ClutterMargin.
16071 clutter_margin_copy (const ClutterMargin *margin_)
16073 if (G_LIKELY (margin_ != NULL))
16074 return g_slice_dup (ClutterMargin, margin_);
16080 * clutter_margin_free:
16081 * @margin_: a #ClutterMargin
16083 * Frees the resources allocated by clutter_margin_new() and
16084 * clutter_margin_copy().
16089 clutter_margin_free (ClutterMargin *margin_)
16091 if (G_LIKELY (margin_ != NULL))
16092 g_slice_free (ClutterMargin, margin_);
16095 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16096 clutter_margin_copy,
16097 clutter_margin_free)
16100 * clutter_actor_set_margin:
16101 * @self: a #ClutterActor
16102 * @margin: a #ClutterMargin
16104 * Sets all the components of the margin of a #ClutterActor.
16109 clutter_actor_set_margin (ClutterActor *self,
16110 const ClutterMargin *margin)
16112 ClutterLayoutInfo *info;
16116 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16117 g_return_if_fail (margin != NULL);
16119 obj = G_OBJECT (self);
16122 g_object_freeze_notify (obj);
16124 info = _clutter_actor_get_layout_info (self);
16126 if (info->margin.top != margin->top)
16128 info->margin.top = margin->top;
16129 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16133 if (info->margin.right != margin->right)
16135 info->margin.right = margin->right;
16136 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16140 if (info->margin.bottom != margin->bottom)
16142 info->margin.bottom = margin->bottom;
16143 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16147 if (info->margin.left != margin->left)
16149 info->margin.left = margin->left;
16150 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16155 clutter_actor_queue_relayout (self);
16157 g_object_thaw_notify (obj);
16161 * clutter_actor_get_margin:
16162 * @self: a #ClutterActor
16163 * @margin: (out caller-allocates): return location for a #ClutterMargin
16165 * Retrieves all the components of the margin of a #ClutterActor.
16170 clutter_actor_get_margin (ClutterActor *self,
16171 ClutterMargin *margin)
16173 const ClutterLayoutInfo *info;
16175 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16176 g_return_if_fail (margin != NULL);
16178 info = _clutter_actor_get_layout_info_or_defaults (self);
16180 *margin = info->margin;
16184 * clutter_actor_set_margin_top:
16185 * @self: a #ClutterActor
16186 * @margin: the top margin
16188 * Sets the margin from the top of a #ClutterActor.
16193 clutter_actor_set_margin_top (ClutterActor *self,
16196 ClutterLayoutInfo *info;
16198 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16199 g_return_if_fail (margin >= 0.f);
16201 info = _clutter_actor_get_layout_info (self);
16203 if (info->margin.top == margin)
16206 info->margin.top = margin;
16208 clutter_actor_queue_relayout (self);
16210 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16214 * clutter_actor_get_margin_top:
16215 * @self: a #ClutterActor
16217 * Retrieves the top margin of a #ClutterActor.
16219 * Return value: the top margin
16224 clutter_actor_get_margin_top (ClutterActor *self)
16226 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16228 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16232 * clutter_actor_set_margin_bottom:
16233 * @self: a #ClutterActor
16234 * @margin: the bottom margin
16236 * Sets the margin from the bottom of a #ClutterActor.
16241 clutter_actor_set_margin_bottom (ClutterActor *self,
16244 ClutterLayoutInfo *info;
16246 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16247 g_return_if_fail (margin >= 0.f);
16249 info = _clutter_actor_get_layout_info (self);
16251 if (info->margin.bottom == margin)
16254 info->margin.bottom = margin;
16256 clutter_actor_queue_relayout (self);
16258 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16262 * clutter_actor_get_margin_bottom:
16263 * @self: a #ClutterActor
16265 * Retrieves the bottom margin of a #ClutterActor.
16267 * Return value: the bottom margin
16272 clutter_actor_get_margin_bottom (ClutterActor *self)
16274 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16276 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16280 * clutter_actor_set_margin_left:
16281 * @self: a #ClutterActor
16282 * @margin: the left margin
16284 * Sets the margin from the left of a #ClutterActor.
16289 clutter_actor_set_margin_left (ClutterActor *self,
16292 ClutterLayoutInfo *info;
16294 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16295 g_return_if_fail (margin >= 0.f);
16297 info = _clutter_actor_get_layout_info (self);
16299 if (info->margin.left == margin)
16302 info->margin.left = margin;
16304 clutter_actor_queue_relayout (self);
16306 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16310 * clutter_actor_get_margin_left:
16311 * @self: a #ClutterActor
16313 * Retrieves the left margin of a #ClutterActor.
16315 * Return value: the left margin
16320 clutter_actor_get_margin_left (ClutterActor *self)
16322 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16324 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16328 * clutter_actor_set_margin_right:
16329 * @self: a #ClutterActor
16330 * @margin: the right margin
16332 * Sets the margin from the right of a #ClutterActor.
16337 clutter_actor_set_margin_right (ClutterActor *self,
16340 ClutterLayoutInfo *info;
16342 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16343 g_return_if_fail (margin >= 0.f);
16345 info = _clutter_actor_get_layout_info (self);
16347 if (info->margin.right == margin)
16350 info->margin.right = margin;
16352 clutter_actor_queue_relayout (self);
16354 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16358 * clutter_actor_get_margin_right:
16359 * @self: a #ClutterActor
16361 * Retrieves the right margin of a #ClutterActor.
16363 * Return value: the right margin
16368 clutter_actor_get_margin_right (ClutterActor *self)
16370 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16372 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16376 clutter_actor_set_background_color_internal (ClutterActor *self,
16377 const ClutterColor *color)
16379 ClutterActorPrivate *priv = self->priv;
16382 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16385 obj = G_OBJECT (self);
16387 priv->bg_color = *color;
16388 priv->bg_color_set = TRUE;
16390 clutter_actor_queue_redraw (self);
16392 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16393 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16397 * clutter_actor_set_background_color:
16398 * @self: a #ClutterActor
16399 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16402 * Sets the background color of a #ClutterActor.
16404 * The background color will be used to cover the whole allocation of the
16405 * actor. The default background color of an actor is transparent.
16407 * To check whether an actor has a background color, you can use the
16408 * #ClutterActor:background-color-set actor property.
16410 * The #ClutterActor:background-color property is animatable.
16415 clutter_actor_set_background_color (ClutterActor *self,
16416 const ClutterColor *color)
16418 ClutterActorPrivate *priv;
16420 GParamSpec *bg_color_pspec;
16422 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16424 obj = G_OBJECT (self);
16430 priv->bg_color_set = FALSE;
16431 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16432 clutter_actor_queue_redraw (self);
16436 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16437 if (clutter_actor_get_easing_duration (self) != 0)
16439 ClutterTransition *transition;
16441 transition = _clutter_actor_get_transition (self, bg_color_pspec);
16442 if (transition == NULL)
16444 transition = _clutter_actor_create_transition (self, bg_color_pspec,
16447 clutter_timeline_start (CLUTTER_TIMELINE (transition));
16450 _clutter_actor_update_transition (self, bg_color_pspec, color);
16452 clutter_actor_queue_redraw (self);
16455 clutter_actor_set_background_color_internal (self, color);
16459 * clutter_actor_get_background_color:
16460 * @self: a #ClutterActor
16461 * @color: (out caller-allocates): return location for a #ClutterColor
16463 * Retrieves the color set using clutter_actor_set_background_color().
16468 clutter_actor_get_background_color (ClutterActor *self,
16469 ClutterColor *color)
16471 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16472 g_return_if_fail (color != NULL);
16474 *color = self->priv->bg_color;
16478 * clutter_actor_get_previous_sibling:
16479 * @self: a #ClutterActor
16481 * Retrieves the sibling of @self that comes before it in the list
16482 * of children of @self's parent.
16484 * The returned pointer is only valid until the scene graph changes; it
16485 * is not safe to modify the list of children of @self while iterating
16488 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16493 clutter_actor_get_previous_sibling (ClutterActor *self)
16495 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16497 return self->priv->prev_sibling;
16501 * clutter_actor_get_next_sibling:
16502 * @self: a #ClutterActor
16504 * Retrieves the sibling of @self that comes after it in the list
16505 * of children of @self's parent.
16507 * The returned pointer is only valid until the scene graph changes; it
16508 * is not safe to modify the list of children of @self while iterating
16511 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16516 clutter_actor_get_next_sibling (ClutterActor *self)
16518 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16520 return self->priv->next_sibling;
16524 * clutter_actor_get_first_child:
16525 * @self: a #ClutterActor
16527 * Retrieves the first child of @self.
16529 * The returned pointer is only valid until the scene graph changes; it
16530 * is not safe to modify the list of children of @self while iterating
16533 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16538 clutter_actor_get_first_child (ClutterActor *self)
16540 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16542 return self->priv->first_child;
16546 * clutter_actor_get_last_child:
16547 * @self: a #ClutterActor
16549 * Retrieves the last child of @self.
16551 * The returned pointer is only valid until the scene graph changes; it
16552 * is not safe to modify the list of children of @self while iterating
16555 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16560 clutter_actor_get_last_child (ClutterActor *self)
16562 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16564 return self->priv->last_child;
16567 /* easy way to have properly named fields instead of the dummy ones
16568 * we use in the public structure
16570 typedef struct _RealActorIter
16572 ClutterActor *root; /* dummy1 */
16573 ClutterActor *current; /* dummy2 */
16574 gpointer padding_1; /* dummy3 */
16575 gint age; /* dummy4 */
16576 gpointer padding_2; /* dummy5 */
16580 * clutter_actor_iter_init:
16581 * @iter: a #ClutterActorIter
16582 * @root: a #ClutterActor
16584 * Initializes a #ClutterActorIter, which can then be used to iterate
16585 * efficiently over a section of the scene graph, and associates it
16588 * Modifying the scene graph section that contains @root will invalidate
16592 * ClutterActorIter iter;
16593 * ClutterActor *child;
16595 * clutter_actor_iter_init (&iter, container);
16596 * while (clutter_actor_iter_next (&iter, &child))
16598 * /* do something with child */
16605 clutter_actor_iter_init (ClutterActorIter *iter,
16606 ClutterActor *root)
16608 RealActorIter *ri = (RealActorIter *) iter;
16610 g_return_if_fail (iter != NULL);
16611 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16614 ri->current = NULL;
16615 ri->age = root->priv->age;
16619 * clutter_actor_iter_next:
16620 * @iter: a #ClutterActorIter
16621 * @child: (out): return location for a #ClutterActor
16623 * Advances the @iter and retrieves the next child of the root #ClutterActor
16624 * that was used to initialize the #ClutterActorIterator.
16626 * If the iterator can advance, this function returns %TRUE and sets the
16629 * If the iterator cannot advance, this function returns %FALSE, and
16630 * the contents of @child are undefined.
16632 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16637 clutter_actor_iter_next (ClutterActorIter *iter,
16638 ClutterActor **child)
16640 RealActorIter *ri = (RealActorIter *) iter;
16642 g_return_val_if_fail (iter != NULL, FALSE);
16643 g_return_val_if_fail (ri->root != NULL, FALSE);
16644 #ifndef G_DISABLE_ASSERT
16645 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16648 if (ri->current == NULL)
16649 ri->current = ri->root->priv->first_child;
16651 ri->current = ri->current->priv->next_sibling;
16654 *child = ri->current;
16656 return ri->current != NULL;
16660 * clutter_actor_iter_prev:
16661 * @iter: a #ClutterActorIter
16662 * @child: (out): return location for a #ClutterActor
16664 * Advances the @iter and retrieves the previous child of the root
16665 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16667 * If the iterator can advance, this function returns %TRUE and sets the
16670 * If the iterator cannot advance, this function returns %FALSE, and
16671 * the contents of @child are undefined.
16673 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16678 clutter_actor_iter_prev (ClutterActorIter *iter,
16679 ClutterActor **child)
16681 RealActorIter *ri = (RealActorIter *) iter;
16683 g_return_val_if_fail (iter != NULL, FALSE);
16684 g_return_val_if_fail (ri->root != NULL, FALSE);
16685 #ifndef G_DISABLE_ASSERT
16686 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16689 if (ri->current == NULL)
16690 ri->current = ri->root->priv->last_child;
16692 ri->current = ri->current->priv->prev_sibling;
16695 *child = ri->current;
16697 return ri->current != NULL;
16701 * clutter_actor_iter_remove:
16702 * @iter: a #ClutterActorIter
16704 * Safely removes the #ClutterActor currently pointer to by the iterator
16707 * This function can only be called after clutter_actor_iter_next() or
16708 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16709 * than once for the same actor.
16711 * This function will call clutter_actor_remove_child() internally.
16716 clutter_actor_iter_remove (ClutterActorIter *iter)
16718 RealActorIter *ri = (RealActorIter *) iter;
16721 g_return_if_fail (iter != NULL);
16722 g_return_if_fail (ri->root != NULL);
16723 #ifndef G_DISABLE_ASSERT
16724 g_return_if_fail (ri->age == ri->root->priv->age);
16726 g_return_if_fail (ri->current != NULL);
16732 ri->current = cur->priv->prev_sibling;
16734 clutter_actor_remove_child_internal (ri->root, cur,
16735 REMOVE_CHILD_DEFAULT_FLAGS);
16742 * clutter_actor_iter_destroy:
16743 * @iter: a #ClutterActorIter
16745 * Safely destroys the #ClutterActor currently pointer to by the iterator
16748 * This function can only be called after clutter_actor_iter_next() or
16749 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16750 * than once for the same actor.
16752 * This function will call clutter_actor_destroy() internally.
16757 clutter_actor_iter_destroy (ClutterActorIter *iter)
16759 RealActorIter *ri = (RealActorIter *) iter;
16762 g_return_if_fail (iter != NULL);
16763 g_return_if_fail (ri->root != NULL);
16764 #ifndef G_DISABLE_ASSERT
16765 g_return_if_fail (ri->age == ri->root->priv->age);
16767 g_return_if_fail (ri->current != NULL);
16773 ri->current = cur->priv->prev_sibling;
16775 clutter_actor_destroy (cur);
16781 static const ClutterAnimationInfo default_animation_info = {
16782 NULL, /* transitions */
16784 NULL, /* cur_state */
16788 clutter_animation_info_free (gpointer data)
16792 ClutterAnimationInfo *info = data;
16794 if (info->transitions != NULL)
16795 g_hash_table_unref (info->transitions);
16797 if (info->states != NULL)
16798 g_array_unref (info->states);
16800 g_slice_free (ClutterAnimationInfo, info);
16804 const ClutterAnimationInfo *
16805 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16807 const ClutterAnimationInfo *res;
16808 GObject *obj = G_OBJECT (self);
16810 res = g_object_get_qdata (obj, quark_actor_animation_info);
16814 return &default_animation_info;
16817 ClutterAnimationInfo *
16818 _clutter_actor_get_animation_info (ClutterActor *self)
16820 GObject *obj = G_OBJECT (self);
16821 ClutterAnimationInfo *res;
16823 res = g_object_get_qdata (obj, quark_actor_animation_info);
16826 res = g_slice_new (ClutterAnimationInfo);
16828 *res = default_animation_info;
16830 g_object_set_qdata_full (obj, quark_actor_animation_info,
16832 clutter_animation_info_free);
16838 ClutterTransition *
16839 _clutter_actor_get_transition (ClutterActor *actor,
16842 const ClutterAnimationInfo *info;
16844 info = _clutter_actor_get_animation_info_or_defaults (actor);
16846 if (info->transitions == NULL)
16849 return g_hash_table_lookup (info->transitions, pspec->name);
16852 typedef struct _TransitionClosure
16854 ClutterActor *actor;
16855 ClutterTransition *transition;
16857 gulong completed_id;
16858 } TransitionClosure;
16861 transition_closure_free (gpointer data)
16863 if (G_LIKELY (data != NULL))
16865 TransitionClosure *clos = data;
16867 g_signal_handler_disconnect (clos->transition, clos->completed_id);
16868 g_free (clos->name);
16870 g_slice_free (TransitionClosure, clos);
16875 on_transition_completed (ClutterTransition *transition,
16876 TransitionClosure *clos)
16878 ClutterAnimationInfo *info;
16880 info = _clutter_actor_get_animation_info (clos->actor);
16882 /* this will take care of cleaning clos for us */
16883 g_hash_table_remove (info->transitions, clos->name);
16887 _clutter_actor_update_transition (ClutterActor *actor,
16891 TransitionClosure *clos;
16892 ClutterInterval *interval;
16893 const ClutterAnimationInfo *info;
16896 GValue initial = G_VALUE_INIT;
16897 GValue final = G_VALUE_INIT;
16898 char *error = NULL;
16900 info = _clutter_actor_get_animation_info_or_defaults (actor);
16902 if (info->transitions == NULL)
16905 clos = g_hash_table_lookup (info->transitions, pspec->name);
16909 va_start (var_args, pspec);
16911 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16913 g_value_init (&initial, ptype);
16914 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16918 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16921 g_critical ("%s: %s", G_STRLOC, error);
16926 interval = clutter_transition_get_interval (clos->transition);
16927 clutter_interval_set_initial_value (interval, &initial);
16928 clutter_interval_set_final_value (interval, &final);
16930 clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16933 g_value_unset (&initial);
16934 g_value_unset (&final);
16940 * _clutter_actor_create_transition:
16941 * @actor: a #ClutterActor
16942 * @pspec: the property used for the transition
16943 * @...: initial and final state
16945 * Creates a #ClutterTransition for the property represented by @pspec.
16947 * Return value: a #ClutterTransition
16949 ClutterTransition *
16950 _clutter_actor_create_transition (ClutterActor *actor,
16954 ClutterAnimationInfo *info;
16955 ClutterTransition *res = NULL;
16956 gboolean call_restore = FALSE;
16957 TransitionClosure *clos;
16960 info = _clutter_actor_get_animation_info (actor);
16962 if (info->states == NULL)
16964 clutter_actor_save_easing_state (actor);
16965 call_restore = TRUE;
16968 if (info->transitions == NULL)
16969 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
16971 transition_closure_free);
16973 va_start (var_args, pspec);
16975 clos = g_hash_table_lookup (info->transitions, pspec->name);
16978 ClutterInterval *interval;
16979 GValue initial = G_VALUE_INIT;
16980 GValue final = G_VALUE_INIT;
16984 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16986 G_VALUE_COLLECT_INIT (&initial, ptype,
16991 g_critical ("%s: %s", G_STRLOC, error);
16996 G_VALUE_COLLECT_INIT (&final, ptype,
17002 g_critical ("%s: %s", G_STRLOC, error);
17003 g_value_unset (&initial);
17008 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17010 g_value_unset (&initial);
17011 g_value_unset (&final);
17013 res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17016 clutter_transition_set_interval (res, interval);
17017 clutter_transition_set_remove_on_complete (res, TRUE);
17019 clutter_actor_add_transition (actor, pspec->name, res);
17022 res = clos->transition;
17026 clutter_actor_restore_easing_state (actor);
17034 * clutter_actor_add_transition:
17035 * @self: a #ClutterActor
17036 * @name: the name of the transition to add
17037 * @transition: the #ClutterTransition to add
17039 * Adds a @transition to the #ClutterActor's list of animations.
17041 * The @name string is a per-actor unique identifier of the @transition: only
17042 * one #ClutterTransition can be associated to the specified @name.
17044 * The @transition will be given the easing duration, mode, and delay
17045 * associated to the actor's current easing state; it is possible to modify
17046 * these values after calling clutter_actor_add_transition().
17048 * This function is usually called implicitly when modifying an animatable
17054 clutter_actor_add_transition (ClutterActor *self,
17056 ClutterTransition *transition)
17058 ClutterTimeline *timeline;
17059 TransitionClosure *clos;
17060 ClutterAnimationInfo *info;
17062 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17063 g_return_if_fail (name != NULL);
17064 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17066 info = _clutter_actor_get_animation_info (self);
17068 if (info->cur_state == NULL)
17070 g_warning ("No easing state is defined for the actor '%s'; you "
17071 "must call clutter_actor_save_easing_state() before "
17072 "calling clutter_actor_add_transition().",
17073 _clutter_actor_get_debug_name (self));
17077 if (info->transitions == NULL)
17078 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17080 transition_closure_free);
17082 if (g_hash_table_lookup (info->transitions, name) != NULL)
17084 g_warning ("A transition with name '%s' already exists for "
17087 _clutter_actor_get_debug_name (self));
17091 timeline = CLUTTER_TIMELINE (transition);
17093 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17094 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17095 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17097 clos = g_slice_new (TransitionClosure);
17098 clos->actor = self;
17099 clos->transition = transition;
17100 clos->name = g_strdup (name);
17101 clos->completed_id = g_signal_connect (timeline, "completed",
17102 G_CALLBACK (on_transition_completed),
17105 g_hash_table_insert (info->transitions, clos->name, clos);
17109 * clutter_actor_remove_transition:
17110 * @self: a #ClutterActor
17111 * @name: the name of the transition to remove
17113 * Removes the transition stored inside a #ClutterActor using @name
17119 clutter_actor_remove_transition (ClutterActor *self,
17122 const ClutterAnimationInfo *info;
17124 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17125 g_return_if_fail (name != NULL);
17127 info = _clutter_actor_get_animation_info_or_defaults (self);
17129 if (info->transitions == NULL)
17132 g_hash_table_remove (info->transitions, name);
17136 * clutter_actor_remove_all_transitions:
17137 * @self: a #ClutterActor
17139 * Removes all transitions associated to @self.
17144 clutter_actor_remove_all_transitions (ClutterActor *self)
17146 const ClutterAnimationInfo *info;
17148 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17150 info = _clutter_actor_get_animation_info_or_defaults (self);
17151 if (info->transitions == NULL)
17154 g_hash_table_remove_all (info->transitions);
17158 * clutter_actor_set_easing_duration:
17159 * @self: a #ClutterActor
17160 * @msecs: the duration of the easing, or %NULL
17162 * Sets the duration of the tweening for animatable properties
17163 * of @self for the current easing state.
17165 * Calling this function will implicitly call
17166 * clutter_actor_save_easing_state() if no previous call to
17167 * that function was made.
17172 clutter_actor_set_easing_duration (ClutterActor *self,
17175 ClutterAnimationInfo *info;
17177 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17179 info = _clutter_actor_get_animation_info (self);
17181 if (info->states == NULL)
17182 clutter_actor_save_easing_state (self);
17184 if (info->cur_state->easing_duration != msecs)
17185 info->cur_state->easing_duration = msecs;
17189 * clutter_actor_get_easing_duration:
17190 * @self: a #ClutterActor
17192 * Retrieves the duration of the tweening for animatable
17193 * properties of @self for the current easing state.
17195 * Return value: the duration of the tweening, in milliseconds
17200 clutter_actor_get_easing_duration (ClutterActor *self)
17202 const ClutterAnimationInfo *info;
17204 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17206 info = _clutter_actor_get_animation_info_or_defaults (self);
17208 if (info->cur_state != NULL)
17209 return info->cur_state->easing_duration;
17215 * clutter_actor_set_easing_mode:
17216 * @self: a #ClutterActor
17217 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17219 * Sets the easing mode for the tweening of animatable properties
17222 * Calling this function will implicitly call
17223 * clutter_actor_save_easing_state() if no previous calls to
17224 * that function were made.
17229 clutter_actor_set_easing_mode (ClutterActor *self,
17230 ClutterAnimationMode mode)
17232 ClutterAnimationInfo *info;
17234 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17235 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17236 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17238 info = _clutter_actor_get_animation_info (self);
17240 if (info->states == NULL)
17241 clutter_actor_save_easing_state (self);
17243 if (info->cur_state->easing_mode != mode)
17244 info->cur_state->easing_mode = mode;
17248 * clutter_actor_get_easing_mode:
17249 * @self: a #ClutterActor
17251 * Retrieves the easing mode for the tweening of animatable properties
17252 * of @self for the current easing state.
17254 * Return value: an easing mode
17258 ClutterAnimationMode
17259 clutter_actor_get_easing_mode (ClutterActor *self)
17261 const ClutterAnimationInfo *info;
17263 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17265 info = _clutter_actor_get_animation_info_or_defaults (self);
17267 if (info->cur_state != NULL)
17268 return info->cur_state->easing_mode;
17270 return CLUTTER_EASE_OUT_CUBIC;
17274 * clutter_actor_set_easing_delay:
17275 * @self: a #ClutterActor
17276 * @msecs: the delay before the start of the tweening, in milliseconds
17278 * Sets the delay that should be applied before tweening animatable
17281 * Calling this function will implicitly call
17282 * clutter_actor_save_easing_state() if no previous calls to
17283 * that function were made.
17288 clutter_actor_set_easing_delay (ClutterActor *self,
17291 ClutterAnimationInfo *info;
17293 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17295 info = _clutter_actor_get_animation_info (self);
17297 if (info->states == NULL)
17298 clutter_actor_save_easing_state (self);
17300 if (info->cur_state->easing_delay != msecs)
17301 info->cur_state->easing_delay = msecs;
17305 * clutter_actor_get_easing_delay:
17306 * @self: a #ClutterActor
17308 * Retrieves the delay that should be applied when tweening animatable
17311 * Return value: a delay, in milliseconds
17316 clutter_actor_get_easing_delay (ClutterActor *self)
17318 const ClutterAnimationInfo *info;
17320 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17322 info = _clutter_actor_get_animation_info_or_defaults (self);
17324 if (info->cur_state != NULL)
17325 return info->cur_state->easing_delay;
17331 * clutter_actor_get_transition:
17332 * @self: a #ClutterActor
17333 * @name: the name of the transition
17335 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17336 * transition @name.
17338 * Transitions created for animatable properties use the name of the
17339 * property itself, for instance the code below:
17342 * clutter_actor_set_easing_duration (actor, 1000);
17343 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17345 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17346 * g_signal_connect (transition, "completed",
17347 * G_CALLBACK (on_transition_complete),
17351 * will call the <function>on_transition_complete</function> callback when
17352 * the transition is complete.
17354 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17355 * was found to match the passed name; the returned instance is owned
17356 * by Clutter and it should not be freed
17360 ClutterTransition *
17361 clutter_actor_get_transition (ClutterActor *self,
17364 TransitionClosure *clos;
17365 const ClutterAnimationInfo *info;
17367 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17368 g_return_val_if_fail (name != NULL, NULL);
17370 info = _clutter_actor_get_animation_info_or_defaults (self);
17372 if (info->transitions == NULL)
17375 clos = g_hash_table_lookup (info->transitions, name);
17379 return clos->transition;
17383 * clutter_actor_save_easing_state:
17384 * @self: a #ClutterActor
17386 * Saves the current easing state for animatable properties, and creates
17387 * a new state with the default values for easing mode and duration.
17392 clutter_actor_save_easing_state (ClutterActor *self)
17394 ClutterAnimationInfo *info;
17397 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17399 info = _clutter_actor_get_animation_info (self);
17401 if (info->states == NULL)
17402 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17404 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17405 new_state.easing_duration = 250;
17406 new_state.easing_delay = 0;
17408 g_array_append_val (info->states, new_state);
17410 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17414 * clutter_actor_restore_easing_state:
17415 * @self: a #ClutterActor
17417 * Restores the easing state as it was prior to a call to
17418 * clutter_actor_save_easing_state().
17423 clutter_actor_restore_easing_state (ClutterActor *self)
17425 ClutterAnimationInfo *info;
17427 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17429 info = _clutter_actor_get_animation_info (self);
17431 if (info->states == NULL)
17433 g_critical ("The function clutter_actor_restore_easing_state() has "
17434 "called without a previous call to "
17435 "clutter_actor_save_easing_state().");
17439 g_array_remove_index (info->states, info->states->len - 1);
17440 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17444 * clutter_actor_set_content:
17445 * @self: a #ClutterActor
17446 * @content: (allow-none): a #ClutterContent, or %NULL
17448 * Sets the contents of a #ClutterActor.
17453 clutter_actor_set_content (ClutterActor *self,
17454 ClutterContent *content)
17456 ClutterActorPrivate *priv;
17458 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17459 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17463 if (priv->content != NULL)
17465 _clutter_content_detached (priv->content, self);
17466 g_object_unref (priv->content);
17469 priv->content = content;
17471 if (priv->content != NULL)
17473 g_object_ref (priv->content);
17474 _clutter_content_attached (priv->content, self);
17477 /* given that the content is always painted within the allocation,
17478 * we only need to queue a redraw here
17480 clutter_actor_queue_redraw (self);
17482 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17484 /* if the content gravity is not resize-fill, and the new content has a
17485 * different preferred size than the previous one, then the content box
17486 * may have been changed. since we compute that lazily, we just notify
17487 * here, and let whomever watches :content-box do whatever they need to
17490 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17491 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17495 * clutter_actor_get_content:
17496 * @self: a #ClutterActor
17498 * Retrieves the contents of @self.
17500 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17501 * or %NULL if none was set
17506 clutter_actor_get_content (ClutterActor *self)
17508 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17510 return self->priv->content;
17514 * clutter_actor_set_content_gravity:
17515 * @self: a #ClutterActor
17516 * @gravity: the #ClutterContentGravity
17518 * Sets the gravity of the #ClutterContent used by @self.
17520 * See the description of the #ClutterActor:content-gravity property for
17521 * more information.
17526 clutter_actor_set_content_gravity (ClutterActor *self,
17527 ClutterContentGravity gravity)
17529 ClutterActorPrivate *priv;
17531 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17535 if (priv->content_gravity == gravity)
17538 priv->content_gravity = gravity;
17540 clutter_actor_queue_redraw (self);
17542 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17543 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17547 * clutter_actor_get_content_gravity:
17548 * @self: a #ClutterActor
17550 * Retrieves the content gravity as set using
17551 * clutter_actor_get_content_gravity().
17553 * Return value: the content gravity
17557 ClutterContentGravity
17558 clutter_actor_get_content_gravity (ClutterActor *self)
17560 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17561 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17563 return self->priv->content_gravity;
17567 * clutter_actor_get_content_box:
17568 * @self: a #ClutterActor
17569 * @box: (out caller-allocates): the return location for the bounding
17570 * box for the #ClutterContent
17572 * Retrieves the bounding box for the #ClutterContent of @self.
17574 * If no #ClutterContent is set for @self, or if @self has not been
17575 * allocated yet, then the result is undefined.
17577 * The content box is guaranteed to be, at most, as big as the allocation
17578 * of the #ClutterActor.
17580 * If the #ClutterContent used by the actor has a preferred size, then
17581 * it is possible to modify the content box by using the
17582 * #ClutterActor:content-gravity property.
17587 clutter_actor_get_content_box (ClutterActor *self,
17588 ClutterActorBox *box)
17590 ClutterActorPrivate *priv;
17591 gfloat content_w, content_h;
17592 gfloat alloc_w, alloc_h;
17594 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17595 g_return_if_fail (box != NULL);
17599 if (!clutter_actor_has_allocation (self))
17604 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17605 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17607 if (priv->content == NULL)
17610 /* no need to do any more work */
17611 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17614 /* if the content does not have a preferred size then there is
17615 * no point in computing the content box
17617 if (!_clutter_content_get_preferred_size (priv->content,
17622 clutter_actor_box_get_size (&priv->allocation, &alloc_w, &alloc_h);
17624 switch (priv->content_gravity)
17626 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17627 box->x2 = box->x1 + MIN (content_w, alloc_w);
17628 box->y2 = box->y1 + MIN (content_h, alloc_h);
17631 case CLUTTER_CONTENT_GRAVITY_TOP:
17632 if (alloc_w > content_w)
17634 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17635 box->x2 = box->x1 + content_w;
17637 box->y2 = box->y1 + MIN (content_h, alloc_h);
17640 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17641 if (alloc_w > content_w)
17643 box->x1 += (alloc_w - content_w);
17644 box->x2 = box->x1 + content_w;
17646 box->y2 = box->y1 + MIN (content_h, alloc_h);
17649 case CLUTTER_CONTENT_GRAVITY_LEFT:
17650 box->x2 = box->x1 + MIN (content_w, alloc_w);
17651 if (alloc_h > content_h)
17653 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17654 box->y2 = box->y1 + content_h;
17658 case CLUTTER_CONTENT_GRAVITY_CENTER:
17659 if (alloc_w > content_w)
17661 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17662 box->x2 = box->x1 + content_w;
17664 if (alloc_h > content_h)
17666 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17667 box->y2 = box->y1 + content_h;
17671 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17672 if (alloc_w > content_w)
17674 box->x1 += (alloc_w - content_w);
17675 box->x2 = box->x1 + content_w;
17677 if (alloc_h > content_h)
17679 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17680 box->y2 = box->y1 + content_h;
17684 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17685 box->x2 = box->x1 + MIN (content_w, alloc_w);
17686 if (alloc_h > content_h)
17688 box->y1 += (alloc_h - content_h);
17689 box->y2 = box->y1 + content_h;
17693 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17694 if (alloc_w > content_w)
17696 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17697 box->x2 = box->x1 + content_w;
17699 if (alloc_h > content_h)
17701 box->y1 += (alloc_h - content_h);
17702 box->y2 = box->y1 + content_h;
17706 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17707 if (alloc_w > content_w)
17709 box->x1 += (alloc_w - content_w);
17710 box->x2 = box->x1 + content_w;
17712 if (alloc_h > content_h)
17714 box->y1 += (alloc_h - content_h);
17715 box->y2 = box->y1 + content_h;
17719 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17720 g_assert_not_reached ();
17723 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17724 if (content_w >= content_h && content_h > 0)
17726 double ratio = content_w / content_h;
17728 box->x2 = box->x1 + alloc_w;
17730 box->y1 += ceilf ((alloc_h - (alloc_h / ratio)) / 2.0);
17731 box->y2 = box->y1 + (alloc_h / ratio);
17733 else if (content_h > content_w && content_w > 0)
17735 double ratio = content_h / content_w;
17737 box->x1 += ceilf ((alloc_w - (alloc_w / ratio)) / 2.0);
17738 box->x2 = box->x2 + (alloc_w / ratio);
17740 box->y2 = box->x1 + alloc_h;