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_paint_node (ClutterActor *actor,
3182 ClutterPaintNode *root)
3184 ClutterActorPrivate *priv = actor->priv;
3186 if (priv->bg_color_set)
3188 ClutterPaintNode *node;
3189 ClutterColor bg_color;
3191 bg_color = priv->bg_color;
3192 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3193 * priv->bg_color.alpha
3196 node = clutter_color_node_new (&bg_color);
3197 clutter_paint_node_set_name (node, "backgroundColor");
3198 clutter_paint_node_add_rectangle (node, &priv->allocation);
3199 clutter_paint_node_add_child (root, node);
3200 clutter_paint_node_unref (node);
3203 if (priv->content != NULL)
3204 _clutter_content_paint_content (priv->content, actor, root);
3206 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3207 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3209 if (clutter_paint_node_get_n_children (root) == 0)
3212 _clutter_paint_node_paint (root);
3216 clutter_actor_real_paint (ClutterActor *actor)
3218 ClutterActorPrivate *priv = actor->priv;
3221 for (iter = priv->first_child;
3223 iter = iter->priv->next_sibling)
3225 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3226 _clutter_actor_get_debug_name (iter),
3227 _clutter_actor_get_debug_name (actor),
3228 iter->priv->allocation.x1,
3229 iter->priv->allocation.y1,
3230 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3231 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3233 clutter_actor_paint (iter);
3238 * clutter_actor_paint:
3239 * @self: A #ClutterActor
3241 * Renders the actor to display.
3243 * This function should not be called directly by applications.
3244 * Call clutter_actor_queue_redraw() to queue paints, instead.
3246 * This function is context-aware, and will either cause a
3247 * regular paint or a pick paint.
3249 * This function will emit the #ClutterActor::paint signal or
3250 * the #ClutterActor::pick signal, depending on the context.
3252 * This function does not paint the actor if the actor is set to 0,
3253 * unless it is performing a pick paint.
3256 clutter_actor_paint (ClutterActor *self)
3258 ClutterActorPrivate *priv;
3259 ClutterPickMode pick_mode;
3260 gboolean clip_set = FALSE;
3261 gboolean shader_applied = FALSE;
3263 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3264 "Actor real-paint counter",
3265 "Increments each time any actor is painted",
3266 0 /* no application private data */);
3267 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3268 "Actor pick-paint counter",
3269 "Increments each time any actor is painted "
3271 0 /* no application private data */);
3273 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3275 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3280 pick_mode = _clutter_context_get_pick_mode ();
3282 if (pick_mode == CLUTTER_PICK_NONE)
3283 priv->propagated_one_redraw = FALSE;
3285 /* It's an important optimization that we consider painting of
3286 * actors with 0 opacity to be a NOP... */
3287 if (pick_mode == CLUTTER_PICK_NONE &&
3288 /* ignore top-levels, since they might be transparent */
3289 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3290 /* Use the override opacity if its been set */
3291 ((priv->opacity_override >= 0) ?
3292 priv->opacity_override : priv->opacity) == 0)
3295 /* if we aren't paintable (not in a toplevel with all
3296 * parents paintable) then do nothing.
3298 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3301 /* mark that we are in the paint process */
3302 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3306 if (priv->enable_model_view_transform)
3310 /* XXX: It could be better to cache the modelview with the actor
3311 * instead of progressively building up the transformations on
3312 * the matrix stack every time we paint. */
3313 cogl_get_modelview_matrix (&matrix);
3314 _clutter_actor_apply_modelview_transform (self, &matrix);
3316 #ifdef CLUTTER_ENABLE_DEBUG
3317 /* Catch when out-of-band transforms have been made by actors not as part
3318 * of an apply_transform vfunc... */
3319 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3321 CoglMatrix expected_matrix;
3323 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3326 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3328 GString *buf = g_string_sized_new (1024);
3329 ClutterActor *parent;
3332 while (parent != NULL)
3334 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3336 if (parent->priv->parent != NULL)
3337 g_string_append (buf, "->");
3339 parent = parent->priv->parent;
3342 g_warning ("Unexpected transform found when painting actor "
3343 "\"%s\". This will be caused by one of the actor's "
3344 "ancestors (%s) using the Cogl API directly to transform "
3345 "children instead of using ::apply_transform().",
3346 _clutter_actor_get_debug_name (self),
3349 g_string_free (buf, TRUE);
3352 #endif /* CLUTTER_ENABLE_DEBUG */
3354 cogl_set_modelview_matrix (&matrix);
3359 cogl_clip_push_rectangle (priv->clip.x,
3361 priv->clip.x + priv->clip.width,
3362 priv->clip.y + priv->clip.height);
3365 else if (priv->clip_to_allocation)
3367 gfloat width, height;
3369 width = priv->allocation.x2 - priv->allocation.x1;
3370 height = priv->allocation.y2 - priv->allocation.y1;
3372 cogl_clip_push_rectangle (0, 0, width, height);
3376 if (pick_mode == CLUTTER_PICK_NONE)
3378 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3380 /* We check whether we need to add the flatten effect before
3381 each paint so that we can avoid having a mechanism for
3382 applications to notify when the value of the
3383 has_overlaps virtual changes. */
3384 add_or_remove_flatten_effect (self);
3387 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3389 /* We save the current paint volume so that the next time the
3390 * actor queues a redraw we can constrain the redraw to just
3391 * cover the union of the new bounding box and the old.
3393 * We also fetch the current paint volume to perform culling so
3394 * we can avoid painting actors outside the current clip region.
3396 * If we are painting inside a clone, we should neither update
3397 * the paint volume or use it to cull painting, since the paint
3398 * box represents the location of the source actor on the
3401 * XXX: We are starting to do a lot of vertex transforms on
3402 * the CPU in a typical paint, so at some point we should
3403 * audit these and consider caching some things.
3405 * NB: We don't perform culling while picking at this point because
3406 * clutter-stage.c doesn't setup the clipping planes appropriately.
3408 * NB: We don't want to update the last-paint-volume during picking
3409 * because the last-paint-volume is used to determine the old screen
3410 * space location of an actor that has moved so we can know the
3411 * minimal region to redraw to clear an old view of the actor. If we
3412 * update this during picking then by the time we come around to
3413 * paint then the last-paint-volume would likely represent the new
3414 * actor position not the old.
3416 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3419 /* annoyingly gcc warns if uninitialized even though
3420 * the initialization is redundant :-( */
3421 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3423 if (G_LIKELY ((clutter_paint_debug_flags &
3424 (CLUTTER_DEBUG_DISABLE_CULLING |
3425 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3426 (CLUTTER_DEBUG_DISABLE_CULLING |
3427 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3428 _clutter_actor_update_last_paint_volume (self);
3430 success = cull_actor (self, &result);
3432 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3433 _clutter_actor_paint_cull_result (self, success, result);
3434 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3438 if (priv->effects == NULL)
3440 if (pick_mode == CLUTTER_PICK_NONE &&
3441 actor_has_shader_data (self))
3443 _clutter_actor_shader_pre_paint (self, FALSE);
3444 shader_applied = TRUE;
3447 priv->next_effect_to_paint = NULL;
3450 priv->next_effect_to_paint =
3451 _clutter_meta_group_peek_metas (priv->effects);
3453 clutter_actor_continue_paint (self);
3456 _clutter_actor_shader_post_paint (self);
3458 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3459 pick_mode == CLUTTER_PICK_NONE))
3460 _clutter_actor_draw_paint_volume (self);
3463 /* If we make it here then the actor has run through a complete
3464 paint run including all the effects so it's no longer dirty */
3465 if (pick_mode == CLUTTER_PICK_NONE)
3466 priv->is_dirty = FALSE;
3473 /* paint sequence complete */
3474 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3478 * clutter_actor_continue_paint:
3479 * @self: A #ClutterActor
3481 * Run the next stage of the paint sequence. This function should only
3482 * be called within the implementation of the ‘run’ virtual of a
3483 * #ClutterEffect. It will cause the run method of the next effect to
3484 * be applied, or it will paint the actual actor if the current effect
3485 * is the last effect in the chain.
3490 clutter_actor_continue_paint (ClutterActor *self)
3492 ClutterActorPrivate *priv;
3494 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3495 /* This should only be called from with in the ‘run’ implementation
3496 of a ClutterEffect */
3497 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3501 /* Skip any effects that are disabled */
3502 while (priv->next_effect_to_paint &&
3503 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3504 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3506 /* If this has come from the last effect then we'll just paint the
3508 if (priv->next_effect_to_paint == NULL)
3510 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3512 ClutterPaintNode *dummy;
3514 /* XXX - this will go away in 2.0, when we can get rid of this
3515 * stuff and switch to a pure retained render tree of PaintNodes
3516 * for the entire frame, starting from the Stage.
3518 dummy = _clutter_dummy_node_new ();
3519 clutter_paint_node_set_name (dummy, "Root");
3520 clutter_actor_paint_node (self, dummy);
3522 if (clutter_paint_node_get_n_children (dummy) != 0)
3524 #ifdef CLUTTER_ENABLE_DEBUG
3525 if (CLUTTER_HAS_DEBUG (PAINT))
3527 /* dump the tree only if we have one */
3528 _clutter_paint_node_dump_tree (dummy);
3530 #endif /* CLUTTER_ENABLE_DEBUG */
3532 _clutter_paint_node_paint (dummy);
3535 clutter_paint_node_unref (dummy);
3537 g_signal_emit (self, actor_signals[PAINT], 0);
3541 ClutterColor col = { 0, };
3543 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3545 /* Actor will then paint silhouette of itself in supplied
3546 * color. See clutter_stage_get_actor_at_pos() for where
3547 * picking is enabled.
3549 g_signal_emit (self, actor_signals[PICK], 0, &col);
3554 ClutterEffect *old_current_effect;
3555 ClutterEffectPaintFlags run_flags = 0;
3557 /* Cache the current effect so that we can put it back before
3559 old_current_effect = priv->current_effect;
3561 priv->current_effect = priv->next_effect_to_paint->data;
3562 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3564 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3568 /* If there's an effect queued with this redraw then all
3569 effects up to that one will be considered dirty. It
3570 is expected the queued effect will paint the cached
3571 image and not call clutter_actor_continue_paint again
3572 (although it should work ok if it does) */
3573 if (priv->effect_to_redraw == NULL ||
3574 priv->current_effect != priv->effect_to_redraw)
3575 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3578 _clutter_effect_paint (priv->current_effect, run_flags);
3582 /* We can't determine when an actor has been modified since
3583 its last pick so lets just assume it has always been
3585 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3587 _clutter_effect_pick (priv->current_effect, run_flags);
3590 priv->current_effect = old_current_effect;
3594 static ClutterActorTraverseVisitFlags
3595 invalidate_queue_redraw_entry (ClutterActor *self,
3599 ClutterActorPrivate *priv = self->priv;
3601 if (priv->queue_redraw_entry != NULL)
3603 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3604 priv->queue_redraw_entry = NULL;
3607 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3611 remove_child (ClutterActor *self,
3612 ClutterActor *child)
3614 ClutterActor *prev_sibling, *next_sibling;
3616 prev_sibling = child->priv->prev_sibling;
3617 next_sibling = child->priv->next_sibling;
3619 if (prev_sibling != NULL)
3620 prev_sibling->priv->next_sibling = next_sibling;
3622 if (next_sibling != NULL)
3623 next_sibling->priv->prev_sibling = prev_sibling;
3625 if (self->priv->first_child == child)
3626 self->priv->first_child = next_sibling;
3628 if (self->priv->last_child == child)
3629 self->priv->last_child = prev_sibling;
3631 child->priv->parent = NULL;
3632 child->priv->prev_sibling = NULL;
3633 child->priv->next_sibling = NULL;
3637 REMOVE_CHILD_DESTROY_META = 1 << 0,
3638 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3639 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3640 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3641 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3642 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3644 /* default flags for public API */
3645 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3646 REMOVE_CHILD_EMIT_PARENT_SET |
3647 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3648 REMOVE_CHILD_CHECK_STATE |
3649 REMOVE_CHILD_FLUSH_QUEUE |
3650 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3652 /* flags for legacy/deprecated API */
3653 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3654 REMOVE_CHILD_FLUSH_QUEUE |
3655 REMOVE_CHILD_EMIT_PARENT_SET |
3656 REMOVE_CHILD_NOTIFY_FIRST_LAST
3657 } ClutterActorRemoveChildFlags;
3660 * clutter_actor_remove_child_internal:
3661 * @self: a #ClutterActor
3662 * @child: the child of @self that has to be removed
3663 * @flags: control the removal operations
3665 * Removes @child from the list of children of @self.
3668 clutter_actor_remove_child_internal (ClutterActor *self,
3669 ClutterActor *child,
3670 ClutterActorRemoveChildFlags flags)
3672 ClutterActor *old_first, *old_last;
3673 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3674 gboolean flush_queue;
3675 gboolean notify_first_last;
3676 gboolean was_mapped;
3678 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3679 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3680 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3681 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3682 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3683 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3685 g_object_freeze_notify (G_OBJECT (self));
3688 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3692 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3694 /* we need to unrealize *before* we set parent_actor to NULL,
3695 * because in an unrealize method actors are dissociating from the
3696 * stage, which means they need to be able to
3697 * clutter_actor_get_stage().
3699 * yhis should unmap and unrealize, unless we're reparenting.
3701 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3708 /* We take this opportunity to invalidate any queue redraw entry
3709 * associated with the actor and descendants since we won't be able to
3710 * determine the appropriate stage after this.
3712 * we do this after we updated the mapped state because actors might
3713 * end up queueing redraws inside their mapped/unmapped virtual
3714 * functions, and if we invalidate the redraw entry we could end up
3715 * with an inconsistent state and weird memory corruption. see
3718 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3719 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3721 _clutter_actor_traverse (child,
3723 invalidate_queue_redraw_entry,
3728 old_first = self->priv->first_child;
3729 old_last = self->priv->last_child;
3731 remove_child (self, child);
3733 self->priv->n_children -= 1;
3735 self->priv->age += 1;
3737 /* clutter_actor_reparent() will emit ::parent-set for us */
3738 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3739 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3741 /* if the child was mapped then we need to relayout ourselves to account
3742 * for the removed child
3745 clutter_actor_queue_relayout (self);
3747 /* we need to emit the signal before dropping the reference */
3748 if (emit_actor_removed)
3749 g_signal_emit_by_name (self, "actor-removed", child);
3751 if (notify_first_last)
3753 if (old_first != self->priv->first_child)
3754 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3756 if (old_last != self->priv->last_child)
3757 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3760 g_object_thaw_notify (G_OBJECT (self));
3762 /* remove the reference we acquired in clutter_actor_add_child() */
3763 g_object_unref (child);
3766 static const ClutterTransformInfo default_transform_info = {
3767 0.0, { 0, }, /* rotation-x */
3768 0.0, { 0, }, /* rotation-y */
3769 0.0, { 0, }, /* rotation-z */
3771 1.0, 1.0, { 0, }, /* scale */
3773 { 0, }, /* anchor */
3779 * _clutter_actor_get_transform_info_or_defaults:
3780 * @self: a #ClutterActor
3782 * Retrieves the ClutterTransformInfo structure associated to an actor.
3784 * If the actor does not have a ClutterTransformInfo structure associated
3785 * to it, then the default structure will be returned.
3787 * This function should only be used for getters.
3789 * Return value: a const pointer to the ClutterTransformInfo structure
3791 const ClutterTransformInfo *
3792 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3794 ClutterTransformInfo *info;
3796 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3800 return &default_transform_info;
3804 clutter_transform_info_free (gpointer data)
3807 g_slice_free (ClutterTransformInfo, data);
3811 * _clutter_actor_get_transform_info:
3812 * @self: a #ClutterActor
3814 * Retrieves a pointer to the ClutterTransformInfo structure.
3816 * If the actor does not have a ClutterTransformInfo associated to it, one
3817 * will be created and initialized to the default values.
3819 * This function should be used for setters.
3821 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3824 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3827 ClutterTransformInfo *
3828 _clutter_actor_get_transform_info (ClutterActor *self)
3830 ClutterTransformInfo *info;
3832 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3835 info = g_slice_new (ClutterTransformInfo);
3837 *info = default_transform_info;
3839 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3841 clutter_transform_info_free);
3848 * clutter_actor_set_rotation_angle_internal:
3849 * @self: a #ClutterActor
3850 * @axis: the axis of the angle to change
3851 * @angle: the angle of rotation
3853 * Sets the rotation angle on the given axis without affecting the
3854 * rotation center point.
3857 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3858 ClutterRotateAxis axis,
3861 GObject *obj = G_OBJECT (self);
3862 ClutterTransformInfo *info;
3864 info = _clutter_actor_get_transform_info (self);
3866 g_object_freeze_notify (obj);
3870 case CLUTTER_X_AXIS:
3871 info->rx_angle = angle;
3872 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3875 case CLUTTER_Y_AXIS:
3876 info->ry_angle = angle;
3877 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3880 case CLUTTER_Z_AXIS:
3881 info->rz_angle = angle;
3882 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3886 self->priv->transform_valid = FALSE;
3888 g_object_thaw_notify (obj);
3890 clutter_actor_queue_redraw (self);
3894 clutter_actor_set_rotation_angle (ClutterActor *self,
3895 ClutterRotateAxis axis,
3898 ClutterTransformInfo *info;
3900 info = _clutter_actor_get_transform_info (self);
3902 if (clutter_actor_get_easing_duration (self) != 0)
3904 ClutterTransition *transition;
3905 GParamSpec *pspec = NULL;
3906 double *cur_angle_p = NULL;
3910 case CLUTTER_X_AXIS:
3911 cur_angle_p = &info->rx_angle;
3912 pspec = obj_props[PROP_ROTATION_ANGLE_X];
3915 case CLUTTER_Y_AXIS:
3916 cur_angle_p = &info->ry_angle;
3917 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3920 case CLUTTER_Z_AXIS:
3921 cur_angle_p = &info->rz_angle;
3922 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3926 g_assert (pspec != NULL);
3927 g_assert (cur_angle_p != NULL);
3929 transition = _clutter_actor_get_transition (self, pspec);
3930 if (transition == NULL)
3932 transition = _clutter_actor_create_transition (self, pspec,
3935 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3938 _clutter_actor_update_transition (self, pspec, angle);
3940 self->priv->transform_valid = FALSE;
3941 clutter_actor_queue_redraw (self);
3944 clutter_actor_set_rotation_angle_internal (self, axis, angle);
3948 * clutter_actor_set_rotation_center_internal:
3949 * @self: a #ClutterActor
3950 * @axis: the axis of the center to change
3951 * @center: the coordinates of the rotation center
3953 * Sets the rotation center on the given axis without affecting the
3957 clutter_actor_set_rotation_center_internal (ClutterActor *self,
3958 ClutterRotateAxis axis,
3959 const ClutterVertex *center)
3961 GObject *obj = G_OBJECT (self);
3962 ClutterTransformInfo *info;
3963 ClutterVertex v = { 0, 0, 0 };
3965 info = _clutter_actor_get_transform_info (self);
3970 g_object_freeze_notify (obj);
3974 case CLUTTER_X_AXIS:
3975 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3976 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3979 case CLUTTER_Y_AXIS:
3980 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3981 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3984 case CLUTTER_Z_AXIS:
3985 /* if the previously set rotation center was fractional, then
3986 * setting explicit coordinates will have to notify the
3987 * :rotation-center-z-gravity property as well
3989 if (info->rz_center.is_fractional)
3990 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3992 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3993 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3997 self->priv->transform_valid = FALSE;
3999 g_object_thaw_notify (obj);
4001 clutter_actor_queue_redraw (self);
4005 clutter_actor_animate_scale_factor (ClutterActor *self,
4010 ClutterTransition *transition;
4012 transition = _clutter_actor_get_transition (self, pspec);
4013 if (transition == NULL)
4015 transition = _clutter_actor_create_transition (self, pspec,
4018 clutter_timeline_start (CLUTTER_TIMELINE (transition));
4021 _clutter_actor_update_transition (self, pspec, new_factor);
4024 self->priv->transform_valid = FALSE;
4025 clutter_actor_queue_redraw (self);
4029 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4033 GObject *obj = G_OBJECT (self);
4034 ClutterTransformInfo *info;
4036 info = _clutter_actor_get_transform_info (self);
4038 if (pspec == obj_props[PROP_SCALE_X])
4039 info->scale_x = factor;
4041 info->scale_y = factor;
4043 self->priv->transform_valid = FALSE;
4044 clutter_actor_queue_redraw (self);
4045 g_object_notify_by_pspec (obj, pspec);
4049 clutter_actor_set_scale_factor (ClutterActor *self,
4050 ClutterRotateAxis axis,
4053 GObject *obj = G_OBJECT (self);
4054 ClutterTransformInfo *info;
4057 info = _clutter_actor_get_transform_info (self);
4059 g_object_freeze_notify (obj);
4063 case CLUTTER_X_AXIS:
4064 pspec = obj_props[PROP_SCALE_X];
4066 if (clutter_actor_get_easing_duration (self) != 0)
4067 clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4069 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4072 case CLUTTER_Y_AXIS:
4073 pspec = obj_props[PROP_SCALE_Y];
4075 if (clutter_actor_get_easing_duration (self) != 0)
4076 clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4078 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4082 g_assert_not_reached ();
4085 g_object_thaw_notify (obj);
4089 clutter_actor_set_scale_center (ClutterActor *self,
4090 ClutterRotateAxis axis,
4093 GObject *obj = G_OBJECT (self);
4094 ClutterTransformInfo *info;
4095 gfloat center_x, center_y;
4097 info = _clutter_actor_get_transform_info (self);
4099 g_object_freeze_notify (obj);
4101 /* get the current scale center coordinates */
4102 clutter_anchor_coord_get_units (self, &info->scale_center,
4107 /* we need to notify this too, because setting explicit coordinates will
4108 * change the gravity as a side effect
4110 if (info->scale_center.is_fractional)
4111 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4115 case CLUTTER_X_AXIS:
4116 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4117 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4120 case CLUTTER_Y_AXIS:
4121 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4122 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4126 g_assert_not_reached ();
4129 self->priv->transform_valid = FALSE;
4131 clutter_actor_queue_redraw (self);
4133 g_object_thaw_notify (obj);
4137 clutter_actor_set_anchor_coord (ClutterActor *self,
4138 ClutterRotateAxis axis,
4141 GObject *obj = G_OBJECT (self);
4142 ClutterTransformInfo *info;
4143 gfloat anchor_x, anchor_y;
4145 info = _clutter_actor_get_transform_info (self);
4147 g_object_freeze_notify (obj);
4149 clutter_anchor_coord_get_units (self, &info->anchor,
4154 if (info->anchor.is_fractional)
4155 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4159 case CLUTTER_X_AXIS:
4160 clutter_anchor_coord_set_units (&info->anchor,
4164 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4167 case CLUTTER_Y_AXIS:
4168 clutter_anchor_coord_set_units (&info->anchor,
4172 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4176 g_assert_not_reached ();
4179 self->priv->transform_valid = FALSE;
4181 clutter_actor_queue_redraw (self);
4183 g_object_thaw_notify (obj);
4187 clutter_actor_set_property (GObject *object,
4189 const GValue *value,
4192 ClutterActor *actor = CLUTTER_ACTOR (object);
4193 ClutterActorPrivate *priv = actor->priv;
4198 clutter_actor_set_x (actor, g_value_get_float (value));
4202 clutter_actor_set_y (actor, g_value_get_float (value));
4206 clutter_actor_set_width (actor, g_value_get_float (value));
4210 clutter_actor_set_height (actor, g_value_get_float (value));
4214 clutter_actor_set_x (actor, g_value_get_float (value));
4218 clutter_actor_set_y (actor, g_value_get_float (value));
4221 case PROP_FIXED_POSITION_SET:
4222 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4225 case PROP_MIN_WIDTH:
4226 clutter_actor_set_min_width (actor, g_value_get_float (value));
4229 case PROP_MIN_HEIGHT:
4230 clutter_actor_set_min_height (actor, g_value_get_float (value));
4233 case PROP_NATURAL_WIDTH:
4234 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4237 case PROP_NATURAL_HEIGHT:
4238 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4241 case PROP_MIN_WIDTH_SET:
4242 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4245 case PROP_MIN_HEIGHT_SET:
4246 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4249 case PROP_NATURAL_WIDTH_SET:
4250 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4253 case PROP_NATURAL_HEIGHT_SET:
4254 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4257 case PROP_REQUEST_MODE:
4258 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4262 clutter_actor_set_depth (actor, g_value_get_float (value));
4266 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4269 case PROP_OFFSCREEN_REDIRECT:
4270 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4274 clutter_actor_set_name (actor, g_value_get_string (value));
4278 if (g_value_get_boolean (value) == TRUE)
4279 clutter_actor_show (actor);
4281 clutter_actor_hide (actor);
4285 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4286 g_value_get_double (value));
4290 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4291 g_value_get_double (value));
4294 case PROP_SCALE_CENTER_X:
4295 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4296 g_value_get_float (value));
4299 case PROP_SCALE_CENTER_Y:
4300 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4301 g_value_get_float (value));
4304 case PROP_SCALE_GRAVITY:
4306 const ClutterTransformInfo *info;
4307 ClutterGravity gravity;
4309 info = _clutter_actor_get_transform_info_or_defaults (actor);
4310 gravity = g_value_get_enum (value);
4312 clutter_actor_set_scale_with_gravity (actor,
4321 const ClutterGeometry *geom = g_value_get_boxed (value);
4323 clutter_actor_set_clip (actor,
4325 geom->width, geom->height);
4329 case PROP_CLIP_TO_ALLOCATION:
4330 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4334 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4337 case PROP_ROTATION_ANGLE_X:
4338 clutter_actor_set_rotation_angle (actor,
4340 g_value_get_double (value));
4343 case PROP_ROTATION_ANGLE_Y:
4344 clutter_actor_set_rotation_angle (actor,
4346 g_value_get_double (value));
4349 case PROP_ROTATION_ANGLE_Z:
4350 clutter_actor_set_rotation_angle (actor,
4352 g_value_get_double (value));
4355 case PROP_ROTATION_CENTER_X:
4356 clutter_actor_set_rotation_center_internal (actor,
4358 g_value_get_boxed (value));
4361 case PROP_ROTATION_CENTER_Y:
4362 clutter_actor_set_rotation_center_internal (actor,
4364 g_value_get_boxed (value));
4367 case PROP_ROTATION_CENTER_Z:
4368 clutter_actor_set_rotation_center_internal (actor,
4370 g_value_get_boxed (value));
4373 case PROP_ROTATION_CENTER_Z_GRAVITY:
4375 const ClutterTransformInfo *info;
4377 info = _clutter_actor_get_transform_info_or_defaults (actor);
4378 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4379 g_value_get_enum (value));
4384 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4385 g_value_get_float (value));
4389 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4390 g_value_get_float (value));
4393 case PROP_ANCHOR_GRAVITY:
4394 clutter_actor_set_anchor_point_from_gravity (actor,
4395 g_value_get_enum (value));
4398 case PROP_SHOW_ON_SET_PARENT:
4399 priv->show_on_set_parent = g_value_get_boolean (value);
4402 case PROP_TEXT_DIRECTION:
4403 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4407 clutter_actor_add_action (actor, g_value_get_object (value));
4410 case PROP_CONSTRAINTS:
4411 clutter_actor_add_constraint (actor, g_value_get_object (value));
4415 clutter_actor_add_effect (actor, g_value_get_object (value));
4418 case PROP_LAYOUT_MANAGER:
4419 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4423 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4427 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4430 case PROP_MARGIN_TOP:
4431 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4434 case PROP_MARGIN_BOTTOM:
4435 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4438 case PROP_MARGIN_LEFT:
4439 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4442 case PROP_MARGIN_RIGHT:
4443 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4446 case PROP_BACKGROUND_COLOR:
4447 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4451 clutter_actor_set_content (actor, g_value_get_object (value));
4454 case PROP_CONTENT_GRAVITY:
4455 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4459 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4465 clutter_actor_get_property (GObject *object,
4470 ClutterActor *actor = CLUTTER_ACTOR (object);
4471 ClutterActorPrivate *priv = actor->priv;
4476 g_value_set_float (value, clutter_actor_get_x (actor));
4480 g_value_set_float (value, clutter_actor_get_y (actor));
4484 g_value_set_float (value, clutter_actor_get_width (actor));
4488 g_value_set_float (value, clutter_actor_get_height (actor));
4493 const ClutterLayoutInfo *info;
4495 info = _clutter_actor_get_layout_info_or_defaults (actor);
4496 g_value_set_float (value, info->fixed_x);
4502 const ClutterLayoutInfo *info;
4504 info = _clutter_actor_get_layout_info_or_defaults (actor);
4505 g_value_set_float (value, info->fixed_y);
4509 case PROP_FIXED_POSITION_SET:
4510 g_value_set_boolean (value, priv->position_set);
4513 case PROP_MIN_WIDTH:
4515 const ClutterLayoutInfo *info;
4517 info = _clutter_actor_get_layout_info_or_defaults (actor);
4518 g_value_set_float (value, info->min_width);
4522 case PROP_MIN_HEIGHT:
4524 const ClutterLayoutInfo *info;
4526 info = _clutter_actor_get_layout_info_or_defaults (actor);
4527 g_value_set_float (value, info->min_height);
4531 case PROP_NATURAL_WIDTH:
4533 const ClutterLayoutInfo *info;
4535 info = _clutter_actor_get_layout_info_or_defaults (actor);
4536 g_value_set_float (value, info->natural_width);
4540 case PROP_NATURAL_HEIGHT:
4542 const ClutterLayoutInfo *info;
4544 info = _clutter_actor_get_layout_info_or_defaults (actor);
4545 g_value_set_float (value, info->natural_height);
4549 case PROP_MIN_WIDTH_SET:
4550 g_value_set_boolean (value, priv->min_width_set);
4553 case PROP_MIN_HEIGHT_SET:
4554 g_value_set_boolean (value, priv->min_height_set);
4557 case PROP_NATURAL_WIDTH_SET:
4558 g_value_set_boolean (value, priv->natural_width_set);
4561 case PROP_NATURAL_HEIGHT_SET:
4562 g_value_set_boolean (value, priv->natural_height_set);
4565 case PROP_REQUEST_MODE:
4566 g_value_set_enum (value, priv->request_mode);
4569 case PROP_ALLOCATION:
4570 g_value_set_boxed (value, &priv->allocation);
4574 g_value_set_float (value, clutter_actor_get_depth (actor));
4578 g_value_set_uint (value, priv->opacity);
4581 case PROP_OFFSCREEN_REDIRECT:
4582 g_value_set_enum (value, priv->offscreen_redirect);
4586 g_value_set_string (value, priv->name);
4590 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4594 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4598 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4602 g_value_set_boolean (value, priv->has_clip);
4607 ClutterGeometry clip;
4609 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4610 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4611 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4612 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4614 g_value_set_boxed (value, &clip);
4618 case PROP_CLIP_TO_ALLOCATION:
4619 g_value_set_boolean (value, priv->clip_to_allocation);
4624 const ClutterTransformInfo *info;
4626 info = _clutter_actor_get_transform_info_or_defaults (actor);
4627 g_value_set_double (value, info->scale_x);
4633 const ClutterTransformInfo *info;
4635 info = _clutter_actor_get_transform_info_or_defaults (actor);
4636 g_value_set_double (value, info->scale_y);
4640 case PROP_SCALE_CENTER_X:
4644 clutter_actor_get_scale_center (actor, ¢er, NULL);
4646 g_value_set_float (value, center);
4650 case PROP_SCALE_CENTER_Y:
4654 clutter_actor_get_scale_center (actor, NULL, ¢er);
4656 g_value_set_float (value, center);
4660 case PROP_SCALE_GRAVITY:
4661 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4665 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4668 case PROP_ROTATION_ANGLE_X:
4670 const ClutterTransformInfo *info;
4672 info = _clutter_actor_get_transform_info_or_defaults (actor);
4673 g_value_set_double (value, info->rx_angle);
4677 case PROP_ROTATION_ANGLE_Y:
4679 const ClutterTransformInfo *info;
4681 info = _clutter_actor_get_transform_info_or_defaults (actor);
4682 g_value_set_double (value, info->ry_angle);
4686 case PROP_ROTATION_ANGLE_Z:
4688 const ClutterTransformInfo *info;
4690 info = _clutter_actor_get_transform_info_or_defaults (actor);
4691 g_value_set_double (value, info->rz_angle);
4695 case PROP_ROTATION_CENTER_X:
4697 ClutterVertex center;
4699 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4704 g_value_set_boxed (value, ¢er);
4708 case PROP_ROTATION_CENTER_Y:
4710 ClutterVertex center;
4712 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4717 g_value_set_boxed (value, ¢er);
4721 case PROP_ROTATION_CENTER_Z:
4723 ClutterVertex center;
4725 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4730 g_value_set_boxed (value, ¢er);
4734 case PROP_ROTATION_CENTER_Z_GRAVITY:
4735 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4740 const ClutterTransformInfo *info;
4743 info = _clutter_actor_get_transform_info_or_defaults (actor);
4744 clutter_anchor_coord_get_units (actor, &info->anchor,
4748 g_value_set_float (value, anchor_x);
4754 const ClutterTransformInfo *info;
4757 info = _clutter_actor_get_transform_info_or_defaults (actor);
4758 clutter_anchor_coord_get_units (actor, &info->anchor,
4762 g_value_set_float (value, anchor_y);
4766 case PROP_ANCHOR_GRAVITY:
4767 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4770 case PROP_SHOW_ON_SET_PARENT:
4771 g_value_set_boolean (value, priv->show_on_set_parent);
4774 case PROP_TEXT_DIRECTION:
4775 g_value_set_enum (value, priv->text_direction);
4778 case PROP_HAS_POINTER:
4779 g_value_set_boolean (value, priv->has_pointer);
4782 case PROP_LAYOUT_MANAGER:
4783 g_value_set_object (value, priv->layout_manager);
4788 const ClutterLayoutInfo *info;
4790 info = _clutter_actor_get_layout_info_or_defaults (actor);
4791 g_value_set_enum (value, info->x_align);
4797 const ClutterLayoutInfo *info;
4799 info = _clutter_actor_get_layout_info_or_defaults (actor);
4800 g_value_set_enum (value, info->y_align);
4804 case PROP_MARGIN_TOP:
4806 const ClutterLayoutInfo *info;
4808 info = _clutter_actor_get_layout_info_or_defaults (actor);
4809 g_value_set_float (value, info->margin.top);
4813 case PROP_MARGIN_BOTTOM:
4815 const ClutterLayoutInfo *info;
4817 info = _clutter_actor_get_layout_info_or_defaults (actor);
4818 g_value_set_float (value, info->margin.bottom);
4822 case PROP_MARGIN_LEFT:
4824 const ClutterLayoutInfo *info;
4826 info = _clutter_actor_get_layout_info_or_defaults (actor);
4827 g_value_set_float (value, info->margin.left);
4831 case PROP_MARGIN_RIGHT:
4833 const ClutterLayoutInfo *info;
4835 info = _clutter_actor_get_layout_info_or_defaults (actor);
4836 g_value_set_float (value, info->margin.right);
4840 case PROP_BACKGROUND_COLOR_SET:
4841 g_value_set_boolean (value, priv->bg_color_set);
4844 case PROP_BACKGROUND_COLOR:
4845 g_value_set_boxed (value, &priv->bg_color);
4848 case PROP_FIRST_CHILD:
4849 g_value_set_object (value, priv->first_child);
4852 case PROP_LAST_CHILD:
4853 g_value_set_object (value, priv->last_child);
4857 g_value_set_object (value, priv->content);
4860 case PROP_CONTENT_GRAVITY:
4861 g_value_set_enum (value, priv->content_gravity);
4864 case PROP_CONTENT_BOX:
4866 ClutterActorBox box = { 0, };
4868 clutter_actor_get_content_box (actor, &box);
4869 g_value_set_boxed (value, &box);
4874 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4880 clutter_actor_dispose (GObject *object)
4882 ClutterActor *self = CLUTTER_ACTOR (object);
4883 ClutterActorPrivate *priv = self->priv;
4885 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4887 g_type_name (G_OBJECT_TYPE (self)),
4890 g_signal_emit (self, actor_signals[DESTROY], 0);
4892 /* avoid recursing when called from clutter_actor_destroy() */
4893 if (priv->parent != NULL)
4895 ClutterActor *parent = priv->parent;
4897 /* go through the Container implementation unless this
4898 * is an internal child and has been marked as such.
4900 * removing the actor from its parent will reset the
4901 * realized and mapped states.
4903 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4904 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4906 clutter_actor_remove_child_internal (parent, self,
4907 REMOVE_CHILD_LEGACY_FLAGS);
4910 /* parent must be gone at this point */
4911 g_assert (priv->parent == NULL);
4913 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4915 /* can't be mapped or realized with no parent */
4916 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4917 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4920 g_clear_object (&priv->pango_context);
4921 g_clear_object (&priv->actions);
4922 g_clear_object (&priv->constraints);
4923 g_clear_object (&priv->effects);
4924 g_clear_object (&priv->flatten_effect);
4926 if (priv->layout_manager != NULL)
4928 clutter_layout_manager_set_container (priv->layout_manager, NULL);
4929 g_clear_object (&priv->layout_manager);
4932 if (priv->content != NULL)
4934 _clutter_content_detached (priv->content, self);
4935 g_clear_object (&priv->content);
4938 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4942 clutter_actor_finalize (GObject *object)
4944 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4946 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4947 priv->name != NULL ? priv->name : "<none>",
4949 g_type_name (G_OBJECT_TYPE (object)));
4951 _clutter_context_release_id (priv->id);
4953 g_free (priv->name);
4955 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4960 * clutter_actor_get_accessible:
4961 * @self: a #ClutterActor
4963 * Returns the accessible object that describes the actor to an
4964 * assistive technology.
4966 * If no class-specific #AtkObject implementation is available for the
4967 * actor instance in question, it will inherit an #AtkObject
4968 * implementation from the first ancestor class for which such an
4969 * implementation is defined.
4971 * The documentation of the <ulink
4972 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4973 * library contains more information about accessible objects and
4976 * Returns: (transfer none): the #AtkObject associated with @actor
4979 clutter_actor_get_accessible (ClutterActor *self)
4981 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4983 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4987 clutter_actor_real_get_accessible (ClutterActor *actor)
4989 return atk_gobject_accessible_for_object (G_OBJECT (actor));
4993 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4995 AtkObject *accessible;
4997 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4998 if (accessible != NULL)
4999 g_object_ref (accessible);
5005 atk_implementor_iface_init (AtkImplementorIface *iface)
5007 iface->ref_accessible = _clutter_actor_ref_accessible;
5011 clutter_actor_update_default_paint_volume (ClutterActor *self,
5012 ClutterPaintVolume *volume)
5014 ClutterActorPrivate *priv = self->priv;
5015 gboolean res = FALSE;
5017 /* we start from the allocation */
5018 clutter_paint_volume_set_width (volume,
5019 priv->allocation.x2 - priv->allocation.x1);
5020 clutter_paint_volume_set_height (volume,
5021 priv->allocation.y2 - priv->allocation.y1);
5023 /* if the actor has a clip set then we have a pretty definite
5024 * size for the paint volume: the actor cannot possibly paint
5025 * outside the clip region.
5027 if (priv->clip_to_allocation)
5029 /* the allocation has already been set, so we just flip the
5036 ClutterActor *child;
5038 if (priv->has_clip &&
5039 priv->clip.width >= 0 &&
5040 priv->clip.height >= 0)
5042 ClutterVertex origin;
5044 origin.x = priv->clip.x;
5045 origin.y = priv->clip.y;
5048 clutter_paint_volume_set_origin (volume, &origin);
5049 clutter_paint_volume_set_width (volume, priv->clip.width);
5050 clutter_paint_volume_set_height (volume, priv->clip.height);
5055 /* if we don't have children we just bail out here... */
5056 if (priv->n_children == 0)
5059 /* ...but if we have children then we ask for their paint volume in
5060 * our coordinates. if any of our children replies that it doesn't
5061 * have a paint volume, we bail out
5063 for (child = priv->first_child;
5065 child = child->priv->next_sibling)
5067 const ClutterPaintVolume *child_volume;
5069 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5070 if (child_volume == NULL)
5076 clutter_paint_volume_union (volume, child_volume);
5086 clutter_actor_real_get_paint_volume (ClutterActor *self,
5087 ClutterPaintVolume *volume)
5089 ClutterActorClass *klass;
5092 klass = CLUTTER_ACTOR_GET_CLASS (self);
5094 /* XXX - this thoroughly sucks, but we don't want to penalize users
5095 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5096 * redraw. This should go away in 2.0.
5098 if (klass->paint == clutter_actor_real_paint &&
5099 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5105 /* this is the default return value: we cannot know if a class
5106 * is going to paint outside its allocation, so we take the
5107 * conservative approach.
5112 if (clutter_actor_update_default_paint_volume (self, volume))
5119 * clutter_actor_get_default_paint_volume:
5120 * @self: a #ClutterActor
5122 * Retrieves the default paint volume for @self.
5124 * This function provides the same #ClutterPaintVolume that would be
5125 * computed by the default implementation inside #ClutterActor of the
5126 * #ClutterActorClass.get_paint_volume() virtual function.
5128 * This function should only be used by #ClutterActor subclasses that
5129 * cannot chain up to the parent implementation when computing their
5132 * Return value: (transfer none): a pointer to the default
5133 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5134 * the actor could not compute a valid paint volume. The returned value
5135 * is not guaranteed to be stable across multiple frames, so if you
5136 * want to retain it, you will need to copy it using
5137 * clutter_paint_volume_copy().
5141 const ClutterPaintVolume *
5142 clutter_actor_get_default_paint_volume (ClutterActor *self)
5144 ClutterPaintVolume volume;
5145 ClutterPaintVolume *res;
5147 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5150 _clutter_paint_volume_init_static (&volume, self);
5151 if (clutter_actor_update_default_paint_volume (self, &volume))
5153 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5157 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5158 _clutter_paint_volume_copy_static (&volume, res);
5162 clutter_paint_volume_free (&volume);
5168 clutter_actor_real_has_overlaps (ClutterActor *self)
5170 /* By default we'll assume that all actors need an offscreen redirect to get
5171 * the correct opacity. Actors such as ClutterTexture that would never need
5172 * an offscreen redirect can override this to return FALSE. */
5177 clutter_actor_real_destroy (ClutterActor *actor)
5179 ClutterActorIter iter;
5181 clutter_actor_iter_init (&iter, actor);
5182 while (clutter_actor_iter_next (&iter, NULL))
5183 clutter_actor_iter_destroy (&iter);
5187 clutter_actor_constructor (GType gtype,
5189 GObjectConstructParam *props)
5191 GObjectClass *gobject_class;
5195 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5196 retval = gobject_class->constructor (gtype, n_props, props);
5197 self = CLUTTER_ACTOR (retval);
5199 if (self->priv->layout_manager == NULL)
5201 ClutterLayoutManager *default_layout;
5203 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5205 default_layout = clutter_fixed_layout_new ();
5206 clutter_actor_set_layout_manager (self, default_layout);
5213 clutter_actor_class_init (ClutterActorClass *klass)
5215 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5217 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5218 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5219 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5220 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5222 object_class->constructor = clutter_actor_constructor;
5223 object_class->set_property = clutter_actor_set_property;
5224 object_class->get_property = clutter_actor_get_property;
5225 object_class->dispose = clutter_actor_dispose;
5226 object_class->finalize = clutter_actor_finalize;
5228 klass->show = clutter_actor_real_show;
5229 klass->show_all = clutter_actor_show;
5230 klass->hide = clutter_actor_real_hide;
5231 klass->hide_all = clutter_actor_hide;
5232 klass->map = clutter_actor_real_map;
5233 klass->unmap = clutter_actor_real_unmap;
5234 klass->unrealize = clutter_actor_real_unrealize;
5235 klass->pick = clutter_actor_real_pick;
5236 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5237 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5238 klass->allocate = clutter_actor_real_allocate;
5239 klass->queue_redraw = clutter_actor_real_queue_redraw;
5240 klass->queue_relayout = clutter_actor_real_queue_relayout;
5241 klass->apply_transform = clutter_actor_real_apply_transform;
5242 klass->get_accessible = clutter_actor_real_get_accessible;
5243 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5244 klass->has_overlaps = clutter_actor_real_has_overlaps;
5245 klass->paint = clutter_actor_real_paint;
5246 klass->destroy = clutter_actor_real_destroy;
5248 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5253 * X coordinate of the actor in pixels. If written, forces a fixed
5254 * position for the actor. If read, returns the fixed position if any,
5255 * otherwise the allocation if available, otherwise 0.
5257 * The #ClutterActor:x property is animatable.
5260 g_param_spec_float ("x",
5262 P_("X coordinate of the actor"),
5263 -G_MAXFLOAT, G_MAXFLOAT,
5266 G_PARAM_STATIC_STRINGS |
5267 CLUTTER_PARAM_ANIMATABLE);
5272 * Y coordinate of the actor in pixels. If written, forces a fixed
5273 * position for the actor. If read, returns the fixed position if
5274 * any, otherwise the allocation if available, otherwise 0.
5276 * The #ClutterActor:y property is animatable.
5279 g_param_spec_float ("y",
5281 P_("Y coordinate of the actor"),
5282 -G_MAXFLOAT, G_MAXFLOAT,
5285 G_PARAM_STATIC_STRINGS |
5286 CLUTTER_PARAM_ANIMATABLE);
5289 * ClutterActor:width:
5291 * Width of the actor (in pixels). If written, forces the minimum and
5292 * natural size request of the actor to the given width. If read, returns
5293 * the allocated width if available, otherwise the width request.
5295 * The #ClutterActor:width property is animatable.
5297 obj_props[PROP_WIDTH] =
5298 g_param_spec_float ("width",
5300 P_("Width of the actor"),
5304 G_PARAM_STATIC_STRINGS |
5305 CLUTTER_PARAM_ANIMATABLE);
5308 * ClutterActor:height:
5310 * Height of the actor (in pixels). If written, forces the minimum and
5311 * natural size request of the actor to the given height. If read, returns
5312 * the allocated height if available, otherwise the height request.
5314 * The #ClutterActor:height property is animatable.
5316 obj_props[PROP_HEIGHT] =
5317 g_param_spec_float ("height",
5319 P_("Height of the actor"),
5323 G_PARAM_STATIC_STRINGS |
5324 CLUTTER_PARAM_ANIMATABLE);
5327 * ClutterActor:fixed-x:
5329 * The fixed X position of the actor in pixels.
5331 * Writing this property sets #ClutterActor:fixed-position-set
5332 * property as well, as a side effect
5336 obj_props[PROP_FIXED_X] =
5337 g_param_spec_float ("fixed-x",
5339 P_("Forced X position of the actor"),
5340 -G_MAXFLOAT, G_MAXFLOAT,
5342 CLUTTER_PARAM_READWRITE);
5345 * ClutterActor:fixed-y:
5347 * The fixed Y position of the actor in pixels.
5349 * Writing this property sets the #ClutterActor:fixed-position-set
5350 * property as well, as a side effect
5354 obj_props[PROP_FIXED_Y] =
5355 g_param_spec_float ("fixed-y",
5357 P_("Forced Y position of the actor"),
5358 -G_MAXFLOAT, G_MAXFLOAT,
5360 CLUTTER_PARAM_READWRITE);
5363 * ClutterActor:fixed-position-set:
5365 * This flag controls whether the #ClutterActor:fixed-x and
5366 * #ClutterActor:fixed-y properties are used
5370 obj_props[PROP_FIXED_POSITION_SET] =
5371 g_param_spec_boolean ("fixed-position-set",
5372 P_("Fixed position set"),
5373 P_("Whether to use fixed positioning for the actor"),
5375 CLUTTER_PARAM_READWRITE);
5378 * ClutterActor:min-width:
5380 * A forced minimum width request for the actor, in pixels
5382 * Writing this property sets the #ClutterActor:min-width-set property
5383 * as well, as a side effect.
5385 *This property overrides the usual width request of the actor.
5389 obj_props[PROP_MIN_WIDTH] =
5390 g_param_spec_float ("min-width",
5392 P_("Forced minimum width request for the actor"),
5395 CLUTTER_PARAM_READWRITE);
5398 * ClutterActor:min-height:
5400 * A forced minimum height request for the actor, in pixels
5402 * Writing this property sets the #ClutterActor:min-height-set property
5403 * as well, as a side effect. This property overrides the usual height
5404 * request of the actor.
5408 obj_props[PROP_MIN_HEIGHT] =
5409 g_param_spec_float ("min-height",
5411 P_("Forced minimum height request for the actor"),
5414 CLUTTER_PARAM_READWRITE);
5417 * ClutterActor:natural-width:
5419 * A forced natural width request for the actor, in pixels
5421 * Writing this property sets the #ClutterActor:natural-width-set
5422 * property as well, as a side effect. This property overrides the
5423 * usual width request of the actor
5427 obj_props[PROP_NATURAL_WIDTH] =
5428 g_param_spec_float ("natural-width",
5429 P_("Natural Width"),
5430 P_("Forced natural width request for the actor"),
5433 CLUTTER_PARAM_READWRITE);
5436 * ClutterActor:natural-height:
5438 * A forced natural height request for the actor, in pixels
5440 * Writing this property sets the #ClutterActor:natural-height-set
5441 * property as well, as a side effect. This property overrides the
5442 * usual height request of the actor
5446 obj_props[PROP_NATURAL_HEIGHT] =
5447 g_param_spec_float ("natural-height",
5448 P_("Natural Height"),
5449 P_("Forced natural height request for the actor"),
5452 CLUTTER_PARAM_READWRITE);
5455 * ClutterActor:min-width-set:
5457 * This flag controls whether the #ClutterActor:min-width property
5462 obj_props[PROP_MIN_WIDTH_SET] =
5463 g_param_spec_boolean ("min-width-set",
5464 P_("Minimum width set"),
5465 P_("Whether to use the min-width property"),
5467 CLUTTER_PARAM_READWRITE);
5470 * ClutterActor:min-height-set:
5472 * This flag controls whether the #ClutterActor:min-height property
5477 obj_props[PROP_MIN_HEIGHT_SET] =
5478 g_param_spec_boolean ("min-height-set",
5479 P_("Minimum height set"),
5480 P_("Whether to use the min-height property"),
5482 CLUTTER_PARAM_READWRITE);
5485 * ClutterActor:natural-width-set:
5487 * This flag controls whether the #ClutterActor:natural-width property
5492 obj_props[PROP_NATURAL_WIDTH_SET] =
5493 g_param_spec_boolean ("natural-width-set",
5494 P_("Natural width set"),
5495 P_("Whether to use the natural-width property"),
5497 CLUTTER_PARAM_READWRITE);
5500 * ClutterActor:natural-height-set:
5502 * This flag controls whether the #ClutterActor:natural-height property
5507 obj_props[PROP_NATURAL_HEIGHT_SET] =
5508 g_param_spec_boolean ("natural-height-set",
5509 P_("Natural height set"),
5510 P_("Whether to use the natural-height property"),
5512 CLUTTER_PARAM_READWRITE);
5515 * ClutterActor:allocation:
5517 * The allocation for the actor, in pixels
5519 * This is property is read-only, but you might monitor it to know when an
5520 * actor moves or resizes
5524 obj_props[PROP_ALLOCATION] =
5525 g_param_spec_boxed ("allocation",
5527 P_("The actor's allocation"),
5528 CLUTTER_TYPE_ACTOR_BOX,
5529 CLUTTER_PARAM_READABLE);
5532 * ClutterActor:request-mode:
5534 * Request mode for the #ClutterActor. The request mode determines the
5535 * type of geometry management used by the actor, either height for width
5536 * (the default) or width for height.
5538 * For actors implementing height for width, the parent container should get
5539 * the preferred width first, and then the preferred height for that width.
5541 * For actors implementing width for height, the parent container should get
5542 * the preferred height first, and then the preferred width for that height.
5547 * ClutterRequestMode mode;
5548 * gfloat natural_width, min_width;
5549 * gfloat natural_height, min_height;
5551 * mode = clutter_actor_get_request_mode (child);
5552 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5554 * clutter_actor_get_preferred_width (child, -1,
5556 * &natural_width);
5557 * clutter_actor_get_preferred_height (child, natural_width,
5559 * &natural_height);
5563 * clutter_actor_get_preferred_height (child, -1,
5565 * &natural_height);
5566 * clutter_actor_get_preferred_width (child, natural_height,
5568 * &natural_width);
5572 * will retrieve the minimum and natural width and height depending on the
5573 * preferred request mode of the #ClutterActor "child".
5575 * The clutter_actor_get_preferred_size() function will implement this
5580 obj_props[PROP_REQUEST_MODE] =
5581 g_param_spec_enum ("request-mode",
5583 P_("The actor's request mode"),
5584 CLUTTER_TYPE_REQUEST_MODE,
5585 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5586 CLUTTER_PARAM_READWRITE);
5589 * ClutterActor:depth:
5591 * The position of the actor on the Z axis.
5593 * The #ClutterActor:depth property is relative to the parent's
5596 * The #ClutterActor:depth property is animatable.
5600 obj_props[PROP_DEPTH] =
5601 g_param_spec_float ("depth",
5603 P_("Position on the Z axis"),
5604 -G_MAXFLOAT, G_MAXFLOAT,
5607 G_PARAM_STATIC_STRINGS |
5608 CLUTTER_PARAM_ANIMATABLE);
5611 * ClutterActor:opacity:
5613 * Opacity of an actor, between 0 (fully transparent) and
5614 * 255 (fully opaque)
5616 * The #ClutterActor:opacity property is animatable.
5618 obj_props[PROP_OPACITY] =
5619 g_param_spec_uint ("opacity",
5621 P_("Opacity of an actor"),
5625 G_PARAM_STATIC_STRINGS |
5626 CLUTTER_PARAM_ANIMATABLE);
5629 * ClutterActor:offscreen-redirect:
5631 * Determines the conditions in which the actor will be redirected
5632 * to an offscreen framebuffer while being painted. For example this
5633 * can be used to cache an actor in a framebuffer or for improved
5634 * handling of transparent actors. See
5635 * clutter_actor_set_offscreen_redirect() for details.
5639 obj_props[PROP_OFFSCREEN_REDIRECT] =
5640 g_param_spec_flags ("offscreen-redirect",
5641 P_("Offscreen redirect"),
5642 P_("Flags controlling when to flatten the actor into a single image"),
5643 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5645 CLUTTER_PARAM_READWRITE);
5648 * ClutterActor:visible:
5650 * Whether the actor is set to be visible or not
5652 * See also #ClutterActor:mapped
5654 obj_props[PROP_VISIBLE] =
5655 g_param_spec_boolean ("visible",
5657 P_("Whether the actor is visible or not"),
5659 CLUTTER_PARAM_READWRITE);
5662 * ClutterActor:mapped:
5664 * Whether the actor is mapped (will be painted when the stage
5665 * to which it belongs is mapped)
5669 obj_props[PROP_MAPPED] =
5670 g_param_spec_boolean ("mapped",
5672 P_("Whether the actor will be painted"),
5674 CLUTTER_PARAM_READABLE);
5677 * ClutterActor:realized:
5679 * Whether the actor has been realized
5683 obj_props[PROP_REALIZED] =
5684 g_param_spec_boolean ("realized",
5686 P_("Whether the actor has been realized"),
5688 CLUTTER_PARAM_READABLE);
5691 * ClutterActor:reactive:
5693 * Whether the actor is reactive to events or not
5695 * Only reactive actors will emit event-related signals
5699 obj_props[PROP_REACTIVE] =
5700 g_param_spec_boolean ("reactive",
5702 P_("Whether the actor is reactive to events"),
5704 CLUTTER_PARAM_READWRITE);
5707 * ClutterActor:has-clip:
5709 * Whether the actor has the #ClutterActor:clip property set or not
5711 obj_props[PROP_HAS_CLIP] =
5712 g_param_spec_boolean ("has-clip",
5714 P_("Whether the actor has a clip set"),
5716 CLUTTER_PARAM_READABLE);
5719 * ClutterActor:clip:
5721 * The clip region for the actor, in actor-relative coordinates
5723 * Every part of the actor outside the clip region will not be
5726 obj_props[PROP_CLIP] =
5727 g_param_spec_boxed ("clip",
5729 P_("The clip region for the actor"),
5730 CLUTTER_TYPE_GEOMETRY,
5731 CLUTTER_PARAM_READWRITE);
5734 * ClutterActor:name:
5736 * The name of the actor
5740 obj_props[PROP_NAME] =
5741 g_param_spec_string ("name",
5743 P_("Name of the actor"),
5745 CLUTTER_PARAM_READWRITE);
5748 * ClutterActor:scale-x:
5750 * The horizontal scale of the actor.
5752 * The #ClutterActor:scale-x property is animatable.
5756 obj_props[PROP_SCALE_X] =
5757 g_param_spec_double ("scale-x",
5759 P_("Scale factor on the X axis"),
5763 G_PARAM_STATIC_STRINGS |
5764 CLUTTER_PARAM_ANIMATABLE);
5767 * ClutterActor:scale-y:
5769 * The vertical scale of the actor.
5771 * The #ClutterActor:scale-y property is animatable.
5775 obj_props[PROP_SCALE_Y] =
5776 g_param_spec_double ("scale-y",
5778 P_("Scale factor on the Y axis"),
5782 G_PARAM_STATIC_STRINGS |
5783 CLUTTER_PARAM_ANIMATABLE);
5786 * ClutterActor:scale-center-x:
5788 * The horizontal center point for scaling
5792 obj_props[PROP_SCALE_CENTER_X] =
5793 g_param_spec_float ("scale-center-x",
5794 P_("Scale Center X"),
5795 P_("Horizontal scale center"),
5796 -G_MAXFLOAT, G_MAXFLOAT,
5798 CLUTTER_PARAM_READWRITE);
5801 * ClutterActor:scale-center-y:
5803 * The vertical center point for scaling
5807 obj_props[PROP_SCALE_CENTER_Y] =
5808 g_param_spec_float ("scale-center-y",
5809 P_("Scale Center Y"),
5810 P_("Vertical scale center"),
5811 -G_MAXFLOAT, G_MAXFLOAT,
5813 CLUTTER_PARAM_READWRITE);
5816 * ClutterActor:scale-gravity:
5818 * The center point for scaling expressed as a #ClutterGravity
5822 obj_props[PROP_SCALE_GRAVITY] =
5823 g_param_spec_enum ("scale-gravity",
5824 P_("Scale Gravity"),
5825 P_("The center of scaling"),
5826 CLUTTER_TYPE_GRAVITY,
5827 CLUTTER_GRAVITY_NONE,
5828 CLUTTER_PARAM_READWRITE);
5831 * ClutterActor:rotation-angle-x:
5833 * The rotation angle on the X axis.
5835 * The #ClutterActor:rotation-angle-x property is animatable.
5839 obj_props[PROP_ROTATION_ANGLE_X] =
5840 g_param_spec_double ("rotation-angle-x",
5841 P_("Rotation Angle X"),
5842 P_("The rotation angle on the X axis"),
5843 -G_MAXDOUBLE, G_MAXDOUBLE,
5846 G_PARAM_STATIC_STRINGS |
5847 CLUTTER_PARAM_ANIMATABLE);
5850 * ClutterActor:rotation-angle-y:
5852 * The rotation angle on the Y axis
5854 * The #ClutterActor:rotation-angle-y property is animatable.
5858 obj_props[PROP_ROTATION_ANGLE_Y] =
5859 g_param_spec_double ("rotation-angle-y",
5860 P_("Rotation Angle Y"),
5861 P_("The rotation angle on the Y axis"),
5862 -G_MAXDOUBLE, G_MAXDOUBLE,
5865 G_PARAM_STATIC_STRINGS |
5866 CLUTTER_PARAM_ANIMATABLE);
5869 * ClutterActor:rotation-angle-z:
5871 * The rotation angle on the Z axis
5873 * The #ClutterActor:rotation-angle-z property is animatable.
5877 obj_props[PROP_ROTATION_ANGLE_Z] =
5878 g_param_spec_double ("rotation-angle-z",
5879 P_("Rotation Angle Z"),
5880 P_("The rotation angle on the Z axis"),
5881 -G_MAXDOUBLE, G_MAXDOUBLE,
5884 G_PARAM_STATIC_STRINGS |
5885 CLUTTER_PARAM_ANIMATABLE);
5888 * ClutterActor:rotation-center-x:
5890 * The rotation center on the X axis.
5894 obj_props[PROP_ROTATION_CENTER_X] =
5895 g_param_spec_boxed ("rotation-center-x",
5896 P_("Rotation Center X"),
5897 P_("The rotation center on the X axis"),
5898 CLUTTER_TYPE_VERTEX,
5899 CLUTTER_PARAM_READWRITE);
5902 * ClutterActor:rotation-center-y:
5904 * The rotation center on the Y axis.
5908 obj_props[PROP_ROTATION_CENTER_Y] =
5909 g_param_spec_boxed ("rotation-center-y",
5910 P_("Rotation Center Y"),
5911 P_("The rotation center on the Y axis"),
5912 CLUTTER_TYPE_VERTEX,
5913 CLUTTER_PARAM_READWRITE);
5916 * ClutterActor:rotation-center-z:
5918 * The rotation center on the Z axis.
5922 obj_props[PROP_ROTATION_CENTER_Z] =
5923 g_param_spec_boxed ("rotation-center-z",
5924 P_("Rotation Center Z"),
5925 P_("The rotation center on the Z axis"),
5926 CLUTTER_TYPE_VERTEX,
5927 CLUTTER_PARAM_READWRITE);
5930 * ClutterActor:rotation-center-z-gravity:
5932 * The rotation center on the Z axis expressed as a #ClutterGravity.
5936 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5937 g_param_spec_enum ("rotation-center-z-gravity",
5938 P_("Rotation Center Z Gravity"),
5939 P_("Center point for rotation around the Z axis"),
5940 CLUTTER_TYPE_GRAVITY,
5941 CLUTTER_GRAVITY_NONE,
5942 CLUTTER_PARAM_READWRITE);
5945 * ClutterActor:anchor-x:
5947 * The X coordinate of an actor's anchor point, relative to
5948 * the actor coordinate space, in pixels
5952 obj_props[PROP_ANCHOR_X] =
5953 g_param_spec_float ("anchor-x",
5955 P_("X coordinate of the anchor point"),
5956 -G_MAXFLOAT, G_MAXFLOAT,
5958 CLUTTER_PARAM_READWRITE);
5961 * ClutterActor:anchor-y:
5963 * The Y coordinate of an actor's anchor point, relative to
5964 * the actor coordinate space, in pixels
5968 obj_props[PROP_ANCHOR_Y] =
5969 g_param_spec_float ("anchor-y",
5971 P_("Y coordinate of the anchor point"),
5972 -G_MAXFLOAT, G_MAXFLOAT,
5974 CLUTTER_PARAM_READWRITE);
5977 * ClutterActor:anchor-gravity:
5979 * The anchor point expressed as a #ClutterGravity
5983 obj_props[PROP_ANCHOR_GRAVITY] =
5984 g_param_spec_enum ("anchor-gravity",
5985 P_("Anchor Gravity"),
5986 P_("The anchor point as a ClutterGravity"),
5987 CLUTTER_TYPE_GRAVITY,
5988 CLUTTER_GRAVITY_NONE,
5989 CLUTTER_PARAM_READWRITE);
5992 * ClutterActor:show-on-set-parent:
5994 * If %TRUE, the actor is automatically shown when parented.
5996 * Calling clutter_actor_hide() on an actor which has not been
5997 * parented will set this property to %FALSE as a side effect.
6001 obj_props[PROP_SHOW_ON_SET_PARENT] =
6002 g_param_spec_boolean ("show-on-set-parent",
6003 P_("Show on set parent"),
6004 P_("Whether the actor is shown when parented"),
6006 CLUTTER_PARAM_READWRITE);
6009 * ClutterActor:clip-to-allocation:
6011 * Whether the clip region should track the allocated area
6014 * This property is ignored if a clip area has been explicitly
6015 * set using clutter_actor_set_clip().
6019 obj_props[PROP_CLIP_TO_ALLOCATION] =
6020 g_param_spec_boolean ("clip-to-allocation",
6021 P_("Clip to Allocation"),
6022 P_("Sets the clip region to track the actor's allocation"),
6024 CLUTTER_PARAM_READWRITE);
6027 * ClutterActor:text-direction:
6029 * The direction of the text inside a #ClutterActor.
6033 obj_props[PROP_TEXT_DIRECTION] =
6034 g_param_spec_enum ("text-direction",
6035 P_("Text Direction"),
6036 P_("Direction of the text"),
6037 CLUTTER_TYPE_TEXT_DIRECTION,
6038 CLUTTER_TEXT_DIRECTION_LTR,
6039 CLUTTER_PARAM_READWRITE);
6042 * ClutterActor:has-pointer:
6044 * Whether the actor contains the pointer of a #ClutterInputDevice
6049 obj_props[PROP_HAS_POINTER] =
6050 g_param_spec_boolean ("has-pointer",
6052 P_("Whether the actor contains the pointer of an input device"),
6054 CLUTTER_PARAM_READABLE);
6057 * ClutterActor:actions:
6059 * Adds a #ClutterAction to the actor
6063 obj_props[PROP_ACTIONS] =
6064 g_param_spec_object ("actions",
6066 P_("Adds an action to the actor"),
6067 CLUTTER_TYPE_ACTION,
6068 CLUTTER_PARAM_WRITABLE);
6071 * ClutterActor:constraints:
6073 * Adds a #ClutterConstraint to the actor
6077 obj_props[PROP_CONSTRAINTS] =
6078 g_param_spec_object ("constraints",
6080 P_("Adds a constraint to the actor"),
6081 CLUTTER_TYPE_CONSTRAINT,
6082 CLUTTER_PARAM_WRITABLE);
6085 * ClutterActor:effect:
6087 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6091 obj_props[PROP_EFFECT] =
6092 g_param_spec_object ("effect",
6094 P_("Add an effect to be applied on the actor"),
6095 CLUTTER_TYPE_EFFECT,
6096 CLUTTER_PARAM_WRITABLE);
6099 * ClutterActor:layout-manager:
6101 * A delegate object for controlling the layout of the children of
6106 obj_props[PROP_LAYOUT_MANAGER] =
6107 g_param_spec_object ("layout-manager",
6108 P_("Layout Manager"),
6109 P_("The object controlling the layout of an actor's children"),
6110 CLUTTER_TYPE_LAYOUT_MANAGER,
6111 CLUTTER_PARAM_READWRITE);
6115 * ClutterActor:x-align:
6117 * The alignment of an actor on the X axis, if the actor has been given
6118 * extra space for its allocation.
6122 obj_props[PROP_X_ALIGN] =
6123 g_param_spec_enum ("x-align",
6125 P_("The alignment of the actor on the X axis within its allocation"),
6126 CLUTTER_TYPE_ACTOR_ALIGN,
6127 CLUTTER_ACTOR_ALIGN_FILL,
6128 CLUTTER_PARAM_READWRITE);
6131 * ClutterActor:y-align:
6133 * The alignment of an actor on the Y axis, if the actor has been given
6134 * extra space for its allocation.
6138 obj_props[PROP_Y_ALIGN] =
6139 g_param_spec_enum ("y-align",
6141 P_("The alignment of the actor on the Y axis within its allocation"),
6142 CLUTTER_TYPE_ACTOR_ALIGN,
6143 CLUTTER_ACTOR_ALIGN_FILL,
6144 CLUTTER_PARAM_READWRITE);
6147 * ClutterActor:margin-top:
6149 * The margin (in pixels) from the top of the actor.
6151 * This property adds a margin to the actor's preferred size; the margin
6152 * will be automatically taken into account when allocating the actor.
6156 obj_props[PROP_MARGIN_TOP] =
6157 g_param_spec_float ("margin-top",
6159 P_("Extra space at the top"),
6162 CLUTTER_PARAM_READWRITE);
6165 * ClutterActor:margin-bottom:
6167 * The margin (in pixels) from the bottom of the actor.
6169 * This property adds a margin to the actor's preferred size; the margin
6170 * will be automatically taken into account when allocating the actor.
6174 obj_props[PROP_MARGIN_BOTTOM] =
6175 g_param_spec_float ("margin-bottom",
6176 P_("Margin Bottom"),
6177 P_("Extra space at the bottom"),
6180 CLUTTER_PARAM_READWRITE);
6183 * ClutterActor:margin-left:
6185 * The margin (in pixels) from the left of the actor.
6187 * This property adds a margin to the actor's preferred size; the margin
6188 * will be automatically taken into account when allocating the actor.
6192 obj_props[PROP_MARGIN_LEFT] =
6193 g_param_spec_float ("margin-left",
6195 P_("Extra space at the left"),
6198 CLUTTER_PARAM_READWRITE);
6201 * ClutterActor:margin-right:
6203 * The margin (in pixels) from the right of the actor.
6205 * This property adds a margin to the actor's preferred size; the margin
6206 * will be automatically taken into account when allocating the actor.
6210 obj_props[PROP_MARGIN_RIGHT] =
6211 g_param_spec_float ("margin-right",
6213 P_("Extra space at the right"),
6216 CLUTTER_PARAM_READWRITE);
6219 * ClutterActor:background-color-set:
6221 * Whether the #ClutterActor:background-color property has been set.
6225 obj_props[PROP_BACKGROUND_COLOR_SET] =
6226 g_param_spec_boolean ("background-color-set",
6227 P_("Background Color Set"),
6228 P_("Whether the background color is set"),
6230 CLUTTER_PARAM_READABLE);
6233 * ClutterActor:background-color:
6235 * Paints a solid fill of the actor's allocation using the specified
6238 * The #ClutterActor:background-color property is animatable.
6242 obj_props[PROP_BACKGROUND_COLOR] =
6243 clutter_param_spec_color ("background-color",
6244 P_("Background color"),
6245 P_("The actor's background color"),
6246 CLUTTER_COLOR_Transparent,
6248 G_PARAM_STATIC_STRINGS |
6249 CLUTTER_PARAM_ANIMATABLE);
6252 * ClutterActor:first-child:
6254 * The actor's first child.
6258 obj_props[PROP_FIRST_CHILD] =
6259 g_param_spec_object ("first-child",
6261 P_("The actor's first child"),
6263 CLUTTER_PARAM_READABLE);
6266 * ClutterActor:last-child:
6268 * The actor's last child.
6272 obj_props[PROP_LAST_CHILD] =
6273 g_param_spec_object ("last-child",
6275 P_("The actor's last child"),
6277 CLUTTER_PARAM_READABLE);
6280 * ClutterActor:content:
6282 * The #ClutterContent implementation that controls the content
6287 obj_props[PROP_CONTENT] =
6288 g_param_spec_object ("content",
6290 P_("Delegate object for painting the actor's content"),
6291 CLUTTER_TYPE_CONTENT,
6292 CLUTTER_PARAM_READWRITE);
6295 * ClutterActor:content-gravity:
6297 * The alignment that should be honoured by the #ClutterContent
6298 * set with the #ClutterActor:content property.
6300 * Changing the value of this property will change the bounding box of
6301 * the content; you can use the #ClutterActor:content-box property to
6302 * get the position and size of the content within the actor's
6305 * This property is meaningful only for #ClutterContent implementations
6306 * that have a preferred size, and if the preferred size is smaller than
6307 * the actor's allocation.
6311 obj_props[PROP_CONTENT_GRAVITY] =
6312 g_param_spec_enum ("content-gravity",
6313 P_("Content Gravity"),
6314 P_("Alignment of the actor's content"),
6315 CLUTTER_TYPE_CONTENT_GRAVITY,
6316 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6317 CLUTTER_PARAM_READWRITE);
6320 * ClutterActor:content-box:
6322 * The bounding box for the #ClutterContent used by the actor.
6324 * The value of this property is controlled by the #ClutterActor:allocation
6325 * and #ClutterActor:content-gravity properties of #ClutterActor.
6327 * The bounding box for the content is guaranteed to never exceed the
6328 * allocation's of the actor.
6332 obj_props[PROP_CONTENT_BOX] =
6333 g_param_spec_boxed ("content-box",
6335 P_("The bounding box of the actor's content"),
6336 CLUTTER_TYPE_ACTOR_BOX,
6337 CLUTTER_PARAM_READABLE);
6339 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6342 * ClutterActor::destroy:
6343 * @actor: the #ClutterActor which emitted the signal
6345 * The ::destroy signal notifies that all references held on the
6346 * actor which emitted it should be released.
6348 * The ::destroy signal should be used by all holders of a reference
6351 * This signal might result in the finalization of the #ClutterActor
6352 * if all references are released.
6354 * Composite actors and actors implementing the #ClutterContainer
6355 * interface should override the default implementation of the
6356 * class handler of this signal and call clutter_actor_destroy() on
6357 * their children. When overriding the default class handler, it is
6358 * required to chain up to the parent's implementation.
6362 actor_signals[DESTROY] =
6363 g_signal_new (I_("destroy"),
6364 G_TYPE_FROM_CLASS (object_class),
6365 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6366 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6368 _clutter_marshal_VOID__VOID,
6371 * ClutterActor::show:
6372 * @actor: the object which received the signal
6374 * The ::show signal is emitted when an actor is visible and
6375 * rendered on the stage.
6379 actor_signals[SHOW] =
6380 g_signal_new (I_("show"),
6381 G_TYPE_FROM_CLASS (object_class),
6383 G_STRUCT_OFFSET (ClutterActorClass, show),
6385 _clutter_marshal_VOID__VOID,
6388 * ClutterActor::hide:
6389 * @actor: the object which received the signal
6391 * The ::hide signal is emitted when an actor is no longer rendered
6396 actor_signals[HIDE] =
6397 g_signal_new (I_("hide"),
6398 G_TYPE_FROM_CLASS (object_class),
6400 G_STRUCT_OFFSET (ClutterActorClass, hide),
6402 _clutter_marshal_VOID__VOID,
6405 * ClutterActor::parent-set:
6406 * @actor: the object which received the signal
6407 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6409 * This signal is emitted when the parent of the actor changes.
6413 actor_signals[PARENT_SET] =
6414 g_signal_new (I_("parent-set"),
6415 G_TYPE_FROM_CLASS (object_class),
6417 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6419 _clutter_marshal_VOID__OBJECT,
6421 CLUTTER_TYPE_ACTOR);
6424 * ClutterActor::queue-redraw:
6425 * @actor: the actor we're bubbling the redraw request through
6426 * @origin: the actor which initiated the redraw request
6428 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6429 * is called on @origin.
6431 * The default implementation for #ClutterActor chains up to the
6432 * parent actor and queues a redraw on the parent, thus "bubbling"
6433 * the redraw queue up through the actor graph. The default
6434 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6435 * in a main loop idle handler.
6437 * Note that the @origin actor may be the stage, or a container; it
6438 * does not have to be a leaf node in the actor graph.
6440 * Toolkits embedding a #ClutterStage which require a redraw and
6441 * relayout cycle can stop the emission of this signal using the
6442 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6447 * on_redraw_complete (gpointer data)
6449 * ClutterStage *stage = data;
6451 * /* execute the Clutter drawing pipeline */
6452 * clutter_stage_ensure_redraw (stage);
6456 * on_stage_queue_redraw (ClutterStage *stage)
6458 * /* this prevents the default handler to run */
6459 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6461 * /* queue a redraw with the host toolkit and call
6462 * * a function when the redraw has been completed
6464 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6468 * <note><para>This signal is emitted before the Clutter paint
6469 * pipeline is executed. If you want to know when the pipeline has
6470 * been completed you should connect to the ::paint signal on the
6471 * Stage with g_signal_connect_after().</para></note>
6475 actor_signals[QUEUE_REDRAW] =
6476 g_signal_new (I_("queue-redraw"),
6477 G_TYPE_FROM_CLASS (object_class),
6480 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6482 _clutter_marshal_VOID__OBJECT,
6484 CLUTTER_TYPE_ACTOR);
6487 * ClutterActor::queue-relayout
6488 * @actor: the actor being queued for relayout
6490 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6491 * is called on an actor.
6493 * The default implementation for #ClutterActor chains up to the
6494 * parent actor and queues a relayout on the parent, thus "bubbling"
6495 * the relayout queue up through the actor graph.
6497 * The main purpose of this signal is to allow relayout to be propagated
6498 * properly in the procense of #ClutterClone actors. Applications will
6499 * not normally need to connect to this signal.
6503 actor_signals[QUEUE_RELAYOUT] =
6504 g_signal_new (I_("queue-relayout"),
6505 G_TYPE_FROM_CLASS (object_class),
6508 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6510 _clutter_marshal_VOID__VOID,
6514 * ClutterActor::event:
6515 * @actor: the actor which received the event
6516 * @event: a #ClutterEvent
6518 * The ::event signal is emitted each time an event is received
6519 * by the @actor. This signal will be emitted on every actor,
6520 * following the hierarchy chain, until it reaches the top-level
6521 * container (the #ClutterStage).
6523 * Return value: %TRUE if the event has been handled by the actor,
6524 * or %FALSE to continue the emission.
6528 actor_signals[EVENT] =
6529 g_signal_new (I_("event"),
6530 G_TYPE_FROM_CLASS (object_class),
6532 G_STRUCT_OFFSET (ClutterActorClass, event),
6533 _clutter_boolean_handled_accumulator, NULL,
6534 _clutter_marshal_BOOLEAN__BOXED,
6536 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6538 * ClutterActor::button-press-event:
6539 * @actor: the actor which received the event
6540 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6542 * The ::button-press-event signal is emitted each time a mouse button
6543 * is pressed on @actor.
6545 * Return value: %TRUE if the event has been handled by the actor,
6546 * or %FALSE to continue the emission.
6550 actor_signals[BUTTON_PRESS_EVENT] =
6551 g_signal_new (I_("button-press-event"),
6552 G_TYPE_FROM_CLASS (object_class),
6554 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6555 _clutter_boolean_handled_accumulator, NULL,
6556 _clutter_marshal_BOOLEAN__BOXED,
6558 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6560 * ClutterActor::button-release-event:
6561 * @actor: the actor which received the event
6562 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6564 * The ::button-release-event signal is emitted each time a mouse button
6565 * is released on @actor.
6567 * Return value: %TRUE if the event has been handled by the actor,
6568 * or %FALSE to continue the emission.
6572 actor_signals[BUTTON_RELEASE_EVENT] =
6573 g_signal_new (I_("button-release-event"),
6574 G_TYPE_FROM_CLASS (object_class),
6576 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6577 _clutter_boolean_handled_accumulator, NULL,
6578 _clutter_marshal_BOOLEAN__BOXED,
6580 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6582 * ClutterActor::scroll-event:
6583 * @actor: the actor which received the event
6584 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6586 * The ::scroll-event signal is emitted each time the mouse is
6587 * scrolled on @actor
6589 * Return value: %TRUE if the event has been handled by the actor,
6590 * or %FALSE to continue the emission.
6594 actor_signals[SCROLL_EVENT] =
6595 g_signal_new (I_("scroll-event"),
6596 G_TYPE_FROM_CLASS (object_class),
6598 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6599 _clutter_boolean_handled_accumulator, NULL,
6600 _clutter_marshal_BOOLEAN__BOXED,
6602 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6604 * ClutterActor::key-press-event:
6605 * @actor: the actor which received the event
6606 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6608 * The ::key-press-event signal is emitted each time a keyboard button
6609 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6611 * Return value: %TRUE if the event has been handled by the actor,
6612 * or %FALSE to continue the emission.
6616 actor_signals[KEY_PRESS_EVENT] =
6617 g_signal_new (I_("key-press-event"),
6618 G_TYPE_FROM_CLASS (object_class),
6620 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6621 _clutter_boolean_handled_accumulator, NULL,
6622 _clutter_marshal_BOOLEAN__BOXED,
6624 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6626 * ClutterActor::key-release-event:
6627 * @actor: the actor which received the event
6628 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6630 * The ::key-release-event signal is emitted each time a keyboard button
6631 * is released while @actor has key focus (see
6632 * clutter_stage_set_key_focus()).
6634 * Return value: %TRUE if the event has been handled by the actor,
6635 * or %FALSE to continue the emission.
6639 actor_signals[KEY_RELEASE_EVENT] =
6640 g_signal_new (I_("key-release-event"),
6641 G_TYPE_FROM_CLASS (object_class),
6643 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6644 _clutter_boolean_handled_accumulator, NULL,
6645 _clutter_marshal_BOOLEAN__BOXED,
6647 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6649 * ClutterActor::motion-event:
6650 * @actor: the actor which received the event
6651 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6653 * The ::motion-event signal is emitted each time the mouse pointer is
6654 * moved over @actor.
6656 * Return value: %TRUE if the event has been handled by the actor,
6657 * or %FALSE to continue the emission.
6661 actor_signals[MOTION_EVENT] =
6662 g_signal_new (I_("motion-event"),
6663 G_TYPE_FROM_CLASS (object_class),
6665 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6666 _clutter_boolean_handled_accumulator, NULL,
6667 _clutter_marshal_BOOLEAN__BOXED,
6669 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6672 * ClutterActor::key-focus-in:
6673 * @actor: the actor which now has key focus
6675 * The ::key-focus-in signal is emitted when @actor receives key focus.
6679 actor_signals[KEY_FOCUS_IN] =
6680 g_signal_new (I_("key-focus-in"),
6681 G_TYPE_FROM_CLASS (object_class),
6683 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6685 _clutter_marshal_VOID__VOID,
6689 * ClutterActor::key-focus-out:
6690 * @actor: the actor which now has key focus
6692 * The ::key-focus-out signal is emitted when @actor loses key focus.
6696 actor_signals[KEY_FOCUS_OUT] =
6697 g_signal_new (I_("key-focus-out"),
6698 G_TYPE_FROM_CLASS (object_class),
6700 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6702 _clutter_marshal_VOID__VOID,
6706 * ClutterActor::enter-event:
6707 * @actor: the actor which the pointer has entered.
6708 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6710 * The ::enter-event signal is emitted when the pointer enters the @actor
6712 * Return value: %TRUE if the event has been handled by the actor,
6713 * or %FALSE to continue the emission.
6717 actor_signals[ENTER_EVENT] =
6718 g_signal_new (I_("enter-event"),
6719 G_TYPE_FROM_CLASS (object_class),
6721 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6722 _clutter_boolean_handled_accumulator, NULL,
6723 _clutter_marshal_BOOLEAN__BOXED,
6725 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6728 * ClutterActor::leave-event:
6729 * @actor: the actor which the pointer has left
6730 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6732 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6734 * Return value: %TRUE if the event has been handled by the actor,
6735 * or %FALSE to continue the emission.
6739 actor_signals[LEAVE_EVENT] =
6740 g_signal_new (I_("leave-event"),
6741 G_TYPE_FROM_CLASS (object_class),
6743 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6744 _clutter_boolean_handled_accumulator, NULL,
6745 _clutter_marshal_BOOLEAN__BOXED,
6747 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6750 * ClutterActor::captured-event:
6751 * @actor: the actor which received the signal
6752 * @event: a #ClutterEvent
6754 * The ::captured-event signal is emitted when an event is captured
6755 * by Clutter. This signal will be emitted starting from the top-level
6756 * container (the #ClutterStage) to the actor which received the event
6757 * going down the hierarchy. This signal can be used to intercept every
6758 * event before the specialized events (like
6759 * ClutterActor::button-press-event or ::key-released-event) are
6762 * Return value: %TRUE if the event has been handled by the actor,
6763 * or %FALSE to continue the emission.
6767 actor_signals[CAPTURED_EVENT] =
6768 g_signal_new (I_("captured-event"),
6769 G_TYPE_FROM_CLASS (object_class),
6771 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6772 _clutter_boolean_handled_accumulator, NULL,
6773 _clutter_marshal_BOOLEAN__BOXED,
6775 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6778 * ClutterActor::paint:
6779 * @actor: the #ClutterActor that received the signal
6781 * The ::paint signal is emitted each time an actor is being painted.
6783 * Subclasses of #ClutterActor should override the class signal handler
6784 * and paint themselves in that function.
6786 * It is possible to connect a handler to the ::paint signal in order
6787 * to set up some custom aspect of a paint.
6791 actor_signals[PAINT] =
6792 g_signal_new (I_("paint"),
6793 G_TYPE_FROM_CLASS (object_class),
6796 G_STRUCT_OFFSET (ClutterActorClass, paint),
6798 _clutter_marshal_VOID__VOID,
6801 * ClutterActor::realize:
6802 * @actor: the #ClutterActor that received the signal
6804 * The ::realize signal is emitted each time an actor is being
6809 actor_signals[REALIZE] =
6810 g_signal_new (I_("realize"),
6811 G_TYPE_FROM_CLASS (object_class),
6813 G_STRUCT_OFFSET (ClutterActorClass, realize),
6815 _clutter_marshal_VOID__VOID,
6818 * ClutterActor::unrealize:
6819 * @actor: the #ClutterActor that received the signal
6821 * The ::unrealize signal is emitted each time an actor is being
6826 actor_signals[UNREALIZE] =
6827 g_signal_new (I_("unrealize"),
6828 G_TYPE_FROM_CLASS (object_class),
6830 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6832 _clutter_marshal_VOID__VOID,
6836 * ClutterActor::pick:
6837 * @actor: the #ClutterActor that received the signal
6838 * @color: the #ClutterColor to be used when picking
6840 * The ::pick signal is emitted each time an actor is being painted
6841 * in "pick mode". The pick mode is used to identify the actor during
6842 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6843 * The actor should paint its shape using the passed @pick_color.
6845 * Subclasses of #ClutterActor should override the class signal handler
6846 * and paint themselves in that function.
6848 * It is possible to connect a handler to the ::pick signal in order
6849 * to set up some custom aspect of a paint in pick mode.
6853 actor_signals[PICK] =
6854 g_signal_new (I_("pick"),
6855 G_TYPE_FROM_CLASS (object_class),
6857 G_STRUCT_OFFSET (ClutterActorClass, pick),
6859 _clutter_marshal_VOID__BOXED,
6861 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6864 * ClutterActor::allocation-changed:
6865 * @actor: the #ClutterActor that emitted the signal
6866 * @box: a #ClutterActorBox with the new allocation
6867 * @flags: #ClutterAllocationFlags for the allocation
6869 * The ::allocation-changed signal is emitted when the
6870 * #ClutterActor:allocation property changes. Usually, application
6871 * code should just use the notifications for the :allocation property
6872 * but if you want to track the allocation flags as well, for instance
6873 * to know whether the absolute origin of @actor changed, then you might
6874 * want use this signal instead.
6878 actor_signals[ALLOCATION_CHANGED] =
6879 g_signal_new (I_("allocation-changed"),
6880 G_TYPE_FROM_CLASS (object_class),
6884 _clutter_marshal_VOID__BOXED_FLAGS,
6886 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6887 CLUTTER_TYPE_ALLOCATION_FLAGS);
6891 clutter_actor_init (ClutterActor *self)
6893 ClutterActorPrivate *priv;
6895 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6897 priv->id = _clutter_context_acquire_id (self);
6900 priv->opacity = 0xff;
6901 priv->show_on_set_parent = TRUE;
6903 priv->needs_width_request = TRUE;
6904 priv->needs_height_request = TRUE;
6905 priv->needs_allocation = TRUE;
6907 priv->cached_width_age = 1;
6908 priv->cached_height_age = 1;
6910 priv->opacity_override = -1;
6911 priv->enable_model_view_transform = TRUE;
6913 /* Initialize an empty paint volume to start with */
6914 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6915 priv->last_paint_volume_valid = TRUE;
6917 priv->transform_valid = FALSE;
6919 /* the default is to stretch the content, to match the
6920 * current behaviour of basically all actors. also, it's
6921 * the easiest thing to compute.
6923 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6927 * clutter_actor_new:
6929 * Creates a new #ClutterActor.
6931 * A newly created actor has a floating reference, which will be sunk
6932 * when it is added to another actor.
6934 * Return value: (transfer full): the newly created #ClutterActor
6939 clutter_actor_new (void)
6941 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6945 * clutter_actor_destroy:
6946 * @self: a #ClutterActor
6948 * Destroys an actor. When an actor is destroyed, it will break any
6949 * references it holds to other objects. If the actor is inside a
6950 * container, the actor will be removed.
6952 * When you destroy a container, its children will be destroyed as well.
6954 * Note: you cannot destroy the #ClutterStage returned by
6955 * clutter_stage_get_default().
6958 clutter_actor_destroy (ClutterActor *self)
6960 g_return_if_fail (CLUTTER_IS_ACTOR (self));
6962 g_object_ref (self);
6964 /* avoid recursion while destroying */
6965 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6967 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6969 g_object_run_dispose (G_OBJECT (self));
6971 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6974 g_object_unref (self);
6978 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6979 ClutterPaintVolume *clip)
6981 ClutterActorPrivate *priv = self->priv;
6982 ClutterPaintVolume *pv;
6985 /* Remove queue entry early in the process, otherwise a new
6986 queue_redraw() during signal handling could put back this
6987 object in the stage redraw list (but the entry is freed as
6988 soon as we return from this function, causing a segfault
6991 priv->queue_redraw_entry = NULL;
6993 /* If we've been explicitly passed a clip volume then there's
6994 * nothing more to calculate, but otherwise the only thing we know
6995 * is that the change is constrained to the given actor.
6997 * The idea is that if we know the paint volume for where the actor
6998 * was last drawn (in eye coordinates) and we also have the paint
6999 * volume for where it will be drawn next (in actor coordinates)
7000 * then if we queue a redraw for both these volumes that will cover
7001 * everything that needs to be redrawn to clear the old view and
7002 * show the latest view of the actor.
7004 * Don't clip this redraw if we don't know what position we had for
7005 * the previous redraw since we don't know where to set the clip so
7006 * it will clear the actor as it is currently.
7010 _clutter_actor_set_queue_redraw_clip (self, clip);
7013 else if (G_LIKELY (priv->last_paint_volume_valid))
7015 pv = _clutter_actor_get_paint_volume_mutable (self);
7018 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7020 /* make sure we redraw the actors old position... */
7021 _clutter_actor_set_queue_redraw_clip (stage,
7022 &priv->last_paint_volume);
7023 _clutter_actor_signal_queue_redraw (stage, stage);
7024 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7026 /* XXX: Ideally the redraw signal would take a clip volume
7027 * argument, but that would be an ABI break. Until we can
7028 * break the ABI we pass the argument out-of-band
7031 /* setup the clip for the actors new position... */
7032 _clutter_actor_set_queue_redraw_clip (self, pv);
7041 _clutter_actor_signal_queue_redraw (self, self);
7043 /* Just in case anyone is manually firing redraw signals without
7044 * using the public queue_redraw() API we are careful to ensure that
7045 * our out-of-band clip member is cleared before returning...
7047 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7049 if (G_LIKELY (clipped))
7050 _clutter_actor_set_queue_redraw_clip (self, NULL);
7054 _clutter_actor_get_allocation_clip (ClutterActor *self,
7055 ClutterActorBox *clip)
7057 ClutterActorBox allocation;
7059 /* XXX: we don't care if we get an out of date allocation here
7060 * because clutter_actor_queue_redraw_with_clip knows to ignore
7061 * the clip if the actor's allocation is invalid.
7063 * This is noted because clutter_actor_get_allocation_box does some
7064 * unnecessary work to support buggy code with a comment suggesting
7065 * that it could be changed later which would be good for this use
7068 clutter_actor_get_allocation_box (self, &allocation);
7070 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7071 * actor's own coordinate space but the allocation is in parent
7075 clip->x2 = allocation.x2 - allocation.x1;
7076 clip->y2 = allocation.y2 - allocation.y1;
7080 _clutter_actor_queue_redraw_full (ClutterActor *self,
7081 ClutterRedrawFlags flags,
7082 ClutterPaintVolume *volume,
7083 ClutterEffect *effect)
7085 ClutterActorPrivate *priv = self->priv;
7086 ClutterPaintVolume allocation_pv;
7087 ClutterPaintVolume *pv;
7088 gboolean should_free_pv;
7089 ClutterActor *stage;
7091 /* Here's an outline of the actor queue redraw mechanism:
7093 * The process starts in one of the following two functions which
7094 * are wrappers for this function:
7095 * clutter_actor_queue_redraw
7096 * _clutter_actor_queue_redraw_with_clip
7098 * additionally, an effect can queue a redraw by wrapping this
7099 * function in clutter_effect_queue_rerun
7101 * This functions queues an entry in a list associated with the
7102 * stage which is a list of actors that queued a redraw while
7103 * updating the timelines, performing layouting and processing other
7104 * mainloop sources before the next paint starts.
7106 * We aim to minimize the processing done at this point because
7107 * there is a good chance other events will happen while updating
7108 * the scenegraph that would invalidate any expensive work we might
7109 * otherwise try to do here. For example we don't try and resolve
7110 * the screen space bounding box of an actor at this stage so as to
7111 * minimize how much of the screen redraw because it's possible
7112 * something else will happen which will force a full redraw anyway.
7114 * When all updates are complete and we come to paint the stage then
7115 * we iterate this list and actually emit the "queue-redraw" signals
7116 * for each of the listed actors which will bubble up to the stage
7117 * for each actor and at that point we will transform the actors
7118 * paint volume into screen coordinates to determine the clip region
7119 * for what needs to be redrawn in the next paint.
7121 * Besides minimizing redundant work another reason for this
7122 * deferred design is that it's more likely we will be able to
7123 * determine the paint volume of an actor once we've finished
7124 * updating the scenegraph because its allocation should be up to
7125 * date. NB: If we can't determine an actors paint volume then we
7126 * can't automatically queue a clipped redraw which can make a big
7127 * difference to performance.
7129 * So the control flow goes like this:
7130 * One of clutter_actor_queue_redraw,
7131 * _clutter_actor_queue_redraw_with_clip
7132 * or clutter_effect_queue_rerun
7134 * then control moves to:
7135 * _clutter_stage_queue_actor_redraw
7137 * later during _clutter_stage_do_update, once relayouting is done
7138 * and the scenegraph has been updated we will call:
7139 * _clutter_stage_finish_queue_redraws
7141 * _clutter_stage_finish_queue_redraws will call
7142 * _clutter_actor_finish_queue_redraw for each listed actor.
7143 * Note: actors *are* allowed to queue further redraws during this
7144 * process (considering clone actors or texture_new_from_actor which
7145 * respond to their source queueing a redraw by queuing a redraw
7146 * themselves). We repeat the process until the list is empty.
7148 * This will result in the "queue-redraw" signal being fired for
7149 * each actor which will pass control to the default signal handler:
7150 * clutter_actor_real_queue_redraw
7152 * This will bubble up to the stages handler:
7153 * clutter_stage_real_queue_redraw
7155 * clutter_stage_real_queue_redraw will transform the actors paint
7156 * volume into screen space and add it as a clip region for the next
7160 /* ignore queueing a redraw for actors being destroyed */
7161 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7164 stage = _clutter_actor_get_stage_internal (self);
7166 /* Ignore queueing a redraw for actors not descended from a stage */
7170 /* ignore queueing a redraw on stages that are being destroyed */
7171 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7174 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7176 ClutterActorBox allocation_clip;
7177 ClutterVertex origin;
7179 /* If the actor doesn't have a valid allocation then we will
7180 * queue a full stage redraw. */
7181 if (priv->needs_allocation)
7183 /* NB: NULL denotes an undefined clip which will result in a
7185 _clutter_actor_set_queue_redraw_clip (self, NULL);
7186 _clutter_actor_signal_queue_redraw (self, self);
7190 _clutter_paint_volume_init_static (&allocation_pv, self);
7191 pv = &allocation_pv;
7193 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7195 origin.x = allocation_clip.x1;
7196 origin.y = allocation_clip.y1;
7198 clutter_paint_volume_set_origin (pv, &origin);
7199 clutter_paint_volume_set_width (pv,
7200 allocation_clip.x2 - allocation_clip.x1);
7201 clutter_paint_volume_set_height (pv,
7202 allocation_clip.y2 -
7203 allocation_clip.y1);
7204 should_free_pv = TRUE;
7209 should_free_pv = FALSE;
7212 self->priv->queue_redraw_entry =
7213 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7214 priv->queue_redraw_entry,
7219 clutter_paint_volume_free (pv);
7221 /* If this is the first redraw queued then we can directly use the
7223 if (!priv->is_dirty)
7224 priv->effect_to_redraw = effect;
7225 /* Otherwise we need to merge it with the existing effect parameter */
7226 else if (effect != NULL)
7228 /* If there's already an effect then we need to use whichever is
7229 later in the chain of actors. Otherwise a full redraw has
7230 already been queued on the actor so we need to ignore the
7232 if (priv->effect_to_redraw != NULL)
7234 if (priv->effects == NULL)
7235 g_warning ("Redraw queued with an effect that is "
7236 "not applied to the actor");
7241 for (l = _clutter_meta_group_peek_metas (priv->effects);
7245 if (l->data == priv->effect_to_redraw ||
7247 priv->effect_to_redraw = l->data;
7254 /* If no effect is specified then we need to redraw the whole
7256 priv->effect_to_redraw = NULL;
7259 priv->is_dirty = TRUE;
7263 * clutter_actor_queue_redraw:
7264 * @self: A #ClutterActor
7266 * Queues up a redraw of an actor and any children. The redraw occurs
7267 * once the main loop becomes idle (after the current batch of events
7268 * has been processed, roughly).
7270 * Applications rarely need to call this, as redraws are handled
7271 * automatically by modification functions.
7273 * This function will not do anything if @self is not visible, or
7274 * if the actor is inside an invisible part of the scenegraph.
7276 * Also be aware that painting is a NOP for actors with an opacity of
7279 * When you are implementing a custom actor you must queue a redraw
7280 * whenever some private state changes that will affect painting or
7281 * picking of your actor.
7284 clutter_actor_queue_redraw (ClutterActor *self)
7286 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7288 _clutter_actor_queue_redraw_full (self,
7290 NULL, /* clip volume */
7295 * _clutter_actor_queue_redraw_with_clip:
7296 * @self: A #ClutterActor
7297 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7298 * this queue redraw.
7299 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7300 * redrawn or %NULL if you are just using a @flag to state your
7303 * Queues up a clipped redraw of an actor and any children. The redraw
7304 * occurs once the main loop becomes idle (after the current batch of
7305 * events has been processed, roughly).
7307 * If no flags are given the clip volume is defined by @volume
7308 * specified in actor coordinates and tells Clutter that only content
7309 * within this volume has been changed so Clutter can optionally
7310 * optimize the redraw.
7312 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7313 * should be %NULL and this tells Clutter to use the actor's current
7314 * allocation as a clip box. This flag can only be used for 2D actors,
7315 * because any actor with depth may be projected outside its
7318 * Applications rarely need to call this, as redraws are handled
7319 * automatically by modification functions.
7321 * This function will not do anything if @self is not visible, or if
7322 * the actor is inside an invisible part of the scenegraph.
7324 * Also be aware that painting is a NOP for actors with an opacity of
7327 * When you are implementing a custom actor you must queue a redraw
7328 * whenever some private state changes that will affect painting or
7329 * picking of your actor.
7332 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7333 ClutterRedrawFlags flags,
7334 ClutterPaintVolume *volume)
7336 _clutter_actor_queue_redraw_full (self,
7338 volume, /* clip volume */
7343 _clutter_actor_queue_only_relayout (ClutterActor *self)
7345 ClutterActorPrivate *priv = self->priv;
7347 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7350 if (priv->needs_width_request &&
7351 priv->needs_height_request &&
7352 priv->needs_allocation)
7353 return; /* save some cpu cycles */
7355 #if CLUTTER_ENABLE_DEBUG
7356 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7358 g_warning ("The actor '%s' is currently inside an allocation "
7359 "cycle; calling clutter_actor_queue_relayout() is "
7361 _clutter_actor_get_debug_name (self));
7363 #endif /* CLUTTER_ENABLE_DEBUG */
7365 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7369 * clutter_actor_queue_redraw_with_clip:
7370 * @self: a #ClutterActor
7371 * @clip: (allow-none): a rectangular clip region, or %NULL
7373 * Queues a redraw on @self limited to a specific, actor-relative
7376 * If @clip is %NULL this function is equivalent to
7377 * clutter_actor_queue_redraw().
7382 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7383 const cairo_rectangle_int_t *clip)
7385 ClutterPaintVolume volume;
7386 ClutterVertex origin;
7388 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7392 clutter_actor_queue_redraw (self);
7396 _clutter_paint_volume_init_static (&volume, self);
7402 clutter_paint_volume_set_origin (&volume, &origin);
7403 clutter_paint_volume_set_width (&volume, clip->width);
7404 clutter_paint_volume_set_height (&volume, clip->height);
7406 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7408 clutter_paint_volume_free (&volume);
7412 * clutter_actor_queue_relayout:
7413 * @self: A #ClutterActor
7415 * Indicates that the actor's size request or other layout-affecting
7416 * properties may have changed. This function is used inside #ClutterActor
7417 * subclass implementations, not by applications directly.
7419 * Queueing a new layout automatically queues a redraw as well.
7424 clutter_actor_queue_relayout (ClutterActor *self)
7426 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7428 _clutter_actor_queue_only_relayout (self);
7429 clutter_actor_queue_redraw (self);
7433 * clutter_actor_get_preferred_size:
7434 * @self: a #ClutterActor
7435 * @min_width_p: (out) (allow-none): return location for the minimum
7437 * @min_height_p: (out) (allow-none): return location for the minimum
7439 * @natural_width_p: (out) (allow-none): return location for the natural
7441 * @natural_height_p: (out) (allow-none): return location for the natural
7444 * Computes the preferred minimum and natural size of an actor, taking into
7445 * account the actor's geometry management (either height-for-width
7446 * or width-for-height).
7448 * The width and height used to compute the preferred height and preferred
7449 * width are the actor's natural ones.
7451 * If you need to control the height for the preferred width, or the width for
7452 * the preferred height, you should use clutter_actor_get_preferred_width()
7453 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7454 * geometry management using the #ClutterActor:request-mode property.
7459 clutter_actor_get_preferred_size (ClutterActor *self,
7460 gfloat *min_width_p,
7461 gfloat *min_height_p,
7462 gfloat *natural_width_p,
7463 gfloat *natural_height_p)
7465 ClutterActorPrivate *priv;
7466 gfloat min_width, min_height;
7467 gfloat natural_width, natural_height;
7469 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7473 min_width = min_height = 0;
7474 natural_width = natural_height = 0;
7476 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7478 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7479 clutter_actor_get_preferred_width (self, -1,
7482 clutter_actor_get_preferred_height (self, natural_width,
7488 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7489 clutter_actor_get_preferred_height (self, -1,
7492 clutter_actor_get_preferred_width (self, natural_height,
7498 *min_width_p = min_width;
7501 *min_height_p = min_height;
7503 if (natural_width_p)
7504 *natural_width_p = natural_width;
7506 if (natural_height_p)
7507 *natural_height_p = natural_height;
7512 * @align: a #ClutterActorAlign
7513 * @direction: a #ClutterTextDirection
7515 * Retrieves the correct alignment depending on the text direction
7517 * Return value: the effective alignment
7519 static ClutterActorAlign
7520 effective_align (ClutterActorAlign align,
7521 ClutterTextDirection direction)
7523 ClutterActorAlign res;
7527 case CLUTTER_ACTOR_ALIGN_START:
7528 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7529 ? CLUTTER_ACTOR_ALIGN_END
7530 : CLUTTER_ACTOR_ALIGN_START;
7533 case CLUTTER_ACTOR_ALIGN_END:
7534 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7535 ? CLUTTER_ACTOR_ALIGN_START
7536 : CLUTTER_ACTOR_ALIGN_END;
7548 adjust_for_margin (float margin_start,
7550 float *minimum_size,
7551 float *natural_size,
7552 float *allocated_start,
7553 float *allocated_end)
7555 *minimum_size -= (margin_start + margin_end);
7556 *natural_size -= (margin_start + margin_end);
7557 *allocated_start += margin_start;
7558 *allocated_end -= margin_end;
7562 adjust_for_alignment (ClutterActorAlign alignment,
7564 float *allocated_start,
7565 float *allocated_end)
7567 float allocated_size = *allocated_end - *allocated_start;
7571 case CLUTTER_ACTOR_ALIGN_FILL:
7575 case CLUTTER_ACTOR_ALIGN_START:
7577 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7580 case CLUTTER_ACTOR_ALIGN_END:
7581 if (allocated_size > natural_size)
7583 *allocated_start += (allocated_size - natural_size);
7584 *allocated_end = *allocated_start + natural_size;
7588 case CLUTTER_ACTOR_ALIGN_CENTER:
7589 if (allocated_size > natural_size)
7591 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7592 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7599 * clutter_actor_adjust_width:
7600 * @self: a #ClutterActor
7601 * @minimum_width: (inout): the actor's preferred minimum width, which
7602 * will be adjusted depending on the margin
7603 * @natural_width: (inout): the actor's preferred natural width, which
7604 * will be adjusted depending on the margin
7605 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7606 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7608 * Adjusts the preferred and allocated position and size of an actor,
7609 * depending on the margin and alignment properties.
7612 clutter_actor_adjust_width (ClutterActor *self,
7613 gfloat *minimum_width,
7614 gfloat *natural_width,
7615 gfloat *adjusted_x1,
7616 gfloat *adjusted_x2)
7618 ClutterTextDirection text_dir;
7619 const ClutterLayoutInfo *info;
7621 info = _clutter_actor_get_layout_info_or_defaults (self);
7622 text_dir = clutter_actor_get_text_direction (self);
7624 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7626 /* this will tweak natural_width to remove the margin, so that
7627 * adjust_for_alignment() will use the correct size
7629 adjust_for_margin (info->margin.left, info->margin.right,
7630 minimum_width, natural_width,
7631 adjusted_x1, adjusted_x2);
7633 adjust_for_alignment (effective_align (info->x_align, text_dir),
7635 adjusted_x1, adjusted_x2);
7639 * clutter_actor_adjust_height:
7640 * @self: a #ClutterActor
7641 * @minimum_height: (inout): the actor's preferred minimum height, which
7642 * will be adjusted depending on the margin
7643 * @natural_height: (inout): the actor's preferred natural height, which
7644 * will be adjusted depending on the margin
7645 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7646 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7648 * Adjusts the preferred and allocated position and size of an actor,
7649 * depending on the margin and alignment properties.
7652 clutter_actor_adjust_height (ClutterActor *self,
7653 gfloat *minimum_height,
7654 gfloat *natural_height,
7655 gfloat *adjusted_y1,
7656 gfloat *adjusted_y2)
7658 const ClutterLayoutInfo *info;
7660 info = _clutter_actor_get_layout_info_or_defaults (self);
7662 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7664 /* this will tweak natural_height to remove the margin, so that
7665 * adjust_for_alignment() will use the correct size
7667 adjust_for_margin (info->margin.top, info->margin.bottom,
7668 minimum_height, natural_height,
7672 /* we don't use effective_align() here, because text direction
7673 * only affects the horizontal axis
7675 adjust_for_alignment (info->y_align,
7682 /* looks for a cached size request for this for_size. If not
7683 * found, returns the oldest entry so it can be overwritten */
7685 _clutter_actor_get_cached_size_request (gfloat for_size,
7686 SizeRequest *cached_size_requests,
7687 SizeRequest **result)
7691 *result = &cached_size_requests[0];
7693 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7697 sr = &cached_size_requests[i];
7700 sr->for_size == for_size)
7702 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7706 else if (sr->age < (*result)->age)
7712 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7718 * clutter_actor_get_preferred_width:
7719 * @self: A #ClutterActor
7720 * @for_height: available height when computing the preferred width,
7721 * or a negative value to indicate that no height is defined
7722 * @min_width_p: (out) (allow-none): return location for minimum width,
7724 * @natural_width_p: (out) (allow-none): return location for the natural
7727 * Computes the requested minimum and natural widths for an actor,
7728 * optionally depending on the specified height, or if they are
7729 * already computed, returns the cached values.
7731 * An actor may not get its request - depending on the layout
7732 * manager that's in effect.
7734 * A request should not incorporate the actor's scale or anchor point;
7735 * those transformations do not affect layout, only rendering.
7740 clutter_actor_get_preferred_width (ClutterActor *self,
7742 gfloat *min_width_p,
7743 gfloat *natural_width_p)
7745 float request_min_width, request_natural_width;
7746 SizeRequest *cached_size_request;
7747 const ClutterLayoutInfo *info;
7748 ClutterActorPrivate *priv;
7749 gboolean found_in_cache;
7751 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7755 info = _clutter_actor_get_layout_info_or_defaults (self);
7757 /* we shortcircuit the case of a fixed size set using set_width() */
7758 if (priv->min_width_set && priv->natural_width_set)
7760 if (min_width_p != NULL)
7761 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7763 if (natural_width_p != NULL)
7764 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7769 /* the remaining cases are:
7771 * - either min_width or natural_width have been set
7772 * - neither min_width or natural_width have been set
7774 * in both cases, we go through the cache (and through the actor in case
7775 * of cache misses) and determine the authoritative value depending on
7779 if (!priv->needs_width_request)
7782 _clutter_actor_get_cached_size_request (for_height,
7783 priv->width_requests,
7784 &cached_size_request);
7788 /* if the actor needs a width request we use the first slot */
7789 found_in_cache = FALSE;
7790 cached_size_request = &priv->width_requests[0];
7793 if (!found_in_cache)
7795 gfloat minimum_width, natural_width;
7796 ClutterActorClass *klass;
7798 minimum_width = natural_width = 0;
7800 /* adjust for the margin */
7801 if (for_height >= 0)
7803 for_height -= (info->margin.top + info->margin.bottom);
7808 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7810 klass = CLUTTER_ACTOR_GET_CLASS (self);
7811 klass->get_preferred_width (self, for_height,
7815 /* adjust for the margin */
7816 minimum_width += (info->margin.left + info->margin.right);
7817 natural_width += (info->margin.left + info->margin.right);
7819 /* Due to accumulated float errors, it's better not to warn
7820 * on this, but just fix it.
7822 if (natural_width < minimum_width)
7823 natural_width = minimum_width;
7825 cached_size_request->min_size = minimum_width;
7826 cached_size_request->natural_size = natural_width;
7827 cached_size_request->for_size = for_height;
7828 cached_size_request->age = priv->cached_width_age;
7830 priv->cached_width_age += 1;
7831 priv->needs_width_request = FALSE;
7834 if (!priv->min_width_set)
7835 request_min_width = cached_size_request->min_size;
7837 request_min_width = info->min_width;
7839 if (!priv->natural_width_set)
7840 request_natural_width = cached_size_request->natural_size;
7842 request_natural_width = info->natural_width;
7845 *min_width_p = request_min_width;
7847 if (natural_width_p)
7848 *natural_width_p = request_natural_width;
7852 * clutter_actor_get_preferred_height:
7853 * @self: A #ClutterActor
7854 * @for_width: available width to assume in computing desired height,
7855 * or a negative value to indicate that no width is defined
7856 * @min_height_p: (out) (allow-none): return location for minimum height,
7858 * @natural_height_p: (out) (allow-none): return location for natural
7861 * Computes the requested minimum and natural heights for an actor,
7862 * or if they are already computed, returns the cached values.
7864 * An actor may not get its request - depending on the layout
7865 * manager that's in effect.
7867 * A request should not incorporate the actor's scale or anchor point;
7868 * those transformations do not affect layout, only rendering.
7873 clutter_actor_get_preferred_height (ClutterActor *self,
7875 gfloat *min_height_p,
7876 gfloat *natural_height_p)
7878 float request_min_height, request_natural_height;
7879 SizeRequest *cached_size_request;
7880 const ClutterLayoutInfo *info;
7881 ClutterActorPrivate *priv;
7882 gboolean found_in_cache;
7884 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7888 info = _clutter_actor_get_layout_info_or_defaults (self);
7890 /* we shortcircuit the case of a fixed size set using set_height() */
7891 if (priv->min_height_set && priv->natural_height_set)
7893 if (min_height_p != NULL)
7894 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7896 if (natural_height_p != NULL)
7897 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7902 /* the remaining cases are:
7904 * - either min_height or natural_height have been set
7905 * - neither min_height or natural_height have been set
7907 * in both cases, we go through the cache (and through the actor in case
7908 * of cache misses) and determine the authoritative value depending on
7912 if (!priv->needs_height_request)
7915 _clutter_actor_get_cached_size_request (for_width,
7916 priv->height_requests,
7917 &cached_size_request);
7921 found_in_cache = FALSE;
7922 cached_size_request = &priv->height_requests[0];
7925 if (!found_in_cache)
7927 gfloat minimum_height, natural_height;
7928 ClutterActorClass *klass;
7930 minimum_height = natural_height = 0;
7932 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7934 /* adjust for margin */
7937 for_width -= (info->margin.left + info->margin.right);
7942 klass = CLUTTER_ACTOR_GET_CLASS (self);
7943 klass->get_preferred_height (self, for_width,
7947 /* adjust for margin */
7948 minimum_height += (info->margin.top + info->margin.bottom);
7949 natural_height += (info->margin.top + info->margin.bottom);
7951 /* Due to accumulated float errors, it's better not to warn
7952 * on this, but just fix it.
7954 if (natural_height < minimum_height)
7955 natural_height = minimum_height;
7957 cached_size_request->min_size = minimum_height;
7958 cached_size_request->natural_size = natural_height;
7959 cached_size_request->for_size = for_width;
7960 cached_size_request->age = priv->cached_height_age;
7962 priv->cached_height_age += 1;
7963 priv->needs_height_request = FALSE;
7966 if (!priv->min_height_set)
7967 request_min_height = cached_size_request->min_size;
7969 request_min_height = info->min_height;
7971 if (!priv->natural_height_set)
7972 request_natural_height = cached_size_request->natural_size;
7974 request_natural_height = info->natural_height;
7977 *min_height_p = request_min_height;
7979 if (natural_height_p)
7980 *natural_height_p = request_natural_height;
7984 * clutter_actor_get_allocation_box:
7985 * @self: A #ClutterActor
7986 * @box: (out): the function fills this in with the actor's allocation
7988 * Gets the layout box an actor has been assigned. The allocation can
7989 * only be assumed valid inside a paint() method; anywhere else, it
7990 * may be out-of-date.
7992 * An allocation does not incorporate the actor's scale or anchor point;
7993 * those transformations do not affect layout, only rendering.
7995 * <note>Do not call any of the clutter_actor_get_allocation_*() family
7996 * of functions inside the implementation of the get_preferred_width()
7997 * or get_preferred_height() virtual functions.</note>
8002 clutter_actor_get_allocation_box (ClutterActor *self,
8003 ClutterActorBox *box)
8005 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8007 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8008 * which limits calling get_allocation to inside paint() basically; or
8009 * we can 2) force a layout, which could be expensive if someone calls
8010 * get_allocation somewhere silly; or we can 3) just return the latest
8011 * value, allowing it to be out-of-date, and assume people know what
8014 * The least-surprises approach that keeps existing code working is
8015 * likely to be 2). People can end up doing some inefficient things,
8016 * though, and in general code that requires 2) is probably broken.
8019 /* this implements 2) */
8020 if (G_UNLIKELY (self->priv->needs_allocation))
8022 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8024 /* do not queue a relayout on an unparented actor */
8026 _clutter_stage_maybe_relayout (stage);
8029 /* commenting out the code above and just keeping this assigment
8032 *box = self->priv->allocation;
8036 * clutter_actor_get_allocation_geometry:
8037 * @self: A #ClutterActor
8038 * @geom: (out): allocation geometry in pixels
8040 * Gets the layout box an actor has been assigned. The allocation can
8041 * only be assumed valid inside a paint() method; anywhere else, it
8042 * may be out-of-date.
8044 * An allocation does not incorporate the actor's scale or anchor point;
8045 * those transformations do not affect layout, only rendering.
8047 * The returned rectangle is in pixels.
8052 clutter_actor_get_allocation_geometry (ClutterActor *self,
8053 ClutterGeometry *geom)
8055 ClutterActorBox box;
8057 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8058 g_return_if_fail (geom != NULL);
8060 clutter_actor_get_allocation_box (self, &box);
8062 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8063 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8064 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8065 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8069 clutter_actor_update_constraints (ClutterActor *self,
8070 ClutterActorBox *allocation)
8072 ClutterActorPrivate *priv = self->priv;
8073 const GList *constraints, *l;
8075 if (priv->constraints == NULL)
8078 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8079 for (l = constraints; l != NULL; l = l->next)
8081 ClutterConstraint *constraint = l->data;
8082 ClutterActorMeta *meta = l->data;
8084 if (clutter_actor_meta_get_enabled (meta))
8086 _clutter_constraint_update_allocation (constraint,
8094 * clutter_actor_adjust_allocation:
8095 * @self: a #ClutterActor
8096 * @allocation: (inout): the allocation to adjust
8098 * Adjusts the passed allocation box taking into account the actor's
8099 * layout information, like alignment, expansion, and margin.
8102 clutter_actor_adjust_allocation (ClutterActor *self,
8103 ClutterActorBox *allocation)
8105 ClutterActorBox adj_allocation;
8106 float alloc_width, alloc_height;
8107 float min_width, min_height;
8108 float nat_width, nat_height;
8109 ClutterRequestMode req_mode;
8111 adj_allocation = *allocation;
8113 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8115 /* we want to hit the cache, so we use the public API */
8116 req_mode = clutter_actor_get_request_mode (self);
8118 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8120 clutter_actor_get_preferred_width (self, -1,
8123 clutter_actor_get_preferred_height (self, alloc_width,
8127 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8129 clutter_actor_get_preferred_height (self, -1,
8132 clutter_actor_get_preferred_height (self, alloc_height,
8137 #ifdef CLUTTER_ENABLE_DEBUG
8138 /* warn about underallocations */
8139 if (_clutter_diagnostic_enabled () &&
8140 (floorf (min_width - alloc_width) > 0 ||
8141 floorf (min_height - alloc_height) > 0))
8143 ClutterActor *parent = clutter_actor_get_parent (self);
8145 /* the only actors that are allowed to be underallocated are the Stage,
8146 * as it doesn't have an implicit size, and Actors that specifically
8147 * told us that they want to opt-out from layout control mechanisms
8148 * through the NO_LAYOUT escape hatch.
8150 if (parent != NULL &&
8151 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8153 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8154 "of %.2f x %.2f from its parent actor '%s', but its "
8155 "requested minimum size is of %.2f x %.2f",
8156 _clutter_actor_get_debug_name (self),
8157 alloc_width, alloc_height,
8158 _clutter_actor_get_debug_name (parent),
8159 min_width, min_height);
8164 clutter_actor_adjust_width (self,
8168 &adj_allocation.x2);
8170 clutter_actor_adjust_height (self,
8174 &adj_allocation.y2);
8176 /* we maintain the invariant that an allocation cannot be adjusted
8177 * to be outside the parent-given box
8179 if (adj_allocation.x1 < allocation->x1 ||
8180 adj_allocation.y1 < allocation->y1 ||
8181 adj_allocation.x2 > allocation->x2 ||
8182 adj_allocation.y2 > allocation->y2)
8184 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8185 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8186 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8187 _clutter_actor_get_debug_name (self),
8188 adj_allocation.x1, adj_allocation.y1,
8189 adj_allocation.x2 - adj_allocation.x1,
8190 adj_allocation.y2 - adj_allocation.y1,
8191 allocation->x1, allocation->y1,
8192 allocation->x2 - allocation->x1,
8193 allocation->y2 - allocation->y1);
8197 *allocation = adj_allocation;
8201 * clutter_actor_allocate:
8202 * @self: A #ClutterActor
8203 * @box: new allocation of the actor, in parent-relative coordinates
8204 * @flags: flags that control the allocation
8206 * Called by the parent of an actor to assign the actor its size.
8207 * Should never be called by applications (except when implementing
8208 * a container or layout manager).
8210 * Actors can know from their allocation box whether they have moved
8211 * with respect to their parent actor. The @flags parameter describes
8212 * additional information about the allocation, for instance whether
8213 * the parent has moved with respect to the stage, for example because
8214 * a grandparent's origin has moved.
8219 clutter_actor_allocate (ClutterActor *self,
8220 const ClutterActorBox *box,
8221 ClutterAllocationFlags flags)
8223 ClutterActorPrivate *priv;
8224 ClutterActorClass *klass;
8225 ClutterActorBox old_allocation, real_allocation;
8226 gboolean origin_changed, child_moved, size_changed;
8227 gboolean stage_allocation_changed;
8229 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8230 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8232 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8233 "which isn't a descendent of the stage!\n",
8234 self, _clutter_actor_get_debug_name (self));
8240 old_allocation = priv->allocation;
8241 real_allocation = *box;
8243 /* constraints are allowed to modify the allocation only here; we do
8244 * this prior to all the other checks so that we can bail out if the
8245 * allocation did not change
8247 clutter_actor_update_constraints (self, &real_allocation);
8249 /* adjust the allocation depending on the align/margin properties */
8250 clutter_actor_adjust_allocation (self, &real_allocation);
8252 if (real_allocation.x2 < real_allocation.x1 ||
8253 real_allocation.y2 < real_allocation.y1)
8255 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8256 _clutter_actor_get_debug_name (self),
8257 real_allocation.x2 - real_allocation.x1,
8258 real_allocation.y2 - real_allocation.y1);
8261 /* we allow 0-sized actors, but not negative-sized ones */
8262 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8263 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8265 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8267 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8268 real_allocation.y1 != old_allocation.y1);
8270 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8271 real_allocation.y2 != old_allocation.y2);
8273 if (origin_changed || child_moved || size_changed)
8274 stage_allocation_changed = TRUE;
8276 stage_allocation_changed = FALSE;
8278 /* If we get an allocation "out of the blue"
8279 * (we did not queue relayout), then we want to
8280 * ignore it. But if we have needs_allocation set,
8281 * we want to guarantee that allocate() virtual
8282 * method is always called, i.e. that queue_relayout()
8283 * always results in an allocate() invocation on
8286 * The optimization here is to avoid re-allocating
8287 * actors that did not queue relayout and were
8290 if (!priv->needs_allocation && !stage_allocation_changed)
8292 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8296 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8297 * clutter_actor_allocate(), it indicates whether the parent has its
8298 * absolute origin moved; when passed in to ClutterActor::allocate()
8299 * virtual method though, it indicates whether the child has its
8300 * absolute origin moved. So we set it when child_moved is TRUE
8303 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8305 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8307 klass = CLUTTER_ACTOR_GET_CLASS (self);
8308 klass->allocate (self, &real_allocation, flags);
8310 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8312 if (stage_allocation_changed)
8313 clutter_actor_queue_redraw (self);
8317 * clutter_actor_set_allocation:
8318 * @self: a #ClutterActor
8319 * @box: a #ClutterActorBox
8320 * @flags: allocation flags
8322 * Stores the allocation of @self as defined by @box.
8324 * This function can only be called from within the implementation of
8325 * the #ClutterActorClass.allocate() virtual function.
8327 * The allocation should have been adjusted to take into account constraints,
8328 * alignment, and margin properties. If you are implementing a #ClutterActor
8329 * subclass that provides its own layout management policy for its children
8330 * instead of using a #ClutterLayoutManager delegate, you should not call
8331 * this function on the children of @self; instead, you should call
8332 * clutter_actor_allocate(), which will adjust the allocation box for
8335 * This function should only be used by subclasses of #ClutterActor
8336 * that wish to store their allocation but cannot chain up to the
8337 * parent's implementation; the default implementation of the
8338 * #ClutterActorClass.allocate() virtual function will call this
8341 * It is important to note that, while chaining up was the recommended
8342 * behaviour for #ClutterActor subclasses prior to the introduction of
8343 * this function, it is recommended to call clutter_actor_set_allocation()
8346 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8347 * to handle the allocation of its children, this function will call
8348 * the clutter_layout_manager_allocate() function only if the
8349 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8350 * expected that the subclass will call clutter_layout_manager_allocate()
8351 * by itself. For instance, the following code:
8355 * my_actor_allocate (ClutterActor *actor,
8356 * const ClutterActorBox *allocation,
8357 * ClutterAllocationFlags flags)
8359 * ClutterActorBox new_alloc;
8360 * ClutterAllocationFlags new_flags;
8362 * adjust_allocation (allocation, &new_alloc);
8364 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8366 * /* this will use the layout manager set on the actor */
8367 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8371 * is equivalent to this:
8375 * my_actor_allocate (ClutterActor *actor,
8376 * const ClutterActorBox *allocation,
8377 * ClutterAllocationFlags flags)
8379 * ClutterLayoutManager *layout;
8380 * ClutterActorBox new_alloc;
8382 * adjust_allocation (allocation, &new_alloc);
8384 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8386 * layout = clutter_actor_get_layout_manager (actor);
8387 * clutter_layout_manager_allocate (layout,
8388 * CLUTTER_CONTAINER (actor),
8397 clutter_actor_set_allocation (ClutterActor *self,
8398 const ClutterActorBox *box,
8399 ClutterAllocationFlags flags)
8401 ClutterActorPrivate *priv;
8404 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8405 g_return_if_fail (box != NULL);
8407 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8409 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8410 "can only be called from within the implementation of "
8411 "the ClutterActor::allocate() virtual function.");
8417 g_object_freeze_notify (G_OBJECT (self));
8419 changed = clutter_actor_set_allocation_internal (self, box, flags);
8421 /* we allocate our children before we notify changes in our geometry,
8422 * so that people connecting to properties will be able to get valid
8423 * data out of the sub-tree of the scene graph that has this actor at
8426 clutter_actor_maybe_layout_children (self, box, flags);
8430 ClutterActorBox signal_box = priv->allocation;
8431 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8433 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8438 g_object_thaw_notify (G_OBJECT (self));
8442 * clutter_actor_set_geometry:
8443 * @self: A #ClutterActor
8444 * @geometry: A #ClutterGeometry
8446 * Sets the actor's fixed position and forces its minimum and natural
8447 * size, in pixels. This means the untransformed actor will have the
8448 * given geometry. This is the same as calling clutter_actor_set_position()
8449 * and clutter_actor_set_size().
8451 * Deprecated: 1.10: Use clutter_actor_set_position() and
8452 * clutter_actor_set_size() instead.
8455 clutter_actor_set_geometry (ClutterActor *self,
8456 const ClutterGeometry *geometry)
8458 g_object_freeze_notify (G_OBJECT (self));
8460 clutter_actor_set_position (self, geometry->x, geometry->y);
8461 clutter_actor_set_size (self, geometry->width, geometry->height);
8463 g_object_thaw_notify (G_OBJECT (self));
8467 * clutter_actor_get_geometry:
8468 * @self: A #ClutterActor
8469 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8471 * Gets the size and position of an actor relative to its parent
8472 * actor. This is the same as calling clutter_actor_get_position() and
8473 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8474 * requested size and position if the actor's allocation is invalid.
8476 * Deprecated: 1.10: Use clutter_actor_get_position() and
8477 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8481 clutter_actor_get_geometry (ClutterActor *self,
8482 ClutterGeometry *geometry)
8484 gfloat x, y, width, height;
8486 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8487 g_return_if_fail (geometry != NULL);
8489 clutter_actor_get_position (self, &x, &y);
8490 clutter_actor_get_size (self, &width, &height);
8492 geometry->x = (int) x;
8493 geometry->y = (int) y;
8494 geometry->width = (int) width;
8495 geometry->height = (int) height;
8499 * clutter_actor_set_position:
8500 * @self: A #ClutterActor
8501 * @x: New left position of actor in pixels.
8502 * @y: New top position of actor in pixels.
8504 * Sets the actor's fixed position in pixels relative to any parent
8507 * If a layout manager is in use, this position will override the
8508 * layout manager and force a fixed position.
8511 clutter_actor_set_position (ClutterActor *self,
8515 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8517 g_object_freeze_notify (G_OBJECT (self));
8519 clutter_actor_set_x (self, x);
8520 clutter_actor_set_y (self, y);
8522 g_object_thaw_notify (G_OBJECT (self));
8526 * clutter_actor_get_fixed_position_set:
8527 * @self: A #ClutterActor
8529 * Checks whether an actor has a fixed position set (and will thus be
8530 * unaffected by any layout manager).
8532 * Return value: %TRUE if the fixed position is set on the actor
8537 clutter_actor_get_fixed_position_set (ClutterActor *self)
8539 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8541 return self->priv->position_set;
8545 * clutter_actor_set_fixed_position_set:
8546 * @self: A #ClutterActor
8547 * @is_set: whether to use fixed position
8549 * Sets whether an actor has a fixed position set (and will thus be
8550 * unaffected by any layout manager).
8555 clutter_actor_set_fixed_position_set (ClutterActor *self,
8558 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8560 if (self->priv->position_set == (is_set != FALSE))
8563 self->priv->position_set = is_set != FALSE;
8564 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8566 clutter_actor_queue_relayout (self);
8570 * clutter_actor_move_by:
8571 * @self: A #ClutterActor
8572 * @dx: Distance to move Actor on X axis.
8573 * @dy: Distance to move Actor on Y axis.
8575 * Moves an actor by the specified distance relative to its current
8576 * position in pixels.
8578 * This function modifies the fixed position of an actor and thus removes
8579 * it from any layout management. Another way to move an actor is with an
8580 * anchor point, see clutter_actor_set_anchor_point().
8585 clutter_actor_move_by (ClutterActor *self,
8589 const ClutterLayoutInfo *info;
8592 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8594 info = _clutter_actor_get_layout_info_or_defaults (self);
8598 clutter_actor_set_position (self, x + dx, y + dy);
8602 clutter_actor_set_min_width (ClutterActor *self,
8605 ClutterActorPrivate *priv = self->priv;
8606 ClutterActorBox old = { 0, };
8607 ClutterLayoutInfo *info;
8609 /* if we are setting the size on a top-level actor and the
8610 * backend only supports static top-levels (e.g. framebuffers)
8611 * then we ignore the passed value and we override it with
8612 * the stage implementation's preferred size.
8614 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8615 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8618 info = _clutter_actor_get_layout_info (self);
8620 if (priv->min_width_set && min_width == info->min_width)
8623 g_object_freeze_notify (G_OBJECT (self));
8625 clutter_actor_store_old_geometry (self, &old);
8627 info->min_width = min_width;
8628 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8629 clutter_actor_set_min_width_set (self, TRUE);
8631 clutter_actor_notify_if_geometry_changed (self, &old);
8633 g_object_thaw_notify (G_OBJECT (self));
8635 clutter_actor_queue_relayout (self);
8639 clutter_actor_set_min_height (ClutterActor *self,
8643 ClutterActorPrivate *priv = self->priv;
8644 ClutterActorBox old = { 0, };
8645 ClutterLayoutInfo *info;
8647 /* if we are setting the size on a top-level actor and the
8648 * backend only supports static top-levels (e.g. framebuffers)
8649 * then we ignore the passed value and we override it with
8650 * the stage implementation's preferred size.
8652 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8653 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8656 info = _clutter_actor_get_layout_info (self);
8658 if (priv->min_height_set && min_height == info->min_height)
8661 g_object_freeze_notify (G_OBJECT (self));
8663 clutter_actor_store_old_geometry (self, &old);
8665 info->min_height = min_height;
8666 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8667 clutter_actor_set_min_height_set (self, TRUE);
8669 clutter_actor_notify_if_geometry_changed (self, &old);
8671 g_object_thaw_notify (G_OBJECT (self));
8673 clutter_actor_queue_relayout (self);
8677 clutter_actor_set_natural_width (ClutterActor *self,
8678 gfloat natural_width)
8680 ClutterActorPrivate *priv = self->priv;
8681 ClutterActorBox old = { 0, };
8682 ClutterLayoutInfo *info;
8684 /* if we are setting the size on a top-level actor and the
8685 * backend only supports static top-levels (e.g. framebuffers)
8686 * then we ignore the passed value and we override it with
8687 * the stage implementation's preferred size.
8689 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8690 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8693 info = _clutter_actor_get_layout_info (self);
8695 if (priv->natural_width_set && natural_width == info->natural_width)
8698 g_object_freeze_notify (G_OBJECT (self));
8700 clutter_actor_store_old_geometry (self, &old);
8702 info->natural_width = natural_width;
8703 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8704 clutter_actor_set_natural_width_set (self, TRUE);
8706 clutter_actor_notify_if_geometry_changed (self, &old);
8708 g_object_thaw_notify (G_OBJECT (self));
8710 clutter_actor_queue_relayout (self);
8714 clutter_actor_set_natural_height (ClutterActor *self,
8715 gfloat natural_height)
8717 ClutterActorPrivate *priv = self->priv;
8718 ClutterActorBox old = { 0, };
8719 ClutterLayoutInfo *info;
8721 /* if we are setting the size on a top-level actor and the
8722 * backend only supports static top-levels (e.g. framebuffers)
8723 * then we ignore the passed value and we override it with
8724 * the stage implementation's preferred size.
8726 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8727 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8730 info = _clutter_actor_get_layout_info (self);
8732 if (priv->natural_height_set && natural_height == info->natural_height)
8735 g_object_freeze_notify (G_OBJECT (self));
8737 clutter_actor_store_old_geometry (self, &old);
8739 info->natural_height = natural_height;
8740 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8741 clutter_actor_set_natural_height_set (self, TRUE);
8743 clutter_actor_notify_if_geometry_changed (self, &old);
8745 g_object_thaw_notify (G_OBJECT (self));
8747 clutter_actor_queue_relayout (self);
8751 clutter_actor_set_min_width_set (ClutterActor *self,
8752 gboolean use_min_width)
8754 ClutterActorPrivate *priv = self->priv;
8755 ClutterActorBox old = { 0, };
8757 if (priv->min_width_set == (use_min_width != FALSE))
8760 clutter_actor_store_old_geometry (self, &old);
8762 priv->min_width_set = use_min_width != FALSE;
8763 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8765 clutter_actor_notify_if_geometry_changed (self, &old);
8767 clutter_actor_queue_relayout (self);
8771 clutter_actor_set_min_height_set (ClutterActor *self,
8772 gboolean use_min_height)
8774 ClutterActorPrivate *priv = self->priv;
8775 ClutterActorBox old = { 0, };
8777 if (priv->min_height_set == (use_min_height != FALSE))
8780 clutter_actor_store_old_geometry (self, &old);
8782 priv->min_height_set = use_min_height != FALSE;
8783 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8785 clutter_actor_notify_if_geometry_changed (self, &old);
8787 clutter_actor_queue_relayout (self);
8791 clutter_actor_set_natural_width_set (ClutterActor *self,
8792 gboolean use_natural_width)
8794 ClutterActorPrivate *priv = self->priv;
8795 ClutterActorBox old = { 0, };
8797 if (priv->natural_width_set == (use_natural_width != FALSE))
8800 clutter_actor_store_old_geometry (self, &old);
8802 priv->natural_width_set = use_natural_width != FALSE;
8803 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8805 clutter_actor_notify_if_geometry_changed (self, &old);
8807 clutter_actor_queue_relayout (self);
8811 clutter_actor_set_natural_height_set (ClutterActor *self,
8812 gboolean use_natural_height)
8814 ClutterActorPrivate *priv = self->priv;
8815 ClutterActorBox old = { 0, };
8817 if (priv->natural_height_set == (use_natural_height != FALSE))
8820 clutter_actor_store_old_geometry (self, &old);
8822 priv->natural_height_set = use_natural_height != FALSE;
8823 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8825 clutter_actor_notify_if_geometry_changed (self, &old);
8827 clutter_actor_queue_relayout (self);
8831 * clutter_actor_set_request_mode:
8832 * @self: a #ClutterActor
8833 * @mode: the request mode
8835 * Sets the geometry request mode of @self.
8837 * The @mode determines the order for invoking
8838 * clutter_actor_get_preferred_width() and
8839 * clutter_actor_get_preferred_height()
8844 clutter_actor_set_request_mode (ClutterActor *self,
8845 ClutterRequestMode mode)
8847 ClutterActorPrivate *priv;
8849 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8853 if (priv->request_mode == mode)
8856 priv->request_mode = mode;
8858 priv->needs_width_request = TRUE;
8859 priv->needs_height_request = TRUE;
8861 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8863 clutter_actor_queue_relayout (self);
8867 * clutter_actor_get_request_mode:
8868 * @self: a #ClutterActor
8870 * Retrieves the geometry request mode of @self
8872 * Return value: the request mode for the actor
8877 clutter_actor_get_request_mode (ClutterActor *self)
8879 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8880 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8882 return self->priv->request_mode;
8885 /* variant of set_width() without checks and without notification
8886 * freeze+thaw, for internal usage only
8889 clutter_actor_set_width_internal (ClutterActor *self,
8894 /* the Stage will use the :min-width to control the minimum
8895 * width to be resized to, so we should not be setting it
8896 * along with the :natural-width
8898 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8899 clutter_actor_set_min_width (self, width);
8901 clutter_actor_set_natural_width (self, width);
8905 /* we only unset the :natural-width for the Stage */
8906 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8907 clutter_actor_set_min_width_set (self, FALSE);
8909 clutter_actor_set_natural_width_set (self, FALSE);
8913 /* variant of set_height() without checks and without notification
8914 * freeze+thaw, for internal usage only
8917 clutter_actor_set_height_internal (ClutterActor *self,
8922 /* see the comment above in set_width_internal() */
8923 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8924 clutter_actor_set_min_height (self, height);
8926 clutter_actor_set_natural_height (self, height);
8930 /* see the comment above in set_width_internal() */
8931 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8932 clutter_actor_set_min_height_set (self, FALSE);
8934 clutter_actor_set_natural_height_set (self, FALSE);
8939 * clutter_actor_set_size:
8940 * @self: A #ClutterActor
8941 * @width: New width of actor in pixels, or -1
8942 * @height: New height of actor in pixels, or -1
8944 * Sets the actor's size request in pixels. This overrides any
8945 * "normal" size request the actor would have. For example
8946 * a text actor might normally request the size of the text;
8947 * this function would force a specific size instead.
8949 * If @width and/or @height are -1 the actor will use its
8950 * "normal" size request instead of overriding it, i.e.
8951 * you can "unset" the size with -1.
8953 * This function sets or unsets both the minimum and natural size.
8956 clutter_actor_set_size (ClutterActor *self,
8960 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8962 g_object_freeze_notify (G_OBJECT (self));
8964 clutter_actor_set_width (self, width);
8965 clutter_actor_set_height (self, height);
8967 g_object_thaw_notify (G_OBJECT (self));
8971 * clutter_actor_get_size:
8972 * @self: A #ClutterActor
8973 * @width: (out) (allow-none): return location for the width, or %NULL.
8974 * @height: (out) (allow-none): return location for the height, or %NULL.
8976 * This function tries to "do what you mean" and return
8977 * the size an actor will have. If the actor has a valid
8978 * allocation, the allocation will be returned; otherwise,
8979 * the actors natural size request will be returned.
8981 * If you care whether you get the request vs. the allocation, you
8982 * should probably call a different function like
8983 * clutter_actor_get_allocation_box() or
8984 * clutter_actor_get_preferred_width().
8989 clutter_actor_get_size (ClutterActor *self,
8993 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8996 *width = clutter_actor_get_width (self);
8999 *height = clutter_actor_get_height (self);
9003 * clutter_actor_get_position:
9004 * @self: a #ClutterActor
9005 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9006 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9008 * This function tries to "do what you mean" and tell you where the
9009 * actor is, prior to any transformations. Retrieves the fixed
9010 * position of an actor in pixels, if one has been set; otherwise, if
9011 * the allocation is valid, returns the actor's allocated position;
9012 * otherwise, returns 0,0.
9014 * The returned position is in pixels.
9019 clutter_actor_get_position (ClutterActor *self,
9023 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9026 *x = clutter_actor_get_x (self);
9029 *y = clutter_actor_get_y (self);
9033 * clutter_actor_get_transformed_position:
9034 * @self: A #ClutterActor
9035 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9036 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9038 * Gets the absolute position of an actor, in pixels relative to the stage.
9043 clutter_actor_get_transformed_position (ClutterActor *self,
9050 v1.x = v1.y = v1.z = 0;
9051 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9061 * clutter_actor_get_transformed_size:
9062 * @self: A #ClutterActor
9063 * @width: (out) (allow-none): return location for the width, or %NULL
9064 * @height: (out) (allow-none): return location for the height, or %NULL
9066 * Gets the absolute size of an actor in pixels, taking into account the
9069 * If the actor has a valid allocation, the allocated size will be used.
9070 * If the actor has not a valid allocation then the preferred size will
9071 * be transformed and returned.
9073 * If you want the transformed allocation, see
9074 * clutter_actor_get_abs_allocation_vertices() instead.
9076 * <note>When the actor (or one of its ancestors) is rotated around the
9077 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9078 * as a generic quadrangle; in that case this function returns the size
9079 * of the smallest rectangle that encapsulates the entire quad. Please
9080 * note that in this case no assumptions can be made about the relative
9081 * position of this envelope to the absolute position of the actor, as
9082 * returned by clutter_actor_get_transformed_position(); if you need this
9083 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9084 * to get the coords of the actual quadrangle.</note>
9089 clutter_actor_get_transformed_size (ClutterActor *self,
9093 ClutterActorPrivate *priv;
9095 gfloat x_min, x_max, y_min, y_max;
9098 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9102 /* if the actor hasn't been allocated yet, get the preferred
9103 * size and transform that
9105 if (priv->needs_allocation)
9107 gfloat natural_width, natural_height;
9108 ClutterActorBox box;
9110 /* Make a fake allocation to transform.
9112 * NB: _clutter_actor_transform_and_project_box expects a box in
9113 * the actor's coordinate space... */
9118 natural_width = natural_height = 0;
9119 clutter_actor_get_preferred_size (self, NULL, NULL,
9123 box.x2 = natural_width;
9124 box.y2 = natural_height;
9126 _clutter_actor_transform_and_project_box (self, &box, v);
9129 clutter_actor_get_abs_allocation_vertices (self, v);
9131 x_min = x_max = v[0].x;
9132 y_min = y_max = v[0].y;
9134 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9150 *width = x_max - x_min;
9153 *height = y_max - y_min;
9157 * clutter_actor_get_width:
9158 * @self: A #ClutterActor
9160 * Retrieves the width of a #ClutterActor.
9162 * If the actor has a valid allocation, this function will return the
9163 * width of the allocated area given to the actor.
9165 * If the actor does not have a valid allocation, this function will
9166 * return the actor's natural width, that is the preferred width of
9169 * If you care whether you get the preferred width or the width that
9170 * has been assigned to the actor, you should probably call a different
9171 * function like clutter_actor_get_allocation_box() to retrieve the
9172 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9175 * If an actor has a fixed width, for instance a width that has been
9176 * assigned using clutter_actor_set_width(), the width returned will
9177 * be the same value.
9179 * Return value: the width of the actor, in pixels
9182 clutter_actor_get_width (ClutterActor *self)
9184 ClutterActorPrivate *priv;
9186 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9190 if (priv->needs_allocation)
9192 gfloat natural_width = 0;
9194 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9195 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9198 gfloat natural_height = 0;
9200 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9201 clutter_actor_get_preferred_width (self, natural_height,
9206 return natural_width;
9209 return priv->allocation.x2 - priv->allocation.x1;
9213 * clutter_actor_get_height:
9214 * @self: A #ClutterActor
9216 * Retrieves the height of a #ClutterActor.
9218 * If the actor has a valid allocation, this function will return the
9219 * height of the allocated area given to the actor.
9221 * If the actor does not have a valid allocation, this function will
9222 * return the actor's natural height, that is the preferred height of
9225 * If you care whether you get the preferred height or the height that
9226 * has been assigned to the actor, you should probably call a different
9227 * function like clutter_actor_get_allocation_box() to retrieve the
9228 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9231 * If an actor has a fixed height, for instance a height that has been
9232 * assigned using clutter_actor_set_height(), the height returned will
9233 * be the same value.
9235 * Return value: the height of the actor, in pixels
9238 clutter_actor_get_height (ClutterActor *self)
9240 ClutterActorPrivate *priv;
9242 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9246 if (priv->needs_allocation)
9248 gfloat natural_height = 0;
9250 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9252 gfloat natural_width = 0;
9254 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9255 clutter_actor_get_preferred_height (self, natural_width,
9256 NULL, &natural_height);
9259 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9261 return natural_height;
9264 return priv->allocation.y2 - priv->allocation.y1;
9268 * clutter_actor_set_width:
9269 * @self: A #ClutterActor
9270 * @width: Requested new width for the actor, in pixels, or -1
9272 * Forces a width on an actor, causing the actor's preferred width
9273 * and height (if any) to be ignored.
9275 * If @width is -1 the actor will use its preferred width request
9276 * instead of overriding it, i.e. you can "unset" the width with -1.
9278 * This function sets both the minimum and natural size of the actor.
9283 clutter_actor_set_width (ClutterActor *self,
9286 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9288 if (clutter_actor_get_easing_duration (self) != 0)
9290 ClutterTransition *transition;
9292 transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9293 if (transition == NULL)
9295 float old_width = clutter_actor_get_width (self);
9297 transition = _clutter_actor_create_transition (self,
9298 obj_props[PROP_WIDTH],
9301 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9304 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9306 clutter_actor_queue_relayout (self);
9310 g_object_freeze_notify (G_OBJECT (self));
9312 clutter_actor_set_width_internal (self, width);
9314 g_object_thaw_notify (G_OBJECT (self));
9319 * clutter_actor_set_height:
9320 * @self: A #ClutterActor
9321 * @height: Requested new height for the actor, in pixels, or -1
9323 * Forces a height on an actor, causing the actor's preferred width
9324 * and height (if any) to be ignored.
9326 * If @height is -1 the actor will use its preferred height instead of
9327 * overriding it, i.e. you can "unset" the height with -1.
9329 * This function sets both the minimum and natural size of the actor.
9334 clutter_actor_set_height (ClutterActor *self,
9337 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9339 if (clutter_actor_get_easing_duration (self) != 0)
9341 ClutterTransition *transition;
9343 transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9344 if (transition == NULL)
9346 float old_height = clutter_actor_get_height (self);
9348 transition = _clutter_actor_create_transition (self,
9349 obj_props[PROP_HEIGHT],
9352 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9355 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9357 clutter_actor_queue_relayout (self);
9361 g_object_freeze_notify (G_OBJECT (self));
9363 clutter_actor_set_height_internal (self, height);
9365 g_object_thaw_notify (G_OBJECT (self));
9370 clutter_actor_set_x_internal (ClutterActor *self,
9373 ClutterActorPrivate *priv = self->priv;
9374 ClutterLayoutInfo *linfo;
9375 ClutterActorBox old = { 0, };
9377 linfo = _clutter_actor_get_layout_info (self);
9379 if (priv->position_set && linfo->fixed_x == x)
9382 clutter_actor_store_old_geometry (self, &old);
9385 clutter_actor_set_fixed_position_set (self, TRUE);
9387 clutter_actor_notify_if_geometry_changed (self, &old);
9389 clutter_actor_queue_relayout (self);
9393 clutter_actor_set_y_internal (ClutterActor *self,
9396 ClutterActorPrivate *priv = self->priv;
9397 ClutterLayoutInfo *linfo;
9398 ClutterActorBox old = { 0, };
9400 linfo = _clutter_actor_get_layout_info (self);
9402 if (priv->position_set && linfo->fixed_y == y)
9405 clutter_actor_store_old_geometry (self, &old);
9408 clutter_actor_set_fixed_position_set (self, TRUE);
9410 clutter_actor_notify_if_geometry_changed (self, &old);
9414 * clutter_actor_set_x:
9415 * @self: a #ClutterActor
9416 * @x: the actor's position on the X axis
9418 * Sets the actor's X coordinate, relative to its parent, in pixels.
9420 * Overrides any layout manager and forces a fixed position for
9423 * The #ClutterActor:x property is animatable.
9428 clutter_actor_set_x (ClutterActor *self,
9431 const ClutterLayoutInfo *linfo;
9433 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9435 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9437 if (clutter_actor_get_easing_duration (self) != 0)
9439 ClutterTransition *transition;
9441 transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9442 if (transition == NULL)
9444 transition = _clutter_actor_create_transition (self,
9449 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9452 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9454 clutter_actor_queue_relayout (self);
9457 clutter_actor_set_x_internal (self, x);
9461 * clutter_actor_set_y:
9462 * @self: a #ClutterActor
9463 * @y: the actor's position on the Y axis
9465 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9467 * Overrides any layout manager and forces a fixed position for
9470 * The #ClutterActor:y property is animatable.
9475 clutter_actor_set_y (ClutterActor *self,
9478 const ClutterLayoutInfo *linfo;
9480 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9482 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9484 if (clutter_actor_get_easing_duration (self) != 0)
9486 ClutterTransition *transition;
9488 transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9489 if (transition == NULL)
9491 transition = _clutter_actor_create_transition (self,
9496 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9499 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9501 clutter_actor_queue_relayout (self);
9504 clutter_actor_set_y_internal (self, y);
9506 clutter_actor_queue_relayout (self);
9510 * clutter_actor_get_x:
9511 * @self: A #ClutterActor
9513 * Retrieves the X coordinate of a #ClutterActor.
9515 * This function tries to "do what you mean", by returning the
9516 * correct value depending on the actor's state.
9518 * If the actor has a valid allocation, this function will return
9519 * the X coordinate of the origin of the allocation box.
9521 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9522 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9523 * function will return that coordinate.
9525 * If both the allocation and a fixed position are missing, this function
9528 * Return value: the X coordinate, in pixels, ignoring any
9529 * transformation (i.e. scaling, rotation)
9532 clutter_actor_get_x (ClutterActor *self)
9534 ClutterActorPrivate *priv;
9536 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9540 if (priv->needs_allocation)
9542 if (priv->position_set)
9544 const ClutterLayoutInfo *info;
9546 info = _clutter_actor_get_layout_info_or_defaults (self);
9548 return info->fixed_x;
9554 return priv->allocation.x1;
9558 * clutter_actor_get_y:
9559 * @self: A #ClutterActor
9561 * Retrieves the Y coordinate of a #ClutterActor.
9563 * This function tries to "do what you mean", by returning the
9564 * correct value depending on the actor's state.
9566 * If the actor has a valid allocation, this function will return
9567 * the Y coordinate of the origin of the allocation box.
9569 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9570 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9571 * function will return that coordinate.
9573 * If both the allocation and a fixed position are missing, this function
9576 * Return value: the Y coordinate, in pixels, ignoring any
9577 * transformation (i.e. scaling, rotation)
9580 clutter_actor_get_y (ClutterActor *self)
9582 ClutterActorPrivate *priv;
9584 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9588 if (priv->needs_allocation)
9590 if (priv->position_set)
9592 const ClutterLayoutInfo *info;
9594 info = _clutter_actor_get_layout_info_or_defaults (self);
9596 return info->fixed_y;
9602 return priv->allocation.y1;
9606 * clutter_actor_set_scale:
9607 * @self: A #ClutterActor
9608 * @scale_x: double factor to scale actor by horizontally.
9609 * @scale_y: double factor to scale actor by vertically.
9611 * Scales an actor with the given factors. The scaling is relative to
9612 * the scale center and the anchor point. The scale center is
9613 * unchanged by this function and defaults to 0,0.
9615 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9621 clutter_actor_set_scale (ClutterActor *self,
9625 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9627 g_object_freeze_notify (G_OBJECT (self));
9629 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9630 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9632 g_object_thaw_notify (G_OBJECT (self));
9636 * clutter_actor_set_scale_full:
9637 * @self: A #ClutterActor
9638 * @scale_x: double factor to scale actor by horizontally.
9639 * @scale_y: double factor to scale actor by vertically.
9640 * @center_x: X coordinate of the center of the scale.
9641 * @center_y: Y coordinate of the center of the scale
9643 * Scales an actor with the given factors around the given center
9644 * point. The center point is specified in pixels relative to the
9645 * anchor point (usually the top left corner of the actor).
9647 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9653 clutter_actor_set_scale_full (ClutterActor *self,
9659 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9661 g_object_freeze_notify (G_OBJECT (self));
9663 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9664 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9665 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9666 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9668 g_object_thaw_notify (G_OBJECT (self));
9672 * clutter_actor_set_scale_with_gravity:
9673 * @self: A #ClutterActor
9674 * @scale_x: double factor to scale actor by horizontally.
9675 * @scale_y: double factor to scale actor by vertically.
9676 * @gravity: the location of the scale center expressed as a compass
9679 * Scales an actor with the given factors around the given
9680 * center point. The center point is specified as one of the compass
9681 * directions in #ClutterGravity. For example, setting it to north
9682 * will cause the top of the actor to remain unchanged and the rest of
9683 * the actor to expand left, right and downwards.
9685 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9691 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9694 ClutterGravity gravity)
9696 ClutterTransformInfo *info;
9699 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9701 obj = G_OBJECT (self);
9703 g_object_freeze_notify (obj);
9705 info = _clutter_actor_get_transform_info (self);
9706 info->scale_x = scale_x;
9707 info->scale_y = scale_y;
9709 if (gravity == CLUTTER_GRAVITY_NONE)
9710 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9712 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9714 self->priv->transform_valid = FALSE;
9716 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9717 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9718 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9719 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9720 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9722 clutter_actor_queue_redraw (self);
9724 g_object_thaw_notify (obj);
9728 * clutter_actor_get_scale:
9729 * @self: A #ClutterActor
9730 * @scale_x: (out) (allow-none): Location to store horizonal
9731 * scale factor, or %NULL.
9732 * @scale_y: (out) (allow-none): Location to store vertical
9733 * scale factor, or %NULL.
9735 * Retrieves an actors scale factors.
9740 clutter_actor_get_scale (ClutterActor *self,
9744 const ClutterTransformInfo *info;
9746 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9748 info = _clutter_actor_get_transform_info_or_defaults (self);
9751 *scale_x = info->scale_x;
9754 *scale_y = info->scale_y;
9758 * clutter_actor_get_scale_center:
9759 * @self: A #ClutterActor
9760 * @center_x: (out) (allow-none): Location to store the X position
9761 * of the scale center, or %NULL.
9762 * @center_y: (out) (allow-none): Location to store the Y position
9763 * of the scale center, or %NULL.
9765 * Retrieves the scale center coordinate in pixels relative to the top
9766 * left corner of the actor. If the scale center was specified using a
9767 * #ClutterGravity this will calculate the pixel offset using the
9768 * current size of the actor.
9773 clutter_actor_get_scale_center (ClutterActor *self,
9777 const ClutterTransformInfo *info;
9779 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9781 info = _clutter_actor_get_transform_info_or_defaults (self);
9783 clutter_anchor_coord_get_units (self, &info->scale_center,
9790 * clutter_actor_get_scale_gravity:
9791 * @self: A #ClutterActor
9793 * Retrieves the scale center as a compass direction. If the scale
9794 * center was specified in pixels or units this will return
9795 * %CLUTTER_GRAVITY_NONE.
9797 * Return value: the scale gravity
9802 clutter_actor_get_scale_gravity (ClutterActor *self)
9804 const ClutterTransformInfo *info;
9806 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9808 info = _clutter_actor_get_transform_info_or_defaults (self);
9810 return clutter_anchor_coord_get_gravity (&info->scale_center);
9814 clutter_actor_set_opacity_internal (ClutterActor *self,
9817 ClutterActorPrivate *priv = self->priv;
9819 if (priv->opacity != opacity)
9821 priv->opacity = opacity;
9823 /* Queue a redraw from the flatten effect so that it can use
9824 its cached image if available instead of having to redraw the
9825 actual actor. If it doesn't end up using the FBO then the
9826 effect is still able to continue the paint anyway. If there
9827 is no flatten effect yet then this is equivalent to queueing
9829 _clutter_actor_queue_redraw_full (self,
9832 priv->flatten_effect);
9834 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9839 * clutter_actor_set_opacity:
9840 * @self: A #ClutterActor
9841 * @opacity: New opacity value for the actor.
9843 * Sets the actor's opacity, with zero being completely transparent and
9844 * 255 (0xff) being fully opaque.
9846 * The #ClutterActor:opacity property is animatable.
9849 clutter_actor_set_opacity (ClutterActor *self,
9852 ClutterActorPrivate *priv;
9854 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9858 if (clutter_actor_get_easing_duration (self) != 0)
9860 ClutterTransition *transition;
9862 transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9863 if (transition == NULL)
9865 transition = _clutter_actor_create_transition (self,
9866 obj_props[PROP_OPACITY],
9869 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9872 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9874 clutter_actor_queue_redraw (self);
9877 clutter_actor_set_opacity_internal (self, opacity);
9881 * clutter_actor_get_paint_opacity_internal:
9882 * @self: a #ClutterActor
9884 * Retrieves the absolute opacity of the actor, as it appears on the stage
9886 * This function does not do type checks
9888 * Return value: the absolute opacity of the actor
9891 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9893 ClutterActorPrivate *priv = self->priv;
9894 ClutterActor *parent;
9896 /* override the top-level opacity to always be 255; even in
9897 * case of ClutterStage:use-alpha being TRUE we want the rest
9898 * of the scene to be painted
9900 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9903 if (priv->opacity_override >= 0)
9904 return priv->opacity_override;
9906 parent = priv->parent;
9908 /* Factor in the actual actors opacity with parents */
9911 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9913 if (opacity != 0xff)
9914 return (opacity * priv->opacity) / 0xff;
9917 return priv->opacity;
9922 * clutter_actor_get_paint_opacity:
9923 * @self: A #ClutterActor
9925 * Retrieves the absolute opacity of the actor, as it appears on the stage.
9927 * This function traverses the hierarchy chain and composites the opacity of
9928 * the actor with that of its parents.
9930 * This function is intended for subclasses to use in the paint virtual
9931 * function, to paint themselves with the correct opacity.
9933 * Return value: The actor opacity value.
9938 clutter_actor_get_paint_opacity (ClutterActor *self)
9940 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9942 return clutter_actor_get_paint_opacity_internal (self);
9946 * clutter_actor_get_opacity:
9947 * @self: a #ClutterActor
9949 * Retrieves the opacity value of an actor, as set by
9950 * clutter_actor_set_opacity().
9952 * For retrieving the absolute opacity of the actor inside a paint
9953 * virtual function, see clutter_actor_get_paint_opacity().
9955 * Return value: the opacity of the actor
9958 clutter_actor_get_opacity (ClutterActor *self)
9960 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9962 return self->priv->opacity;
9966 * clutter_actor_set_offscreen_redirect:
9967 * @self: A #ClutterActor
9968 * @redirect: New offscreen redirect flags for the actor.
9970 * Defines the circumstances where the actor should be redirected into
9971 * an offscreen image. The offscreen image is used to flatten the
9972 * actor into a single image while painting for two main reasons.
9973 * Firstly, when the actor is painted a second time without any of its
9974 * contents changing it can simply repaint the cached image without
9975 * descending further down the actor hierarchy. Secondly, it will make
9976 * the opacity look correct even if there are overlapping primitives
9979 * Caching the actor could in some cases be a performance win and in
9980 * some cases be a performance lose so it is important to determine
9981 * which value is right for an actor before modifying this value. For
9982 * example, there is never any reason to flatten an actor that is just
9983 * a single texture (such as a #ClutterTexture) because it is
9984 * effectively already cached in an image so the offscreen would be
9985 * redundant. Also if the actor contains primitives that are far apart
9986 * with a large transparent area in the middle (such as a large
9987 * CluterGroup with a small actor in the top left and a small actor in
9988 * the bottom right) then the cached image will contain the entire
9989 * image of the large area and the paint will waste time blending all
9990 * of the transparent pixels in the middle.
9992 * The default method of implementing opacity on a container simply
9993 * forwards on the opacity to all of the children. If the children are
9994 * overlapping then it will appear as if they are two separate glassy
9995 * objects and there will be a break in the color where they
9996 * overlap. By redirecting to an offscreen buffer it will be as if the
9997 * two opaque objects are combined into one and then made transparent
9998 * which is usually what is expected.
10000 * The image below demonstrates the difference between redirecting and
10001 * not. The image shows two Clutter groups, each containing a red and
10002 * a green rectangle which overlap. The opacity on the group is set to
10003 * 128 (which is 50%). When the offscreen redirect is not used, the
10004 * red rectangle can be seen through the blue rectangle as if the two
10005 * rectangles were separately transparent. When the redirect is used
10006 * the group as a whole is transparent instead so the red rectangle is
10007 * not visible where they overlap.
10009 * <figure id="offscreen-redirect">
10010 * <title>Sample of using an offscreen redirect for transparency</title>
10011 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10014 * The default value for this property is 0, so we effectively will
10015 * never redirect an actor offscreen by default. This means that there
10016 * are times that transparent actors may look glassy as described
10017 * above. The reason this is the default is because there is a
10018 * performance trade off between quality and performance here. In many
10019 * cases the default form of glassy opacity looks good enough, but if
10020 * it's not you will need to set the
10021 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10022 * redirection for opacity.
10024 * Custom actors that don't contain any overlapping primitives are
10025 * recommended to override the has_overlaps() virtual to return %FALSE
10026 * for maximum efficiency.
10031 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10032 ClutterOffscreenRedirect redirect)
10034 ClutterActorPrivate *priv;
10036 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10040 if (priv->offscreen_redirect != redirect)
10042 priv->offscreen_redirect = redirect;
10044 /* Queue a redraw from the effect so that it can use its cached
10045 image if available instead of having to redraw the actual
10046 actor. If it doesn't end up using the FBO then the effect is
10047 still able to continue the paint anyway. If there is no
10048 effect then this is equivalent to queuing a full redraw */
10049 _clutter_actor_queue_redraw_full (self,
10052 priv->flatten_effect);
10054 g_object_notify_by_pspec (G_OBJECT (self),
10055 obj_props[PROP_OFFSCREEN_REDIRECT]);
10060 * clutter_actor_get_offscreen_redirect:
10061 * @self: a #ClutterActor
10063 * Retrieves whether to redirect the actor to an offscreen buffer, as
10064 * set by clutter_actor_set_offscreen_redirect().
10066 * Return value: the value of the offscreen-redirect property of the actor
10070 ClutterOffscreenRedirect
10071 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10073 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10075 return self->priv->offscreen_redirect;
10079 * clutter_actor_set_name:
10080 * @self: A #ClutterActor
10081 * @name: Textual tag to apply to actor
10083 * Sets the given name to @self. The name can be used to identify
10087 clutter_actor_set_name (ClutterActor *self,
10090 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10092 g_free (self->priv->name);
10093 self->priv->name = g_strdup (name);
10095 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10099 * clutter_actor_get_name:
10100 * @self: A #ClutterActor
10102 * Retrieves the name of @self.
10104 * Return value: the name of the actor, or %NULL. The returned string is
10105 * owned by the actor and should not be modified or freed.
10108 clutter_actor_get_name (ClutterActor *self)
10110 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10112 return self->priv->name;
10116 * clutter_actor_get_gid:
10117 * @self: A #ClutterActor
10119 * Retrieves the unique id for @self.
10121 * Return value: Globally unique value for this object instance.
10125 * Deprecated: 1.8: The id is not used any longer.
10128 clutter_actor_get_gid (ClutterActor *self)
10130 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10132 return self->priv->id;
10136 clutter_actor_set_depth_internal (ClutterActor *self,
10139 ClutterTransformInfo *info;
10141 info = _clutter_actor_get_transform_info (self);
10143 if (info->depth != depth)
10145 /* Sets Z value - XXX 2.0: should we invert? */
10146 info->depth = depth;
10148 self->priv->transform_valid = FALSE;
10150 /* FIXME - remove this crap; sadly, there are still containers
10151 * in Clutter that depend on this utter brain damage
10153 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10155 clutter_actor_queue_redraw (self);
10157 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10162 * clutter_actor_set_depth:
10163 * @self: a #ClutterActor
10166 * Sets the Z coordinate of @self to @depth.
10168 * The unit used by @depth is dependant on the perspective setup. See
10169 * also clutter_stage_set_perspective().
10172 clutter_actor_set_depth (ClutterActor *self,
10175 const ClutterTransformInfo *tinfo;
10177 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10179 tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10181 if (clutter_actor_get_easing_duration (self) != 0)
10183 ClutterTransition *transition;
10185 transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10186 if (transition == NULL)
10188 transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10191 clutter_timeline_start (CLUTTER_TIMELINE (transition));
10194 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10196 clutter_actor_queue_redraw (self);
10199 clutter_actor_set_depth_internal (self, depth);
10203 * clutter_actor_get_depth:
10204 * @self: a #ClutterActor
10206 * Retrieves the depth of @self.
10208 * Return value: the depth of the actor
10211 clutter_actor_get_depth (ClutterActor *self)
10213 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10215 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10219 * clutter_actor_set_rotation:
10220 * @self: a #ClutterActor
10221 * @axis: the axis of rotation
10222 * @angle: the angle of rotation
10223 * @x: X coordinate of the rotation center
10224 * @y: Y coordinate of the rotation center
10225 * @z: Z coordinate of the rotation center
10227 * Sets the rotation angle of @self around the given axis.
10229 * The rotation center coordinates used depend on the value of @axis:
10231 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10232 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10233 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10236 * The rotation coordinates are relative to the anchor point of the
10237 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10238 * point is set, the upper left corner is assumed as the origin.
10243 clutter_actor_set_rotation (ClutterActor *self,
10244 ClutterRotateAxis axis,
10252 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10258 g_object_freeze_notify (G_OBJECT (self));
10260 clutter_actor_set_rotation_angle (self, axis, angle);
10261 clutter_actor_set_rotation_center_internal (self, axis, &v);
10263 g_object_thaw_notify (G_OBJECT (self));
10267 * clutter_actor_set_z_rotation_from_gravity:
10268 * @self: a #ClutterActor
10269 * @angle: the angle of rotation
10270 * @gravity: the center point of the rotation
10272 * Sets the rotation angle of @self around the Z axis using the center
10273 * point specified as a compass point. For example to rotate such that
10274 * the center of the actor remains static you can use
10275 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10276 * will move accordingly.
10281 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10283 ClutterGravity gravity)
10285 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10287 if (gravity == CLUTTER_GRAVITY_NONE)
10288 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10291 GObject *obj = G_OBJECT (self);
10292 ClutterTransformInfo *info;
10294 info = _clutter_actor_get_transform_info (self);
10296 g_object_freeze_notify (obj);
10298 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10300 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10301 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10302 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10304 g_object_thaw_notify (obj);
10309 * clutter_actor_get_rotation:
10310 * @self: a #ClutterActor
10311 * @axis: the axis of rotation
10312 * @x: (out): return value for the X coordinate of the center of rotation
10313 * @y: (out): return value for the Y coordinate of the center of rotation
10314 * @z: (out): return value for the Z coordinate of the center of rotation
10316 * Retrieves the angle and center of rotation on the given axis,
10317 * set using clutter_actor_set_rotation().
10319 * Return value: the angle of rotation
10324 clutter_actor_get_rotation (ClutterActor *self,
10325 ClutterRotateAxis axis,
10330 const ClutterTransformInfo *info;
10331 const AnchorCoord *anchor_coord;
10332 gdouble retval = 0;
10334 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10336 info = _clutter_actor_get_transform_info_or_defaults (self);
10340 case CLUTTER_X_AXIS:
10341 anchor_coord = &info->rx_center;
10342 retval = info->rx_angle;
10345 case CLUTTER_Y_AXIS:
10346 anchor_coord = &info->ry_center;
10347 retval = info->ry_angle;
10350 case CLUTTER_Z_AXIS:
10351 anchor_coord = &info->rz_center;
10352 retval = info->rz_angle;
10356 anchor_coord = NULL;
10361 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10367 * clutter_actor_get_z_rotation_gravity:
10368 * @self: A #ClutterActor
10370 * Retrieves the center for the rotation around the Z axis as a
10371 * compass direction. If the center was specified in pixels or units
10372 * this will return %CLUTTER_GRAVITY_NONE.
10374 * Return value: the Z rotation center
10379 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10381 const ClutterTransformInfo *info;
10383 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10385 info = _clutter_actor_get_transform_info_or_defaults (self);
10387 return clutter_anchor_coord_get_gravity (&info->rz_center);
10391 * clutter_actor_set_clip:
10392 * @self: A #ClutterActor
10393 * @xoff: X offset of the clip rectangle
10394 * @yoff: Y offset of the clip rectangle
10395 * @width: Width of the clip rectangle
10396 * @height: Height of the clip rectangle
10398 * Sets clip area for @self. The clip area is always computed from the
10399 * upper left corner of the actor, even if the anchor point is set
10405 clutter_actor_set_clip (ClutterActor *self,
10411 ClutterActorPrivate *priv;
10413 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10417 if (priv->has_clip &&
10418 priv->clip.x == xoff &&
10419 priv->clip.y == yoff &&
10420 priv->clip.width == width &&
10421 priv->clip.height == height)
10424 priv->clip.x = xoff;
10425 priv->clip.y = yoff;
10426 priv->clip.width = width;
10427 priv->clip.height = height;
10429 priv->has_clip = TRUE;
10431 clutter_actor_queue_redraw (self);
10433 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10434 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10438 * clutter_actor_remove_clip:
10439 * @self: A #ClutterActor
10441 * Removes clip area from @self.
10444 clutter_actor_remove_clip (ClutterActor *self)
10446 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10448 if (!self->priv->has_clip)
10451 self->priv->has_clip = FALSE;
10453 clutter_actor_queue_redraw (self);
10455 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10459 * clutter_actor_has_clip:
10460 * @self: a #ClutterActor
10462 * Determines whether the actor has a clip area set or not.
10464 * Return value: %TRUE if the actor has a clip area set.
10469 clutter_actor_has_clip (ClutterActor *self)
10471 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10473 return self->priv->has_clip;
10477 * clutter_actor_get_clip:
10478 * @self: a #ClutterActor
10479 * @xoff: (out) (allow-none): return location for the X offset of
10480 * the clip rectangle, or %NULL
10481 * @yoff: (out) (allow-none): return location for the Y offset of
10482 * the clip rectangle, or %NULL
10483 * @width: (out) (allow-none): return location for the width of
10484 * the clip rectangle, or %NULL
10485 * @height: (out) (allow-none): return location for the height of
10486 * the clip rectangle, or %NULL
10488 * Gets the clip area for @self, if any is set
10493 clutter_actor_get_clip (ClutterActor *self,
10499 ClutterActorPrivate *priv;
10501 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10505 if (!priv->has_clip)
10509 *xoff = priv->clip.x;
10512 *yoff = priv->clip.y;
10515 *width = priv->clip.width;
10517 if (height != NULL)
10518 *height = priv->clip.height;
10522 * clutter_actor_get_children:
10523 * @self: a #ClutterActor
10525 * Retrieves the list of children of @self.
10527 * Return value: (transfer container) (element-type ClutterActor): A newly
10528 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10534 clutter_actor_get_children (ClutterActor *self)
10536 ClutterActor *iter;
10539 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10541 /* we walk the list backward so that we can use prepend(),
10544 for (iter = self->priv->last_child, res = NULL;
10546 iter = iter->priv->prev_sibling)
10548 res = g_list_prepend (res, iter);
10555 * insert_child_at_depth:
10556 * @self: a #ClutterActor
10557 * @child: a #ClutterActor
10559 * Inserts @child inside the list of children held by @self, using
10560 * the depth as the insertion criteria.
10562 * This sadly makes the insertion not O(1), but we can keep the
10563 * list sorted so that the painters algorithm we use for painting
10564 * the children will work correctly.
10567 insert_child_at_depth (ClutterActor *self,
10568 ClutterActor *child,
10569 gpointer dummy G_GNUC_UNUSED)
10571 ClutterActor *iter;
10574 child->priv->parent = self;
10577 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10579 /* special-case the first child */
10580 if (self->priv->n_children == 0)
10582 self->priv->first_child = child;
10583 self->priv->last_child = child;
10585 child->priv->next_sibling = NULL;
10586 child->priv->prev_sibling = NULL;
10591 /* Find the right place to insert the child so that it will still be
10592 sorted and the child will be after all of the actors at the same
10594 for (iter = self->priv->first_child;
10596 iter = iter->priv->next_sibling)
10601 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10603 if (iter_depth > child_depth)
10609 ClutterActor *tmp = iter->priv->prev_sibling;
10612 tmp->priv->next_sibling = child;
10614 /* Insert the node before the found one */
10615 child->priv->prev_sibling = iter->priv->prev_sibling;
10616 child->priv->next_sibling = iter;
10617 iter->priv->prev_sibling = child;
10621 ClutterActor *tmp = self->priv->last_child;
10624 tmp->priv->next_sibling = child;
10626 /* insert the node at the end of the list */
10627 child->priv->prev_sibling = self->priv->last_child;
10628 child->priv->next_sibling = NULL;
10631 if (child->priv->prev_sibling == NULL)
10632 self->priv->first_child = child;
10634 if (child->priv->next_sibling == NULL)
10635 self->priv->last_child = child;
10639 insert_child_at_index (ClutterActor *self,
10640 ClutterActor *child,
10643 gint index_ = GPOINTER_TO_INT (data_);
10645 child->priv->parent = self;
10649 ClutterActor *tmp = self->priv->first_child;
10652 tmp->priv->prev_sibling = child;
10654 child->priv->prev_sibling = NULL;
10655 child->priv->next_sibling = tmp;
10657 else if (index_ < 0 || index_ >= self->priv->n_children)
10659 ClutterActor *tmp = self->priv->last_child;
10662 tmp->priv->next_sibling = child;
10664 child->priv->prev_sibling = tmp;
10665 child->priv->next_sibling = NULL;
10669 ClutterActor *iter;
10672 for (iter = self->priv->first_child, i = 0;
10674 iter = iter->priv->next_sibling, i += 1)
10678 ClutterActor *tmp = iter->priv->prev_sibling;
10680 child->priv->prev_sibling = tmp;
10681 child->priv->next_sibling = iter;
10683 iter->priv->prev_sibling = child;
10686 tmp->priv->next_sibling = child;
10693 if (child->priv->prev_sibling == NULL)
10694 self->priv->first_child = child;
10696 if (child->priv->next_sibling == NULL)
10697 self->priv->last_child = child;
10701 insert_child_above (ClutterActor *self,
10702 ClutterActor *child,
10705 ClutterActor *sibling = data;
10707 child->priv->parent = self;
10709 if (sibling == NULL)
10710 sibling = self->priv->last_child;
10712 child->priv->prev_sibling = sibling;
10714 if (sibling != NULL)
10716 ClutterActor *tmp = sibling->priv->next_sibling;
10718 child->priv->next_sibling = tmp;
10721 tmp->priv->prev_sibling = child;
10723 sibling->priv->next_sibling = child;
10726 child->priv->next_sibling = NULL;
10728 if (child->priv->prev_sibling == NULL)
10729 self->priv->first_child = child;
10731 if (child->priv->next_sibling == NULL)
10732 self->priv->last_child = child;
10736 insert_child_below (ClutterActor *self,
10737 ClutterActor *child,
10740 ClutterActor *sibling = data;
10742 child->priv->parent = self;
10744 if (sibling == NULL)
10745 sibling = self->priv->first_child;
10747 child->priv->next_sibling = sibling;
10749 if (sibling != NULL)
10751 ClutterActor *tmp = sibling->priv->prev_sibling;
10753 child->priv->prev_sibling = tmp;
10756 tmp->priv->next_sibling = child;
10758 sibling->priv->prev_sibling = child;
10761 child->priv->prev_sibling = NULL;
10763 if (child->priv->prev_sibling == NULL)
10764 self->priv->first_child = child;
10766 if (child->priv->next_sibling == NULL)
10767 self->priv->last_child = child;
10770 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10771 ClutterActor *child,
10775 ADD_CHILD_CREATE_META = 1 << 0,
10776 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10777 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10778 ADD_CHILD_CHECK_STATE = 1 << 3,
10779 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10781 /* default flags for public API */
10782 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10783 ADD_CHILD_EMIT_PARENT_SET |
10784 ADD_CHILD_EMIT_ACTOR_ADDED |
10785 ADD_CHILD_CHECK_STATE |
10786 ADD_CHILD_NOTIFY_FIRST_LAST,
10788 /* flags for legacy/deprecated API */
10789 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10790 ADD_CHILD_CHECK_STATE |
10791 ADD_CHILD_NOTIFY_FIRST_LAST
10792 } ClutterActorAddChildFlags;
10795 * clutter_actor_add_child_internal:
10796 * @self: a #ClutterActor
10797 * @child: a #ClutterActor
10798 * @flags: control flags for actions
10799 * @add_func: delegate function
10800 * @data: (closure): data to pass to @add_func
10802 * Adds @child to the list of children of @self.
10804 * The actual insertion inside the list is delegated to @add_func: this
10805 * function will just set up the state, perform basic checks, and emit
10808 * The @flags argument is used to perform additional operations.
10811 clutter_actor_add_child_internal (ClutterActor *self,
10812 ClutterActor *child,
10813 ClutterActorAddChildFlags flags,
10814 ClutterActorAddChildFunc add_func,
10817 ClutterTextDirection text_dir;
10818 gboolean create_meta;
10819 gboolean emit_parent_set, emit_actor_added;
10820 gboolean check_state;
10821 gboolean notify_first_last;
10822 ClutterActor *old_first_child, *old_last_child;
10824 if (child->priv->parent != NULL)
10826 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10827 "use clutter_actor_remove_child() first.",
10828 _clutter_actor_get_debug_name (child),
10829 _clutter_actor_get_debug_name (child->priv->parent));
10833 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10835 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10836 "a child of another actor.",
10837 _clutter_actor_get_debug_name (child));
10842 /* XXX - this check disallows calling methods that change the stacking
10843 * order within the destruction sequence, by triggering a critical
10844 * warning first, and leaving the actor in an undefined state, which
10845 * then ends up being caught by an assertion.
10847 * the reproducible sequence is:
10849 * - actor gets destroyed;
10850 * - another actor, linked to the first, will try to change the
10851 * stacking order of the first actor;
10852 * - changing the stacking order is a composite operation composed
10853 * by the following steps:
10854 * 1. ref() the child;
10855 * 2. remove_child_internal(), which removes the reference;
10856 * 3. add_child_internal(), which adds a reference;
10857 * - the state of the actor is not changed between (2) and (3), as
10858 * it could be an expensive recomputation;
10859 * - if (3) bails out, then the actor is in an undefined state, but
10861 * - the destruction sequence terminates, but the actor is unparented
10862 * while its state indicates being parented instead.
10863 * - assertion failure.
10865 * the obvious fix would be to decompose each set_child_*_sibling()
10866 * method into proper remove_child()/add_child(), with state validation;
10867 * this may cause excessive work, though, and trigger a cascade of other
10868 * bugs in code that assumes that a change in the stacking order is an
10869 * atomic operation.
10871 * another potential fix is to just remove this check here, and let
10872 * code doing stacking order changes inside the destruction sequence
10873 * of an actor continue doing the work.
10875 * the third fix is to silently bail out early from every
10876 * set_child_*_sibling() and set_child_at_index() method, and avoid
10879 * I have a preference for the second solution, since it involves the
10880 * least amount of work, and the least amount of code duplication.
10882 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10884 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10886 g_warning ("The actor '%s' is currently being destroyed, and "
10887 "cannot be added as a child of another actor.",
10888 _clutter_actor_get_debug_name (child));
10893 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10894 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10895 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10896 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10897 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10899 old_first_child = self->priv->first_child;
10900 old_last_child = self->priv->last_child;
10902 g_object_freeze_notify (G_OBJECT (self));
10905 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10907 g_object_ref_sink (child);
10908 child->priv->parent = NULL;
10909 child->priv->next_sibling = NULL;
10910 child->priv->prev_sibling = NULL;
10912 /* delegate the actual insertion */
10913 add_func (self, child, data);
10915 g_assert (child->priv->parent == self);
10917 self->priv->n_children += 1;
10919 self->priv->age += 1;
10921 /* if push_internal() has been called then we automatically set
10922 * the flag on the actor
10924 if (self->priv->internal_child)
10925 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10927 /* clutter_actor_reparent() will emit ::parent-set for us */
10928 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10929 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10933 /* If parent is mapped or realized, we need to also be mapped or
10934 * realized once we're inside the parent.
10936 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10938 /* propagate the parent's text direction to the child */
10939 text_dir = clutter_actor_get_text_direction (self);
10940 clutter_actor_set_text_direction (child, text_dir);
10943 if (child->priv->show_on_set_parent)
10944 clutter_actor_show (child);
10946 if (CLUTTER_ACTOR_IS_MAPPED (child))
10947 clutter_actor_queue_redraw (child);
10949 /* maintain the invariant that if an actor needs layout,
10950 * its parents do as well
10952 if (child->priv->needs_width_request ||
10953 child->priv->needs_height_request ||
10954 child->priv->needs_allocation)
10956 /* we work around the short-circuiting we do
10957 * in clutter_actor_queue_relayout() since we
10958 * want to force a relayout
10960 child->priv->needs_width_request = TRUE;
10961 child->priv->needs_height_request = TRUE;
10962 child->priv->needs_allocation = TRUE;
10964 clutter_actor_queue_relayout (child->priv->parent);
10967 if (emit_actor_added)
10968 g_signal_emit_by_name (self, "actor-added", child);
10970 if (notify_first_last)
10972 if (old_first_child != self->priv->first_child)
10973 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10975 if (old_last_child != self->priv->last_child)
10976 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10979 g_object_thaw_notify (G_OBJECT (self));
10983 * clutter_actor_add_child:
10984 * @self: a #ClutterActor
10985 * @child: a #ClutterActor
10987 * Adds @child to the children of @self.
10989 * This function will acquire a reference on @child that will only
10990 * be released when calling clutter_actor_remove_child().
10992 * This function will take into consideration the #ClutterActor:depth
10993 * of @child, and will keep the list of children sorted.
10995 * This function will emit the #ClutterContainer::actor-added signal
11001 clutter_actor_add_child (ClutterActor *self,
11002 ClutterActor *child)
11004 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11005 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11006 g_return_if_fail (self != child);
11007 g_return_if_fail (child->priv->parent == NULL);
11009 clutter_actor_add_child_internal (self, child,
11010 ADD_CHILD_DEFAULT_FLAGS,
11011 insert_child_at_depth,
11016 * clutter_actor_insert_child_at_index:
11017 * @self: a #ClutterActor
11018 * @child: a #ClutterActor
11019 * @index_: the index
11021 * Inserts @child into the list of children of @self, using the
11022 * given @index_. If @index_ is greater than the number of children
11023 * in @self, or is less than 0, then the new child is added at the end.
11025 * This function will acquire a reference on @child that will only
11026 * be released when calling clutter_actor_remove_child().
11028 * This function will not take into consideration the #ClutterActor:depth
11031 * This function will emit the #ClutterContainer::actor-added signal
11037 clutter_actor_insert_child_at_index (ClutterActor *self,
11038 ClutterActor *child,
11041 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11042 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11043 g_return_if_fail (self != child);
11044 g_return_if_fail (child->priv->parent == NULL);
11046 clutter_actor_add_child_internal (self, child,
11047 ADD_CHILD_DEFAULT_FLAGS,
11048 insert_child_at_index,
11049 GINT_TO_POINTER (index_));
11053 * clutter_actor_insert_child_above:
11054 * @self: a #ClutterActor
11055 * @child: a #ClutterActor
11056 * @sibling: (allow-none): a child of @self, or %NULL
11058 * Inserts @child into the list of children of @self, above another
11059 * child of @self or, if @sibling is %NULL, above all the children
11062 * This function will acquire a reference on @child that will only
11063 * be released when calling clutter_actor_remove_child().
11065 * This function will not take into consideration the #ClutterActor:depth
11068 * This function will emit the #ClutterContainer::actor-added signal
11074 clutter_actor_insert_child_above (ClutterActor *self,
11075 ClutterActor *child,
11076 ClutterActor *sibling)
11078 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11079 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11080 g_return_if_fail (self != child);
11081 g_return_if_fail (child != sibling);
11082 g_return_if_fail (child->priv->parent == NULL);
11083 g_return_if_fail (sibling == NULL ||
11084 (CLUTTER_IS_ACTOR (sibling) &&
11085 sibling->priv->parent == self));
11087 clutter_actor_add_child_internal (self, child,
11088 ADD_CHILD_DEFAULT_FLAGS,
11089 insert_child_above,
11094 * clutter_actor_insert_child_below:
11095 * @self: a #ClutterActor
11096 * @child: a #ClutterActor
11097 * @sibling: (allow-none): a child of @self, or %NULL
11099 * Inserts @child into the list of children of @self, below another
11100 * child of @self or, if @sibling is %NULL, below all the children
11103 * This function will acquire a reference on @child that will only
11104 * be released when calling clutter_actor_remove_child().
11106 * This function will not take into consideration the #ClutterActor:depth
11109 * This function will emit the #ClutterContainer::actor-added signal
11115 clutter_actor_insert_child_below (ClutterActor *self,
11116 ClutterActor *child,
11117 ClutterActor *sibling)
11119 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11120 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11121 g_return_if_fail (self != child);
11122 g_return_if_fail (child != sibling);
11123 g_return_if_fail (child->priv->parent == NULL);
11124 g_return_if_fail (sibling == NULL ||
11125 (CLUTTER_IS_ACTOR (sibling) &&
11126 sibling->priv->parent == self));
11128 clutter_actor_add_child_internal (self, child,
11129 ADD_CHILD_DEFAULT_FLAGS,
11130 insert_child_below,
11135 * clutter_actor_set_parent:
11136 * @self: A #ClutterActor
11137 * @parent: A new #ClutterActor parent
11139 * Sets the parent of @self to @parent.
11141 * This function will result in @parent acquiring a reference on @self,
11142 * eventually by sinking its floating reference first. The reference
11143 * will be released by clutter_actor_unparent().
11145 * This function should only be called by legacy #ClutterActor<!-- -->s
11146 * implementing the #ClutterContainer interface.
11148 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11151 clutter_actor_set_parent (ClutterActor *self,
11152 ClutterActor *parent)
11154 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11155 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11156 g_return_if_fail (self != parent);
11157 g_return_if_fail (self->priv->parent == NULL);
11159 /* as this function will be called inside ClutterContainer::add
11160 * implementations or when building up a composite actor, we have
11161 * to preserve the old behaviour, and not create child meta or
11162 * emit the ::actor-added signal, to avoid recursion or double
11165 clutter_actor_add_child_internal (parent, self,
11166 ADD_CHILD_LEGACY_FLAGS,
11167 insert_child_at_depth,
11172 * clutter_actor_get_parent:
11173 * @self: A #ClutterActor
11175 * Retrieves the parent of @self.
11177 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11178 * if no parent is set
11181 clutter_actor_get_parent (ClutterActor *self)
11183 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11185 return self->priv->parent;
11189 * clutter_actor_get_paint_visibility:
11190 * @self: A #ClutterActor
11192 * Retrieves the 'paint' visibility of an actor recursively checking for non
11195 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11197 * Return Value: %TRUE if the actor is visibile and will be painted.
11202 clutter_actor_get_paint_visibility (ClutterActor *actor)
11204 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11206 return CLUTTER_ACTOR_IS_MAPPED (actor);
11210 * clutter_actor_remove_child:
11211 * @self: a #ClutterActor
11212 * @child: a #ClutterActor
11214 * Removes @child from the children of @self.
11216 * This function will release the reference added by
11217 * clutter_actor_add_child(), so if you want to keep using @child
11218 * you will have to acquire a referenced on it before calling this
11221 * This function will emit the #ClutterContainer::actor-removed
11227 clutter_actor_remove_child (ClutterActor *self,
11228 ClutterActor *child)
11230 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11231 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11232 g_return_if_fail (self != child);
11233 g_return_if_fail (child->priv->parent != NULL);
11234 g_return_if_fail (child->priv->parent == self);
11236 clutter_actor_remove_child_internal (self, child,
11237 REMOVE_CHILD_DEFAULT_FLAGS);
11241 * clutter_actor_remove_all_children:
11242 * @self: a #ClutterActor
11244 * Removes all children of @self.
11246 * This function releases the reference added by inserting a child actor
11247 * in the list of children of @self.
11249 * If the reference count of a child drops to zero, the child will be
11250 * destroyed. If you want to ensure the destruction of all the children
11251 * of @self, use clutter_actor_destroy_all_children().
11256 clutter_actor_remove_all_children (ClutterActor *self)
11258 ClutterActorIter iter;
11260 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11262 if (self->priv->n_children == 0)
11265 g_object_freeze_notify (G_OBJECT (self));
11267 clutter_actor_iter_init (&iter, self);
11268 while (clutter_actor_iter_next (&iter, NULL))
11269 clutter_actor_iter_remove (&iter);
11271 g_object_thaw_notify (G_OBJECT (self));
11274 g_assert (self->priv->first_child == NULL);
11275 g_assert (self->priv->last_child == NULL);
11276 g_assert (self->priv->n_children == 0);
11280 * clutter_actor_destroy_all_children:
11281 * @self: a #ClutterActor
11283 * Destroys all children of @self.
11285 * This function releases the reference added by inserting a child
11286 * actor in the list of children of @self, and ensures that the
11287 * #ClutterActor::destroy signal is emitted on each child of the
11290 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11291 * when its reference count drops to 0; the default handler of the
11292 * #ClutterActor::destroy signal will destroy all the children of an
11293 * actor. This function ensures that all children are destroyed, instead
11294 * of just removed from @self, unlike clutter_actor_remove_all_children()
11295 * which will merely release the reference and remove each child.
11297 * Unless you acquired an additional reference on each child of @self
11298 * prior to calling clutter_actor_remove_all_children() and want to reuse
11299 * the actors, you should use clutter_actor_destroy_all_children() in
11300 * order to make sure that children are destroyed and signal handlers
11301 * are disconnected even in cases where circular references prevent this
11302 * from automatically happening through reference counting alone.
11307 clutter_actor_destroy_all_children (ClutterActor *self)
11309 ClutterActorIter iter;
11311 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11313 if (self->priv->n_children == 0)
11316 g_object_freeze_notify (G_OBJECT (self));
11318 clutter_actor_iter_init (&iter, self);
11319 while (clutter_actor_iter_next (&iter, NULL))
11320 clutter_actor_iter_destroy (&iter);
11322 g_object_thaw_notify (G_OBJECT (self));
11325 g_assert (self->priv->first_child == NULL);
11326 g_assert (self->priv->last_child == NULL);
11327 g_assert (self->priv->n_children == 0);
11330 typedef struct _InsertBetweenData {
11331 ClutterActor *prev_sibling;
11332 ClutterActor *next_sibling;
11333 } InsertBetweenData;
11336 insert_child_between (ClutterActor *self,
11337 ClutterActor *child,
11340 InsertBetweenData *data = data_;
11341 ClutterActor *prev_sibling = data->prev_sibling;
11342 ClutterActor *next_sibling = data->next_sibling;
11344 child->priv->parent = self;
11345 child->priv->prev_sibling = prev_sibling;
11346 child->priv->next_sibling = next_sibling;
11348 if (prev_sibling != NULL)
11349 prev_sibling->priv->next_sibling = child;
11351 if (next_sibling != NULL)
11352 next_sibling->priv->prev_sibling = child;
11354 if (child->priv->prev_sibling == NULL)
11355 self->priv->first_child = child;
11357 if (child->priv->next_sibling == NULL)
11358 self->priv->last_child = child;
11362 * clutter_actor_replace_child:
11363 * @self: a #ClutterActor
11364 * @old_child: the child of @self to replace
11365 * @new_child: the #ClutterActor to replace @old_child
11367 * Replaces @old_child with @new_child in the list of children of @self.
11372 clutter_actor_replace_child (ClutterActor *self,
11373 ClutterActor *old_child,
11374 ClutterActor *new_child)
11376 ClutterActor *prev_sibling, *next_sibling;
11377 InsertBetweenData clos;
11379 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11380 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11381 g_return_if_fail (old_child->priv->parent == self);
11382 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11383 g_return_if_fail (old_child != new_child);
11384 g_return_if_fail (new_child != self);
11385 g_return_if_fail (new_child->priv->parent == NULL);
11387 prev_sibling = old_child->priv->prev_sibling;
11388 next_sibling = old_child->priv->next_sibling;
11389 clutter_actor_remove_child_internal (self, old_child,
11390 REMOVE_CHILD_DEFAULT_FLAGS);
11392 clos.prev_sibling = prev_sibling;
11393 clos.next_sibling = next_sibling;
11394 clutter_actor_add_child_internal (self, new_child,
11395 ADD_CHILD_DEFAULT_FLAGS,
11396 insert_child_between,
11401 * clutter_actor_unparent:
11402 * @self: a #ClutterActor
11404 * Removes the parent of @self.
11406 * This will cause the parent of @self to release the reference
11407 * acquired when calling clutter_actor_set_parent(), so if you
11408 * want to keep @self you will have to acquire a reference of
11409 * your own, through g_object_ref().
11411 * This function should only be called by legacy #ClutterActor<!-- -->s
11412 * implementing the #ClutterContainer interface.
11416 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11419 clutter_actor_unparent (ClutterActor *self)
11421 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11423 if (self->priv->parent == NULL)
11426 clutter_actor_remove_child_internal (self->priv->parent, self,
11427 REMOVE_CHILD_LEGACY_FLAGS);
11431 * clutter_actor_reparent:
11432 * @self: a #ClutterActor
11433 * @new_parent: the new #ClutterActor parent
11435 * Resets the parent actor of @self.
11437 * This function is logically equivalent to calling clutter_actor_unparent()
11438 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11439 * ensures the child is not finalized when unparented, and emits the
11440 * #ClutterActor::parent-set signal only once.
11442 * In reality, calling this function is less useful than it sounds, as some
11443 * application code may rely on changes in the intermediate state between
11444 * removal and addition of the actor from its old parent to the @new_parent.
11445 * Thus, it is strongly encouraged to avoid using this function in application
11450 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11451 * clutter_actor_add_child() instead; remember to take a reference on
11452 * the actor being removed before calling clutter_actor_remove_child()
11453 * to avoid the reference count dropping to zero and the actor being
11457 clutter_actor_reparent (ClutterActor *self,
11458 ClutterActor *new_parent)
11460 ClutterActorPrivate *priv;
11462 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11463 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11464 g_return_if_fail (self != new_parent);
11466 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11468 g_warning ("Cannot set a parent on a toplevel actor");
11472 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11474 g_warning ("Cannot set a parent currently being destroyed");
11480 if (priv->parent != new_parent)
11482 ClutterActor *old_parent;
11484 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11486 old_parent = priv->parent;
11488 g_object_ref (self);
11490 if (old_parent != NULL)
11492 /* go through the Container implementation if this is a regular
11493 * child and not an internal one
11495 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11497 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11499 /* this will have to call unparent() */
11500 clutter_container_remove_actor (parent, self);
11503 clutter_actor_remove_child_internal (old_parent, self,
11504 REMOVE_CHILD_LEGACY_FLAGS);
11507 /* Note, will call set_parent() */
11508 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11509 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11511 clutter_actor_add_child_internal (new_parent, self,
11512 ADD_CHILD_LEGACY_FLAGS,
11513 insert_child_at_depth,
11516 /* we emit the ::parent-set signal once */
11517 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11519 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11521 /* the IN_REPARENT flag suspends state updates */
11522 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11524 g_object_unref (self);
11529 * clutter_actor_contains:
11530 * @self: A #ClutterActor
11531 * @descendant: A #ClutterActor, possibly contained in @self
11533 * Determines if @descendant is contained inside @self (either as an
11534 * immediate child, or as a deeper descendant). If @self and
11535 * @descendant point to the same actor then it will also return %TRUE.
11537 * Return value: whether @descendent is contained within @self
11542 clutter_actor_contains (ClutterActor *self,
11543 ClutterActor *descendant)
11545 ClutterActor *actor;
11547 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11548 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11550 for (actor = descendant; actor; actor = actor->priv->parent)
11558 * clutter_actor_set_child_above_sibling:
11559 * @self: a #ClutterActor
11560 * @child: a #ClutterActor child of @self
11561 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11563 * Sets @child to be above @sibling in the list of children of @self.
11565 * If @sibling is %NULL, @child will be the new last child of @self.
11567 * This function is logically equivalent to removing @child and using
11568 * clutter_actor_insert_child_above(), but it will not emit signals
11569 * or change state on @child.
11574 clutter_actor_set_child_above_sibling (ClutterActor *self,
11575 ClutterActor *child,
11576 ClutterActor *sibling)
11578 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11579 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11580 g_return_if_fail (child->priv->parent == self);
11581 g_return_if_fail (child != sibling);
11582 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11584 if (sibling != NULL)
11585 g_return_if_fail (sibling->priv->parent == self);
11587 /* we don't want to change the state of child, or emit signals, or
11588 * regenerate ChildMeta instances here, but we still want to follow
11589 * the correct sequence of steps encoded in remove_child() and
11590 * add_child(), so that correctness is ensured, and we only go
11591 * through one known code path.
11593 g_object_ref (child);
11594 clutter_actor_remove_child_internal (self, child, 0);
11595 clutter_actor_add_child_internal (self, child,
11596 ADD_CHILD_NOTIFY_FIRST_LAST,
11597 insert_child_above,
11600 clutter_actor_queue_relayout (self);
11604 * clutter_actor_set_child_below_sibling:
11605 * @self: a #ClutterActor
11606 * @child: a #ClutterActor child of @self
11607 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11609 * Sets @child to be below @sibling in the list of children of @self.
11611 * If @sibling is %NULL, @child will be the new first child of @self.
11613 * This function is logically equivalent to removing @self and using
11614 * clutter_actor_insert_child_below(), but it will not emit signals
11615 * or change state on @child.
11620 clutter_actor_set_child_below_sibling (ClutterActor *self,
11621 ClutterActor *child,
11622 ClutterActor *sibling)
11624 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11625 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11626 g_return_if_fail (child->priv->parent == self);
11627 g_return_if_fail (child != sibling);
11628 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11630 if (sibling != NULL)
11631 g_return_if_fail (sibling->priv->parent == self);
11633 /* see the comment in set_child_above_sibling() */
11634 g_object_ref (child);
11635 clutter_actor_remove_child_internal (self, child, 0);
11636 clutter_actor_add_child_internal (self, child,
11637 ADD_CHILD_NOTIFY_FIRST_LAST,
11638 insert_child_below,
11641 clutter_actor_queue_relayout (self);
11645 * clutter_actor_set_child_at_index:
11646 * @self: a #ClutterActor
11647 * @child: a #ClutterActor child of @self
11648 * @index_: the new index for @child
11650 * Changes the index of @child in the list of children of @self.
11652 * This function is logically equivalent to removing @child and
11653 * calling clutter_actor_insert_child_at_index(), but it will not
11654 * emit signals or change state on @child.
11659 clutter_actor_set_child_at_index (ClutterActor *self,
11660 ClutterActor *child,
11663 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11664 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11665 g_return_if_fail (child->priv->parent == self);
11666 g_return_if_fail (index_ <= self->priv->n_children);
11668 g_object_ref (child);
11669 clutter_actor_remove_child_internal (self, child, 0);
11670 clutter_actor_add_child_internal (self, child,
11671 ADD_CHILD_NOTIFY_FIRST_LAST,
11672 insert_child_at_index,
11673 GINT_TO_POINTER (index_));
11675 clutter_actor_queue_relayout (self);
11679 * clutter_actor_raise:
11680 * @self: A #ClutterActor
11681 * @below: (allow-none): A #ClutterActor to raise above.
11683 * Puts @self above @below.
11685 * Both actors must have the same parent, and the parent must implement
11686 * the #ClutterContainer interface
11688 * This function calls clutter_container_raise_child() internally.
11690 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11693 clutter_actor_raise (ClutterActor *self,
11694 ClutterActor *below)
11696 ClutterActor *parent;
11698 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11700 parent = clutter_actor_get_parent (self);
11701 if (parent == NULL)
11703 g_warning ("%s: Actor '%s' is not inside a container",
11705 _clutter_actor_get_debug_name (self));
11711 if (parent != clutter_actor_get_parent (below))
11713 g_warning ("%s Actor '%s' is not in the same container as "
11716 _clutter_actor_get_debug_name (self),
11717 _clutter_actor_get_debug_name (below));
11722 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11726 * clutter_actor_lower:
11727 * @self: A #ClutterActor
11728 * @above: (allow-none): A #ClutterActor to lower below
11730 * Puts @self below @above.
11732 * Both actors must have the same parent, and the parent must implement
11733 * the #ClutterContainer interface.
11735 * This function calls clutter_container_lower_child() internally.
11737 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11740 clutter_actor_lower (ClutterActor *self,
11741 ClutterActor *above)
11743 ClutterActor *parent;
11745 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11747 parent = clutter_actor_get_parent (self);
11748 if (parent == NULL)
11750 g_warning ("%s: Actor of type %s is not inside a container",
11752 _clutter_actor_get_debug_name (self));
11758 if (parent != clutter_actor_get_parent (above))
11760 g_warning ("%s: Actor '%s' is not in the same container as "
11763 _clutter_actor_get_debug_name (self),
11764 _clutter_actor_get_debug_name (above));
11769 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11773 * clutter_actor_raise_top:
11774 * @self: A #ClutterActor
11776 * Raises @self to the top.
11778 * This function calls clutter_actor_raise() internally.
11780 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11781 * a %NULL sibling, instead.
11784 clutter_actor_raise_top (ClutterActor *self)
11786 clutter_actor_raise (self, NULL);
11790 * clutter_actor_lower_bottom:
11791 * @self: A #ClutterActor
11793 * Lowers @self to the bottom.
11795 * This function calls clutter_actor_lower() internally.
11797 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11798 * a %NULL sibling, instead.
11801 clutter_actor_lower_bottom (ClutterActor *self)
11803 clutter_actor_lower (self, NULL);
11811 * clutter_actor_event:
11812 * @actor: a #ClutterActor
11813 * @event: a #ClutterEvent
11814 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11816 * This function is used to emit an event on the main stage.
11817 * You should rarely need to use this function, except for
11818 * synthetising events.
11820 * Return value: the return value from the signal emission: %TRUE
11821 * if the actor handled the event, or %FALSE if the event was
11827 clutter_actor_event (ClutterActor *actor,
11828 ClutterEvent *event,
11831 gboolean retval = FALSE;
11832 gint signal_num = -1;
11834 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11835 g_return_val_if_fail (event != NULL, FALSE);
11837 g_object_ref (actor);
11841 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11847 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11851 switch (event->type)
11853 case CLUTTER_NOTHING:
11855 case CLUTTER_BUTTON_PRESS:
11856 signal_num = BUTTON_PRESS_EVENT;
11858 case CLUTTER_BUTTON_RELEASE:
11859 signal_num = BUTTON_RELEASE_EVENT;
11861 case CLUTTER_SCROLL:
11862 signal_num = SCROLL_EVENT;
11864 case CLUTTER_KEY_PRESS:
11865 signal_num = KEY_PRESS_EVENT;
11867 case CLUTTER_KEY_RELEASE:
11868 signal_num = KEY_RELEASE_EVENT;
11870 case CLUTTER_MOTION:
11871 signal_num = MOTION_EVENT;
11873 case CLUTTER_ENTER:
11874 signal_num = ENTER_EVENT;
11876 case CLUTTER_LEAVE:
11877 signal_num = LEAVE_EVENT;
11879 case CLUTTER_DELETE:
11880 case CLUTTER_DESTROY_NOTIFY:
11881 case CLUTTER_CLIENT_MESSAGE:
11887 if (signal_num != -1)
11888 g_signal_emit (actor, actor_signals[signal_num], 0,
11893 g_object_unref (actor);
11899 * clutter_actor_set_reactive:
11900 * @actor: a #ClutterActor
11901 * @reactive: whether the actor should be reactive to events
11903 * Sets @actor as reactive. Reactive actors will receive events.
11908 clutter_actor_set_reactive (ClutterActor *actor,
11911 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11913 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11917 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11919 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11921 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11925 * clutter_actor_get_reactive:
11926 * @actor: a #ClutterActor
11928 * Checks whether @actor is marked as reactive.
11930 * Return value: %TRUE if the actor is reactive
11935 clutter_actor_get_reactive (ClutterActor *actor)
11937 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11939 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11943 * clutter_actor_get_anchor_point:
11944 * @self: a #ClutterActor
11945 * @anchor_x: (out): return location for the X coordinate of the anchor point
11946 * @anchor_y: (out): return location for the Y coordinate of the anchor point
11948 * Gets the current anchor point of the @actor in pixels.
11953 clutter_actor_get_anchor_point (ClutterActor *self,
11957 const ClutterTransformInfo *info;
11959 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11961 info = _clutter_actor_get_transform_info_or_defaults (self);
11962 clutter_anchor_coord_get_units (self, &info->anchor,
11969 * clutter_actor_set_anchor_point:
11970 * @self: a #ClutterActor
11971 * @anchor_x: X coordinate of the anchor point
11972 * @anchor_y: Y coordinate of the anchor point
11974 * Sets an anchor point for @self. The anchor point is a point in the
11975 * coordinate space of an actor to which the actor position within its
11976 * parent is relative; the default is (0, 0), i.e. the top-left corner
11982 clutter_actor_set_anchor_point (ClutterActor *self,
11986 ClutterTransformInfo *info;
11987 ClutterActorPrivate *priv;
11988 gboolean changed = FALSE;
11989 gfloat old_anchor_x, old_anchor_y;
11992 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11994 obj = G_OBJECT (self);
11996 info = _clutter_actor_get_transform_info (self);
11998 g_object_freeze_notify (obj);
12000 clutter_anchor_coord_get_units (self, &info->anchor,
12005 if (info->anchor.is_fractional)
12006 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12008 if (old_anchor_x != anchor_x)
12010 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12014 if (old_anchor_y != anchor_y)
12016 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12020 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12024 priv->transform_valid = FALSE;
12025 clutter_actor_queue_redraw (self);
12028 g_object_thaw_notify (obj);
12032 * clutter_actor_get_anchor_point_gravity:
12033 * @self: a #ClutterActor
12035 * Retrieves the anchor position expressed as a #ClutterGravity. If
12036 * the anchor point was specified using pixels or units this will
12037 * return %CLUTTER_GRAVITY_NONE.
12039 * Return value: the #ClutterGravity used by the anchor point
12044 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12046 const ClutterTransformInfo *info;
12048 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12050 info = _clutter_actor_get_transform_info_or_defaults (self);
12052 return clutter_anchor_coord_get_gravity (&info->anchor);
12056 * clutter_actor_move_anchor_point:
12057 * @self: a #ClutterActor
12058 * @anchor_x: X coordinate of the anchor point
12059 * @anchor_y: Y coordinate of the anchor point
12061 * Sets an anchor point for the actor, and adjusts the actor postion so that
12062 * the relative position of the actor toward its parent remains the same.
12067 clutter_actor_move_anchor_point (ClutterActor *self,
12071 gfloat old_anchor_x, old_anchor_y;
12072 const ClutterTransformInfo *info;
12074 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12076 info = _clutter_actor_get_transform_info (self);
12077 clutter_anchor_coord_get_units (self, &info->anchor,
12082 g_object_freeze_notify (G_OBJECT (self));
12084 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12086 if (self->priv->position_set)
12087 clutter_actor_move_by (self,
12088 anchor_x - old_anchor_x,
12089 anchor_y - old_anchor_y);
12091 g_object_thaw_notify (G_OBJECT (self));
12095 * clutter_actor_move_anchor_point_from_gravity:
12096 * @self: a #ClutterActor
12097 * @gravity: #ClutterGravity.
12099 * Sets an anchor point on the actor based on the given gravity, adjusting the
12100 * actor postion so that its relative position within its parent remains
12103 * Since version 1.0 the anchor point will be stored as a gravity so
12104 * that if the actor changes size then the anchor point will move. For
12105 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12106 * and later double the size of the actor, the anchor point will move
12107 * to the bottom right.
12112 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12113 ClutterGravity gravity)
12115 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12116 const ClutterTransformInfo *info;
12117 ClutterActorPrivate *priv;
12119 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12122 info = _clutter_actor_get_transform_info (self);
12124 g_object_freeze_notify (G_OBJECT (self));
12126 clutter_anchor_coord_get_units (self, &info->anchor,
12130 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12131 clutter_anchor_coord_get_units (self, &info->anchor,
12136 if (priv->position_set)
12137 clutter_actor_move_by (self,
12138 new_anchor_x - old_anchor_x,
12139 new_anchor_y - old_anchor_y);
12141 g_object_thaw_notify (G_OBJECT (self));
12145 * clutter_actor_set_anchor_point_from_gravity:
12146 * @self: a #ClutterActor
12147 * @gravity: #ClutterGravity.
12149 * Sets an anchor point on the actor, based on the given gravity (this is a
12150 * convenience function wrapping clutter_actor_set_anchor_point()).
12152 * Since version 1.0 the anchor point will be stored as a gravity so
12153 * that if the actor changes size then the anchor point will move. For
12154 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12155 * and later double the size of the actor, the anchor point will move
12156 * to the bottom right.
12161 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12162 ClutterGravity gravity)
12164 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12166 if (gravity == CLUTTER_GRAVITY_NONE)
12167 clutter_actor_set_anchor_point (self, 0, 0);
12170 GObject *obj = G_OBJECT (self);
12171 ClutterTransformInfo *info;
12173 g_object_freeze_notify (obj);
12175 info = _clutter_actor_get_transform_info (self);
12176 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12178 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12179 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12180 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12182 self->priv->transform_valid = FALSE;
12184 clutter_actor_queue_redraw (self);
12186 g_object_thaw_notify (obj);
12191 clutter_container_iface_init (ClutterContainerIface *iface)
12193 /* we don't override anything, as ClutterContainer already has a default
12194 * implementation that we can use, and which calls into our own API.
12209 parse_units (ClutterActor *self,
12210 ParseDimension dimension,
12213 GValue value = { 0, };
12216 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12219 json_node_get_value (node, &value);
12221 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12223 retval = (gfloat) g_value_get_int64 (&value);
12225 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12227 retval = g_value_get_double (&value);
12229 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12231 ClutterUnits units;
12234 res = clutter_units_from_string (&units, g_value_get_string (&value));
12236 retval = clutter_units_to_pixels (&units);
12239 g_warning ("Invalid value '%s': integers, strings or floating point "
12240 "values can be used for the x, y, width and height "
12241 "properties. Valid modifiers for strings are 'px', 'mm', "
12243 g_value_get_string (&value));
12249 g_warning ("Invalid value of type '%s': integers, strings of floating "
12250 "point values can be used for the x, y, width, height "
12251 "anchor-x and anchor-y properties.",
12252 g_type_name (G_VALUE_TYPE (&value)));
12255 g_value_unset (&value);
12261 ClutterRotateAxis axis;
12270 static inline gboolean
12271 parse_rotation_array (ClutterActor *actor,
12273 RotationInfo *info)
12277 if (json_array_get_length (array) != 2)
12281 element = json_array_get_element (array, 0);
12282 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12283 info->angle = json_node_get_double (element);
12288 element = json_array_get_element (array, 1);
12289 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12291 JsonArray *center = json_node_get_array (element);
12293 if (json_array_get_length (center) != 2)
12296 switch (info->axis)
12298 case CLUTTER_X_AXIS:
12299 info->center_y = parse_units (actor, PARSE_Y,
12300 json_array_get_element (center, 0));
12301 info->center_z = parse_units (actor, PARSE_Y,
12302 json_array_get_element (center, 1));
12305 case CLUTTER_Y_AXIS:
12306 info->center_x = parse_units (actor, PARSE_X,
12307 json_array_get_element (center, 0));
12308 info->center_z = parse_units (actor, PARSE_X,
12309 json_array_get_element (center, 1));
12312 case CLUTTER_Z_AXIS:
12313 info->center_x = parse_units (actor, PARSE_X,
12314 json_array_get_element (center, 0));
12315 info->center_y = parse_units (actor, PARSE_Y,
12316 json_array_get_element (center, 1));
12325 parse_rotation (ClutterActor *actor,
12327 RotationInfo *info)
12331 gboolean retval = FALSE;
12333 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12335 g_warning ("Invalid node of type '%s' found, expecting an array",
12336 json_node_type_name (node));
12340 array = json_node_get_array (node);
12341 len = json_array_get_length (array);
12343 for (i = 0; i < len; i++)
12345 JsonNode *element = json_array_get_element (array, i);
12346 JsonObject *object;
12349 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12351 g_warning ("Invalid node of type '%s' found, expecting an object",
12352 json_node_type_name (element));
12356 object = json_node_get_object (element);
12358 if (json_object_has_member (object, "x-axis"))
12360 member = json_object_get_member (object, "x-axis");
12362 info->axis = CLUTTER_X_AXIS;
12364 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12366 info->angle = json_node_get_double (member);
12369 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12370 retval = parse_rotation_array (actor,
12371 json_node_get_array (member),
12376 else if (json_object_has_member (object, "y-axis"))
12378 member = json_object_get_member (object, "y-axis");
12380 info->axis = CLUTTER_Y_AXIS;
12382 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12384 info->angle = json_node_get_double (member);
12387 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12388 retval = parse_rotation_array (actor,
12389 json_node_get_array (member),
12394 else if (json_object_has_member (object, "z-axis"))
12396 member = json_object_get_member (object, "z-axis");
12398 info->axis = CLUTTER_Z_AXIS;
12400 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12402 info->angle = json_node_get_double (member);
12405 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12406 retval = parse_rotation_array (actor,
12407 json_node_get_array (member),
12418 parse_actor_metas (ClutterScript *script,
12419 ClutterActor *actor,
12422 GList *elements, *l;
12423 GSList *retval = NULL;
12425 if (!JSON_NODE_HOLDS_ARRAY (node))
12428 elements = json_array_get_elements (json_node_get_array (node));
12430 for (l = elements; l != NULL; l = l->next)
12432 JsonNode *element = l->data;
12433 const gchar *id_ = _clutter_script_get_id_from_node (element);
12436 if (id_ == NULL || *id_ == '\0')
12439 meta = clutter_script_get_object (script, id_);
12443 retval = g_slist_prepend (retval, meta);
12446 g_list_free (elements);
12448 return g_slist_reverse (retval);
12452 parse_behaviours (ClutterScript *script,
12453 ClutterActor *actor,
12456 GList *elements, *l;
12457 GSList *retval = NULL;
12459 if (!JSON_NODE_HOLDS_ARRAY (node))
12462 elements = json_array_get_elements (json_node_get_array (node));
12464 for (l = elements; l != NULL; l = l->next)
12466 JsonNode *element = l->data;
12467 const gchar *id_ = _clutter_script_get_id_from_node (element);
12468 GObject *behaviour;
12470 if (id_ == NULL || *id_ == '\0')
12473 behaviour = clutter_script_get_object (script, id_);
12474 if (behaviour == NULL)
12477 retval = g_slist_prepend (retval, behaviour);
12480 g_list_free (elements);
12482 return g_slist_reverse (retval);
12486 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12487 ClutterScript *script,
12492 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12493 gboolean retval = FALSE;
12495 if ((name[0] == 'x' && name[1] == '\0') ||
12496 (name[0] == 'y' && name[1] == '\0') ||
12497 (strcmp (name, "width") == 0) ||
12498 (strcmp (name, "height") == 0) ||
12499 (strcmp (name, "anchor_x") == 0) ||
12500 (strcmp (name, "anchor_y") == 0))
12502 ParseDimension dimension;
12505 if (name[0] == 'x')
12506 dimension = PARSE_X;
12507 else if (name[0] == 'y')
12508 dimension = PARSE_Y;
12509 else if (name[0] == 'w')
12510 dimension = PARSE_WIDTH;
12511 else if (name[0] == 'h')
12512 dimension = PARSE_HEIGHT;
12513 else if (name[0] == 'a' && name[7] == 'x')
12514 dimension = PARSE_ANCHOR_X;
12515 else if (name[0] == 'a' && name[7] == 'y')
12516 dimension = PARSE_ANCHOR_Y;
12520 units = parse_units (actor, dimension, node);
12522 /* convert back to pixels: all properties are pixel-based */
12523 g_value_init (value, G_TYPE_FLOAT);
12524 g_value_set_float (value, units);
12528 else if (strcmp (name, "rotation") == 0)
12530 RotationInfo *info;
12532 info = g_slice_new0 (RotationInfo);
12533 retval = parse_rotation (actor, node, info);
12537 g_value_init (value, G_TYPE_POINTER);
12538 g_value_set_pointer (value, info);
12541 g_slice_free (RotationInfo, info);
12543 else if (strcmp (name, "behaviours") == 0)
12547 #ifdef CLUTTER_ENABLE_DEBUG
12548 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12549 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12550 "and it should not be used in newly "
12551 "written ClutterScript definitions.");
12554 l = parse_behaviours (script, actor, node);
12556 g_value_init (value, G_TYPE_POINTER);
12557 g_value_set_pointer (value, l);
12561 else if (strcmp (name, "actions") == 0 ||
12562 strcmp (name, "constraints") == 0 ||
12563 strcmp (name, "effects") == 0)
12567 l = parse_actor_metas (script, actor, node);
12569 g_value_init (value, G_TYPE_POINTER);
12570 g_value_set_pointer (value, l);
12579 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12580 ClutterScript *script,
12582 const GValue *value)
12584 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12586 #ifdef CLUTTER_ENABLE_DEBUG
12587 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12589 gchar *tmp = g_strdup_value_contents (value);
12591 CLUTTER_NOTE (SCRIPT,
12592 "in ClutterActor::set_custom_property('%s') = %s",
12598 #endif /* CLUTTER_ENABLE_DEBUG */
12600 if (strcmp (name, "rotation") == 0)
12602 RotationInfo *info;
12604 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12607 info = g_value_get_pointer (value);
12609 clutter_actor_set_rotation (actor,
12610 info->axis, info->angle,
12615 g_slice_free (RotationInfo, info);
12620 if (strcmp (name, "behaviours") == 0)
12622 GSList *behaviours, *l;
12624 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12627 behaviours = g_value_get_pointer (value);
12628 for (l = behaviours; l != NULL; l = l->next)
12630 ClutterBehaviour *behaviour = l->data;
12632 clutter_behaviour_apply (behaviour, actor);
12635 g_slist_free (behaviours);
12640 if (strcmp (name, "actions") == 0 ||
12641 strcmp (name, "constraints") == 0 ||
12642 strcmp (name, "effects") == 0)
12646 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12649 metas = g_value_get_pointer (value);
12650 for (l = metas; l != NULL; l = l->next)
12652 if (name[0] == 'a')
12653 clutter_actor_add_action (actor, l->data);
12655 if (name[0] == 'c')
12656 clutter_actor_add_constraint (actor, l->data);
12658 if (name[0] == 'e')
12659 clutter_actor_add_effect (actor, l->data);
12662 g_slist_free (metas);
12667 g_object_set_property (G_OBJECT (scriptable), name, value);
12671 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12673 iface->parse_custom_node = clutter_actor_parse_custom_node;
12674 iface->set_custom_property = clutter_actor_set_custom_property;
12677 static ClutterActorMeta *
12678 get_meta_from_animation_property (ClutterActor *actor,
12682 ClutterActorPrivate *priv = actor->priv;
12683 ClutterActorMeta *meta = NULL;
12686 /* if this is not a special property, fall through */
12687 if (name[0] != '@')
12690 /* detect the properties named using the following spec:
12692 * @<section>.<meta-name>.<property-name>
12694 * where <section> can be one of the following:
12700 * and <meta-name> is the name set on a specific ActorMeta
12703 tokens = g_strsplit (name + 1, ".", -1);
12704 if (tokens == NULL || g_strv_length (tokens) != 3)
12706 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12708 g_strfreev (tokens);
12712 if (strcmp (tokens[0], "actions") == 0)
12713 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12715 if (strcmp (tokens[0], "constraints") == 0)
12716 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12718 if (strcmp (tokens[0], "effects") == 0)
12719 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12721 if (name_p != NULL)
12722 *name_p = g_strdup (tokens[2]);
12724 CLUTTER_NOTE (ANIMATION,
12725 "Looking for property '%s' of object '%s' in section '%s'",
12730 g_strfreev (tokens);
12735 static GParamSpec *
12736 clutter_actor_find_property (ClutterAnimatable *animatable,
12737 const gchar *property_name)
12739 ClutterActorMeta *meta = NULL;
12740 GObjectClass *klass = NULL;
12741 GParamSpec *pspec = NULL;
12742 gchar *p_name = NULL;
12744 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12750 klass = G_OBJECT_GET_CLASS (meta);
12752 pspec = g_object_class_find_property (klass, p_name);
12756 klass = G_OBJECT_GET_CLASS (animatable);
12758 pspec = g_object_class_find_property (klass, property_name);
12767 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12768 const gchar *property_name,
12771 ClutterActorMeta *meta = NULL;
12772 gchar *p_name = NULL;
12774 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12779 g_object_get_property (G_OBJECT (meta), p_name, initial);
12781 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12787 * clutter_actor_set_animatable_property:
12788 * @actor: a #ClutterActor
12789 * @prop_id: the paramspec id
12790 * @value: the value to set
12791 * @pspec: the paramspec
12793 * Sets values of animatable properties.
12795 * This is a variant of clutter_actor_set_property() that gets called
12796 * by the #ClutterAnimatable implementation of #ClutterActor for the
12797 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12800 * Unlike the implementation of #GObjectClass.set_property(), this
12801 * function will not update the interval if a transition involving an
12802 * animatable property is in progress - this avoids cycles with the
12803 * transition API calling the public API.
12806 clutter_actor_set_animatable_property (ClutterActor *actor,
12808 const GValue *value,
12814 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12818 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12822 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12826 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12830 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12834 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12837 case PROP_BACKGROUND_COLOR:
12838 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12842 clutter_actor_set_scale_factor_internal (actor,
12843 g_value_get_double (value),
12848 clutter_actor_set_scale_factor_internal (actor,
12849 g_value_get_double (value),
12853 case PROP_ROTATION_ANGLE_X:
12854 clutter_actor_set_rotation_angle_internal (actor,
12856 g_value_get_double (value));
12859 case PROP_ROTATION_ANGLE_Y:
12860 clutter_actor_set_rotation_angle_internal (actor,
12862 g_value_get_double (value));
12865 case PROP_ROTATION_ANGLE_Z:
12866 clutter_actor_set_rotation_angle_internal (actor,
12868 g_value_get_double (value));
12872 g_object_set_property (G_OBJECT (actor), pspec->name, value);
12878 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12879 const gchar *property_name,
12880 const GValue *final)
12882 ClutterActor *actor = CLUTTER_ACTOR (animatable);
12883 ClutterActorMeta *meta = NULL;
12884 gchar *p_name = NULL;
12886 meta = get_meta_from_animation_property (actor,
12890 g_object_set_property (G_OBJECT (meta), p_name, final);
12893 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12896 pspec = g_object_class_find_property (obj_class, property_name);
12898 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12900 /* XXX - I'm going to the special hell for this */
12901 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12904 g_object_set_property (G_OBJECT (animatable), property_name, final);
12911 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12913 iface->find_property = clutter_actor_find_property;
12914 iface->get_initial_state = clutter_actor_get_initial_state;
12915 iface->set_final_state = clutter_actor_set_final_state;
12919 * clutter_actor_transform_stage_point:
12920 * @self: A #ClutterActor
12921 * @x: (in): x screen coordinate of the point to unproject
12922 * @y: (in): y screen coordinate of the point to unproject
12923 * @x_out: (out): return location for the unprojected x coordinance
12924 * @y_out: (out): return location for the unprojected y coordinance
12926 * This function translates screen coordinates (@x, @y) to
12927 * coordinates relative to the actor. For example, it can be used to translate
12928 * screen events from global screen coordinates into actor-local coordinates.
12930 * The conversion can fail, notably if the transform stack results in the
12931 * actor being projected on the screen as a mere line.
12933 * The conversion should not be expected to be pixel-perfect due to the
12934 * nature of the operation. In general the error grows when the skewing
12935 * of the actor rectangle on screen increases.
12937 * <note><para>This function can be computationally intensive.</para></note>
12939 * <note><para>This function only works when the allocation is up-to-date,
12940 * i.e. inside of paint().</para></note>
12942 * Return value: %TRUE if conversion was successful.
12947 clutter_actor_transform_stage_point (ClutterActor *self,
12953 ClutterVertex v[4];
12956 int du, dv, xi, yi;
12958 float xf, yf, wf, det;
12959 ClutterActorPrivate *priv;
12961 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12965 /* This implementation is based on the quad -> quad projection algorithm
12966 * described by Paul Heckbert in:
12968 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12970 * and the sample implementation at:
12972 * http://www.cs.cmu.edu/~ph/src/texfund/
12974 * Our texture is a rectangle with origin [0, 0], so we are mapping from
12975 * quad to rectangle only, which significantly simplifies things; the
12976 * function calls have been unrolled, and most of the math is done in fixed
12980 clutter_actor_get_abs_allocation_vertices (self, v);
12982 /* Keeping these as ints simplifies the multiplication (no significant
12983 * loss of precision here).
12985 du = (int) (priv->allocation.x2 - priv->allocation.x1);
12986 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12991 #define UX2FP(x) (x)
12992 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12994 /* First, find mapping from unit uv square to xy quadrilateral; this
12995 * equivalent to the pmap_square_quad() functions in the sample
12996 * implementation, which we can simplify, since our target is always
12999 px = v[0].x - v[1].x + v[3].x - v[2].x;
13000 py = v[0].y - v[1].y + v[3].y - v[2].y;
13004 /* affine transform */
13005 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13006 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13007 RQ[2][0] = UX2FP (v[0].x);
13008 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13009 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13010 RQ[2][1] = UX2FP (v[0].y);
13017 /* projective transform */
13018 double dx1, dx2, dy1, dy2, del;
13020 dx1 = UX2FP (v[1].x - v[3].x);
13021 dx2 = UX2FP (v[2].x - v[3].x);
13022 dy1 = UX2FP (v[1].y - v[3].y);
13023 dy2 = UX2FP (v[2].y - v[3].y);
13025 del = DET2FP (dx1, dx2, dy1, dy2);
13030 * The division here needs to be done in floating point for
13031 * precisions reasons.
13033 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13034 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13035 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13037 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13038 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13039 RQ[2][0] = UX2FP (v[0].x);
13040 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13041 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13042 RQ[2][1] = UX2FP (v[0].y);
13046 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13047 * square. Since our rectangle is based at 0,0 we only need to scale.
13057 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13060 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13061 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13062 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13063 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13064 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13065 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13066 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13067 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13068 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13071 * Check the resulting matrix is OK.
13073 det = (RQ[0][0] * ST[0][0])
13074 + (RQ[0][1] * ST[0][1])
13075 + (RQ[0][2] * ST[0][2]);
13080 * Now transform our point with the ST matrix; the notional w
13081 * coordinate is 1, hence the last part is simply added.
13086 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13087 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13088 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13106 static ClutterGeometry*
13107 clutter_geometry_copy (const ClutterGeometry *geometry)
13109 return g_slice_dup (ClutterGeometry, geometry);
13113 clutter_geometry_free (ClutterGeometry *geometry)
13115 if (G_LIKELY (geometry != NULL))
13116 g_slice_free (ClutterGeometry, geometry);
13120 * clutter_geometry_union:
13121 * @geometry_a: a #ClutterGeometry
13122 * @geometry_b: another #ClutterGeometry
13123 * @result: (out): location to store the result
13125 * Find the union of two rectangles represented as #ClutterGeometry.
13130 clutter_geometry_union (const ClutterGeometry *geometry_a,
13131 const ClutterGeometry *geometry_b,
13132 ClutterGeometry *result)
13134 /* We don't try to handle rectangles that can't be represented
13135 * as a signed integer box */
13136 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13137 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13138 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13139 geometry_b->x + (gint)geometry_b->width);
13140 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13141 geometry_b->y + (gint)geometry_b->height);
13144 result->width = x_2 - x_1;
13145 result->height = y_2 - y_1;
13149 * clutter_geometry_intersects:
13150 * @geometry0: The first geometry to test
13151 * @geometry1: The second geometry to test
13153 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13154 * they do else %FALSE.
13156 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13162 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13163 const ClutterGeometry *geometry1)
13165 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13166 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13167 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13168 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13175 clutter_geometry_progress (const GValue *a,
13180 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13181 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13182 ClutterGeometry res = { 0, };
13183 gint a_width = a_geom->width;
13184 gint b_width = b_geom->width;
13185 gint a_height = a_geom->height;
13186 gint b_height = b_geom->height;
13188 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13189 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13191 res.width = a_width + (b_width - a_width) * progress;
13192 res.height = a_height + (b_height - a_height) * progress;
13194 g_value_set_boxed (retval, &res);
13199 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13200 clutter_geometry_copy,
13201 clutter_geometry_free,
13202 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13209 * clutter_vertex_new:
13214 * Creates a new #ClutterVertex for the point in 3D space
13215 * identified by the 3 coordinates @x, @y, @z
13217 * Return value: the newly allocate #ClutterVertex. Use
13218 * clutter_vertex_free() to free the resources
13223 clutter_vertex_new (gfloat x,
13227 ClutterVertex *vertex;
13229 vertex = g_slice_new (ClutterVertex);
13238 * clutter_vertex_copy:
13239 * @vertex: a #ClutterVertex
13243 * Return value: a newly allocated copy of #ClutterVertex. Use
13244 * clutter_vertex_free() to free the allocated resources
13249 clutter_vertex_copy (const ClutterVertex *vertex)
13251 if (G_LIKELY (vertex != NULL))
13252 return g_slice_dup (ClutterVertex, vertex);
13258 * clutter_vertex_free:
13259 * @vertex: a #ClutterVertex
13261 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13266 clutter_vertex_free (ClutterVertex *vertex)
13268 if (G_UNLIKELY (vertex != NULL))
13269 g_slice_free (ClutterVertex, vertex);
13273 * clutter_vertex_equal:
13274 * @vertex_a: a #ClutterVertex
13275 * @vertex_b: a #ClutterVertex
13277 * Compares @vertex_a and @vertex_b for equality
13279 * Return value: %TRUE if the passed #ClutterVertex are equal
13284 clutter_vertex_equal (const ClutterVertex *vertex_a,
13285 const ClutterVertex *vertex_b)
13287 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13289 if (vertex_a == vertex_b)
13292 return vertex_a->x == vertex_b->x &&
13293 vertex_a->y == vertex_b->y &&
13294 vertex_a->z == vertex_b->z;
13298 clutter_vertex_progress (const GValue *a,
13303 const ClutterVertex *av = g_value_get_boxed (a);
13304 const ClutterVertex *bv = g_value_get_boxed (b);
13305 ClutterVertex res = { 0, };
13307 res.x = av->x + (bv->x - av->x) * progress;
13308 res.y = av->y + (bv->y - av->y) * progress;
13309 res.z = av->z + (bv->z - av->z) * progress;
13311 g_value_set_boxed (retval, &res);
13316 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13317 clutter_vertex_copy,
13318 clutter_vertex_free,
13319 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13322 * clutter_actor_is_rotated:
13323 * @self: a #ClutterActor
13325 * Checks whether any rotation is applied to the actor.
13327 * Return value: %TRUE if the actor is rotated.
13332 clutter_actor_is_rotated (ClutterActor *self)
13334 const ClutterTransformInfo *info;
13336 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13338 info = _clutter_actor_get_transform_info_or_defaults (self);
13340 if (info->rx_angle || info->ry_angle || info->rz_angle)
13347 * clutter_actor_is_scaled:
13348 * @self: a #ClutterActor
13350 * Checks whether the actor is scaled in either dimension.
13352 * Return value: %TRUE if the actor is scaled.
13357 clutter_actor_is_scaled (ClutterActor *self)
13359 const ClutterTransformInfo *info;
13361 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13363 info = _clutter_actor_get_transform_info_or_defaults (self);
13365 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13372 _clutter_actor_get_stage_internal (ClutterActor *actor)
13374 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13375 actor = actor->priv->parent;
13381 * clutter_actor_get_stage:
13382 * @actor: a #ClutterActor
13384 * Retrieves the #ClutterStage where @actor is contained.
13386 * Return value: (transfer none) (type Clutter.Stage): the stage
13387 * containing the actor, or %NULL
13392 clutter_actor_get_stage (ClutterActor *actor)
13394 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13396 return _clutter_actor_get_stage_internal (actor);
13400 * clutter_actor_allocate_available_size:
13401 * @self: a #ClutterActor
13402 * @x: the actor's X coordinate
13403 * @y: the actor's Y coordinate
13404 * @available_width: the maximum available width, or -1 to use the
13405 * actor's natural width
13406 * @available_height: the maximum available height, or -1 to use the
13407 * actor's natural height
13408 * @flags: flags controlling the allocation
13410 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13411 * preferred size, but limiting it to the maximum available width
13412 * and height provided.
13414 * This function will do the right thing when dealing with the
13415 * actor's request mode.
13417 * The implementation of this function is equivalent to:
13420 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13422 * clutter_actor_get_preferred_width (self, available_height,
13424 * &natural_width);
13425 * width = CLAMP (natural_width, min_width, available_width);
13427 * clutter_actor_get_preferred_height (self, width,
13429 * &natural_height);
13430 * height = CLAMP (natural_height, min_height, available_height);
13434 * clutter_actor_get_preferred_height (self, available_width,
13436 * &natural_height);
13437 * height = CLAMP (natural_height, min_height, available_height);
13439 * clutter_actor_get_preferred_width (self, height,
13441 * &natural_width);
13442 * width = CLAMP (natural_width, min_width, available_width);
13445 * box.x1 = x; box.y1 = y;
13446 * box.x2 = box.x1 + available_width;
13447 * box.y2 = box.y1 + available_height;
13448 * clutter_actor_allocate (self, &box, flags);
13451 * This function can be used by fluid layout managers to allocate
13452 * an actor's preferred size without making it bigger than the area
13453 * available for the container.
13458 clutter_actor_allocate_available_size (ClutterActor *self,
13461 gfloat available_width,
13462 gfloat available_height,
13463 ClutterAllocationFlags flags)
13465 ClutterActorPrivate *priv;
13466 gfloat width, height;
13467 gfloat min_width, min_height;
13468 gfloat natural_width, natural_height;
13469 ClutterActorBox box;
13471 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13475 width = height = 0.0;
13477 switch (priv->request_mode)
13479 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13480 clutter_actor_get_preferred_width (self, available_height,
13483 width = CLAMP (natural_width, min_width, available_width);
13485 clutter_actor_get_preferred_height (self, width,
13488 height = CLAMP (natural_height, min_height, available_height);
13491 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13492 clutter_actor_get_preferred_height (self, available_width,
13495 height = CLAMP (natural_height, min_height, available_height);
13497 clutter_actor_get_preferred_width (self, height,
13500 width = CLAMP (natural_width, min_width, available_width);
13507 box.x2 = box.x1 + width;
13508 box.y2 = box.y1 + height;
13509 clutter_actor_allocate (self, &box, flags);
13513 * clutter_actor_allocate_preferred_size:
13514 * @self: a #ClutterActor
13515 * @flags: flags controlling the allocation
13517 * Allocates the natural size of @self.
13519 * This function is a utility call for #ClutterActor implementations
13520 * that allocates the actor's preferred natural size. It can be used
13521 * by fixed layout managers (like #ClutterGroup or so called
13522 * 'composite actors') inside the ClutterActor::allocate
13523 * implementation to give each child exactly how much space it
13526 * This function is not meant to be used by applications. It is also
13527 * not meant to be used outside the implementation of the
13528 * ClutterActor::allocate virtual function.
13533 clutter_actor_allocate_preferred_size (ClutterActor *self,
13534 ClutterAllocationFlags flags)
13536 gfloat actor_x, actor_y;
13537 gfloat natural_width, natural_height;
13538 ClutterActorBox actor_box;
13540 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13542 actor_x = clutter_actor_get_x (self);
13543 actor_y = clutter_actor_get_y (self);
13545 clutter_actor_get_preferred_size (self,
13550 actor_box.x1 = actor_x;
13551 actor_box.y1 = actor_y;
13552 actor_box.x2 = actor_box.x1 + natural_width;
13553 actor_box.y2 = actor_box.y1 + natural_height;
13555 clutter_actor_allocate (self, &actor_box, flags);
13559 * clutter_actor_allocate_align_fill:
13560 * @self: a #ClutterActor
13561 * @box: a #ClutterActorBox, containing the available width and height
13562 * @x_align: the horizontal alignment, between 0 and 1
13563 * @y_align: the vertical alignment, between 0 and 1
13564 * @x_fill: whether the actor should fill horizontally
13565 * @y_fill: whether the actor should fill vertically
13566 * @flags: allocation flags to be passed to clutter_actor_allocate()
13568 * Allocates @self by taking into consideration the available allocation
13569 * area; an alignment factor on either axis; and whether the actor should
13570 * fill the allocation on either axis.
13572 * The @box should contain the available allocation width and height;
13573 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13574 * allocation will be offset by their value.
13576 * This function takes into consideration the geometry request specified by
13577 * the #ClutterActor:request-mode property, and the text direction.
13579 * This function is useful for fluid layout managers, like #ClutterBinLayout
13580 * or #ClutterTableLayout
13585 clutter_actor_allocate_align_fill (ClutterActor *self,
13586 const ClutterActorBox *box,
13591 ClutterAllocationFlags flags)
13593 ClutterActorPrivate *priv;
13594 ClutterActorBox allocation = { 0, };
13595 gfloat x_offset, y_offset;
13596 gfloat available_width, available_height;
13597 gfloat child_width, child_height;
13599 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13600 g_return_if_fail (box != NULL);
13601 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13602 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13606 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13607 clutter_actor_box_get_size (box, &available_width, &available_height);
13609 if (available_width < 0)
13610 available_width = 0;
13612 if (available_height < 0)
13613 available_height = 0;
13617 allocation.x1 = x_offset;
13618 allocation.x2 = allocation.x1 + available_width;
13623 allocation.y1 = y_offset;
13624 allocation.y2 = allocation.y1 + available_height;
13627 /* if we are filling horizontally and vertically then we're done */
13628 if (x_fill && y_fill)
13631 child_width = child_height = 0.0f;
13633 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13635 gfloat min_width, natural_width;
13636 gfloat min_height, natural_height;
13638 clutter_actor_get_preferred_width (self, available_height,
13642 child_width = CLAMP (natural_width, min_width, available_width);
13646 clutter_actor_get_preferred_height (self, child_width,
13650 child_height = CLAMP (natural_height, min_height, available_height);
13655 gfloat min_width, natural_width;
13656 gfloat min_height, natural_height;
13658 clutter_actor_get_preferred_height (self, available_width,
13662 child_height = CLAMP (natural_height, min_height, available_height);
13666 clutter_actor_get_preferred_width (self, child_height,
13670 child_width = CLAMP (natural_width, min_width, available_width);
13674 /* invert the horizontal alignment for RTL languages */
13675 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13676 x_align = 1.0 - x_align;
13680 allocation.x1 = x_offset
13681 + ((available_width - child_width) * x_align);
13682 allocation.x2 = allocation.x1 + child_width;
13687 allocation.y1 = y_offset
13688 + ((available_height - child_height) * y_align);
13689 allocation.y2 = allocation.y1 + child_height;
13693 clutter_actor_box_clamp_to_pixel (&allocation);
13694 clutter_actor_allocate (self, &allocation, flags);
13698 * clutter_actor_grab_key_focus:
13699 * @self: a #ClutterActor
13701 * Sets the key focus of the #ClutterStage including @self
13702 * to this #ClutterActor.
13707 clutter_actor_grab_key_focus (ClutterActor *self)
13709 ClutterActor *stage;
13711 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13713 stage = _clutter_actor_get_stage_internal (self);
13715 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13719 * clutter_actor_get_pango_context:
13720 * @self: a #ClutterActor
13722 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13723 * is already configured using the appropriate font map, resolution
13724 * and font options.
13726 * Unlike clutter_actor_create_pango_context(), this context is owend
13727 * by the #ClutterActor and it will be updated each time the options
13728 * stored by the #ClutterBackend change.
13730 * You can use the returned #PangoContext to create a #PangoLayout
13731 * and render text using cogl_pango_render_layout() to reuse the
13732 * glyphs cache also used by Clutter.
13734 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13735 * The returned #PangoContext is owned by the actor and should not be
13736 * unreferenced by the application code
13741 clutter_actor_get_pango_context (ClutterActor *self)
13743 ClutterActorPrivate *priv;
13745 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13749 if (priv->pango_context != NULL)
13750 return priv->pango_context;
13752 priv->pango_context = _clutter_context_get_pango_context ();
13753 g_object_ref (priv->pango_context);
13755 return priv->pango_context;
13759 * clutter_actor_create_pango_context:
13760 * @self: a #ClutterActor
13762 * Creates a #PangoContext for the given actor. The #PangoContext
13763 * is already configured using the appropriate font map, resolution
13764 * and font options.
13766 * See also clutter_actor_get_pango_context().
13768 * Return value: (transfer full): the newly created #PangoContext.
13769 * Use g_object_unref() on the returned value to deallocate its
13775 clutter_actor_create_pango_context (ClutterActor *self)
13777 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13779 return _clutter_context_create_pango_context ();
13783 * clutter_actor_create_pango_layout:
13784 * @self: a #ClutterActor
13785 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13787 * Creates a new #PangoLayout from the same #PangoContext used
13788 * by the #ClutterActor. The #PangoLayout is already configured
13789 * with the font map, resolution and font options, and the
13792 * If you want to keep around a #PangoLayout created by this
13793 * function you will have to connect to the #ClutterBackend::font-changed
13794 * and #ClutterBackend::resolution-changed signals, and call
13795 * pango_layout_context_changed() in response to them.
13797 * Return value: (transfer full): the newly created #PangoLayout.
13798 * Use g_object_unref() when done
13803 clutter_actor_create_pango_layout (ClutterActor *self,
13806 PangoContext *context;
13807 PangoLayout *layout;
13809 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13811 context = clutter_actor_get_pango_context (self);
13812 layout = pango_layout_new (context);
13815 pango_layout_set_text (layout, text, -1);
13820 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13821 * ClutterOffscreenEffect.
13824 _clutter_actor_set_opacity_override (ClutterActor *self,
13827 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13829 self->priv->opacity_override = opacity;
13833 _clutter_actor_get_opacity_override (ClutterActor *self)
13835 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13837 return self->priv->opacity_override;
13840 /* Allows you to disable applying the actors model view transform during
13841 * a paint. Used by ClutterClone. */
13843 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13846 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13848 self->priv->enable_model_view_transform = enable;
13852 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13855 ClutterActorPrivate *priv;
13857 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13861 priv->enable_paint_unmapped = enable;
13863 if (priv->enable_paint_unmapped)
13865 /* Make sure that the parents of the widget are realized first;
13866 * otherwise checks in clutter_actor_update_map_state() will
13869 clutter_actor_realize (self);
13871 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13875 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13880 clutter_anchor_coord_get_units (ClutterActor *self,
13881 const AnchorCoord *coord,
13886 if (coord->is_fractional)
13888 gfloat actor_width, actor_height;
13890 clutter_actor_get_size (self, &actor_width, &actor_height);
13893 *x = actor_width * coord->v.fraction.x;
13896 *y = actor_height * coord->v.fraction.y;
13904 *x = coord->v.units.x;
13907 *y = coord->v.units.y;
13910 *z = coord->v.units.z;
13915 clutter_anchor_coord_set_units (AnchorCoord *coord,
13920 coord->is_fractional = FALSE;
13921 coord->v.units.x = x;
13922 coord->v.units.y = y;
13923 coord->v.units.z = z;
13926 static ClutterGravity
13927 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13929 if (coord->is_fractional)
13931 if (coord->v.fraction.x == 0.0)
13933 if (coord->v.fraction.y == 0.0)
13934 return CLUTTER_GRAVITY_NORTH_WEST;
13935 else if (coord->v.fraction.y == 0.5)
13936 return CLUTTER_GRAVITY_WEST;
13937 else if (coord->v.fraction.y == 1.0)
13938 return CLUTTER_GRAVITY_SOUTH_WEST;
13940 return CLUTTER_GRAVITY_NONE;
13942 else if (coord->v.fraction.x == 0.5)
13944 if (coord->v.fraction.y == 0.0)
13945 return CLUTTER_GRAVITY_NORTH;
13946 else if (coord->v.fraction.y == 0.5)
13947 return CLUTTER_GRAVITY_CENTER;
13948 else if (coord->v.fraction.y == 1.0)
13949 return CLUTTER_GRAVITY_SOUTH;
13951 return CLUTTER_GRAVITY_NONE;
13953 else if (coord->v.fraction.x == 1.0)
13955 if (coord->v.fraction.y == 0.0)
13956 return CLUTTER_GRAVITY_NORTH_EAST;
13957 else if (coord->v.fraction.y == 0.5)
13958 return CLUTTER_GRAVITY_EAST;
13959 else if (coord->v.fraction.y == 1.0)
13960 return CLUTTER_GRAVITY_SOUTH_EAST;
13962 return CLUTTER_GRAVITY_NONE;
13965 return CLUTTER_GRAVITY_NONE;
13968 return CLUTTER_GRAVITY_NONE;
13972 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
13973 ClutterGravity gravity)
13977 case CLUTTER_GRAVITY_NORTH:
13978 coord->v.fraction.x = 0.5;
13979 coord->v.fraction.y = 0.0;
13982 case CLUTTER_GRAVITY_NORTH_EAST:
13983 coord->v.fraction.x = 1.0;
13984 coord->v.fraction.y = 0.0;
13987 case CLUTTER_GRAVITY_EAST:
13988 coord->v.fraction.x = 1.0;
13989 coord->v.fraction.y = 0.5;
13992 case CLUTTER_GRAVITY_SOUTH_EAST:
13993 coord->v.fraction.x = 1.0;
13994 coord->v.fraction.y = 1.0;
13997 case CLUTTER_GRAVITY_SOUTH:
13998 coord->v.fraction.x = 0.5;
13999 coord->v.fraction.y = 1.0;
14002 case CLUTTER_GRAVITY_SOUTH_WEST:
14003 coord->v.fraction.x = 0.0;
14004 coord->v.fraction.y = 1.0;
14007 case CLUTTER_GRAVITY_WEST:
14008 coord->v.fraction.x = 0.0;
14009 coord->v.fraction.y = 0.5;
14012 case CLUTTER_GRAVITY_NORTH_WEST:
14013 coord->v.fraction.x = 0.0;
14014 coord->v.fraction.y = 0.0;
14017 case CLUTTER_GRAVITY_CENTER:
14018 coord->v.fraction.x = 0.5;
14019 coord->v.fraction.y = 0.5;
14023 coord->v.fraction.x = 0.0;
14024 coord->v.fraction.y = 0.0;
14028 coord->is_fractional = TRUE;
14032 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14034 if (coord->is_fractional)
14035 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14037 return (coord->v.units.x == 0.0
14038 && coord->v.units.y == 0.0
14039 && coord->v.units.z == 0.0);
14043 * clutter_actor_get_flags:
14044 * @self: a #ClutterActor
14046 * Retrieves the flags set on @self
14048 * Return value: a bitwise or of #ClutterActorFlags or 0
14053 clutter_actor_get_flags (ClutterActor *self)
14055 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14057 return self->flags;
14061 * clutter_actor_set_flags:
14062 * @self: a #ClutterActor
14063 * @flags: the flags to set
14065 * Sets @flags on @self
14067 * This function will emit notifications for the changed properties
14072 clutter_actor_set_flags (ClutterActor *self,
14073 ClutterActorFlags flags)
14075 ClutterActorFlags old_flags;
14077 gboolean was_reactive_set, reactive_set;
14078 gboolean was_realized_set, realized_set;
14079 gboolean was_mapped_set, mapped_set;
14080 gboolean was_visible_set, visible_set;
14082 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14084 if (self->flags == flags)
14087 obj = G_OBJECT (self);
14088 g_object_ref (obj);
14089 g_object_freeze_notify (obj);
14091 old_flags = self->flags;
14093 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14094 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14095 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14096 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14098 self->flags |= flags;
14100 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14101 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14102 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14103 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14105 if (reactive_set != was_reactive_set)
14106 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14108 if (realized_set != was_realized_set)
14109 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14111 if (mapped_set != was_mapped_set)
14112 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14114 if (visible_set != was_visible_set)
14115 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14117 g_object_thaw_notify (obj);
14118 g_object_unref (obj);
14122 * clutter_actor_unset_flags:
14123 * @self: a #ClutterActor
14124 * @flags: the flags to unset
14126 * Unsets @flags on @self
14128 * This function will emit notifications for the changed properties
14133 clutter_actor_unset_flags (ClutterActor *self,
14134 ClutterActorFlags flags)
14136 ClutterActorFlags old_flags;
14138 gboolean was_reactive_set, reactive_set;
14139 gboolean was_realized_set, realized_set;
14140 gboolean was_mapped_set, mapped_set;
14141 gboolean was_visible_set, visible_set;
14143 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14145 obj = G_OBJECT (self);
14146 g_object_freeze_notify (obj);
14148 old_flags = self->flags;
14150 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14151 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14152 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14153 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14155 self->flags &= ~flags;
14157 if (self->flags == old_flags)
14160 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14161 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14162 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14163 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14165 if (reactive_set != was_reactive_set)
14166 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14168 if (realized_set != was_realized_set)
14169 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14171 if (mapped_set != was_mapped_set)
14172 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14174 if (visible_set != was_visible_set)
14175 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14177 g_object_thaw_notify (obj);
14181 * clutter_actor_get_transformation_matrix:
14182 * @self: a #ClutterActor
14183 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14185 * Retrieves the transformations applied to @self relative to its
14191 clutter_actor_get_transformation_matrix (ClutterActor *self,
14192 CoglMatrix *matrix)
14194 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14196 cogl_matrix_init_identity (matrix);
14198 _clutter_actor_apply_modelview_transform (self, matrix);
14202 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14203 gboolean is_in_clone_paint)
14205 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14206 self->priv->in_clone_paint = is_in_clone_paint;
14210 * clutter_actor_is_in_clone_paint:
14211 * @self: a #ClutterActor
14213 * Checks whether @self is being currently painted by a #ClutterClone
14215 * This function is useful only inside the ::paint virtual function
14216 * implementations or within handlers for the #ClutterActor::paint
14219 * This function should not be used by applications
14221 * Return value: %TRUE if the #ClutterActor is currently being painted
14222 * by a #ClutterClone, and %FALSE otherwise
14227 clutter_actor_is_in_clone_paint (ClutterActor *self)
14229 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14231 return self->priv->in_clone_paint;
14235 set_direction_recursive (ClutterActor *actor,
14236 gpointer user_data)
14238 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14240 clutter_actor_set_text_direction (actor, text_dir);
14246 * clutter_actor_set_text_direction:
14247 * @self: a #ClutterActor
14248 * @text_dir: the text direction for @self
14250 * Sets the #ClutterTextDirection for an actor
14252 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14254 * If @self implements #ClutterContainer then this function will recurse
14255 * inside all the children of @self (including the internal ones).
14257 * Composite actors not implementing #ClutterContainer, or actors requiring
14258 * special handling when the text direction changes, should connect to
14259 * the #GObject::notify signal for the #ClutterActor:text-direction property
14264 clutter_actor_set_text_direction (ClutterActor *self,
14265 ClutterTextDirection text_dir)
14267 ClutterActorPrivate *priv;
14269 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14270 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14274 if (priv->text_direction != text_dir)
14276 priv->text_direction = text_dir;
14278 /* we need to emit the notify::text-direction first, so that
14279 * the sub-classes can catch that and do specific handling of
14280 * the text direction; see clutter_text_direction_changed_cb()
14281 * inside clutter-text.c
14283 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14285 _clutter_actor_foreach_child (self, set_direction_recursive,
14286 GINT_TO_POINTER (text_dir));
14288 clutter_actor_queue_relayout (self);
14293 _clutter_actor_set_has_pointer (ClutterActor *self,
14294 gboolean has_pointer)
14296 ClutterActorPrivate *priv = self->priv;
14298 if (priv->has_pointer != has_pointer)
14300 priv->has_pointer = has_pointer;
14302 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14307 * clutter_actor_get_text_direction:
14308 * @self: a #ClutterActor
14310 * Retrieves the value set using clutter_actor_set_text_direction()
14312 * If no text direction has been previously set, the default text
14313 * direction, as returned by clutter_get_default_text_direction(), will
14314 * be returned instead
14316 * Return value: the #ClutterTextDirection for the actor
14320 ClutterTextDirection
14321 clutter_actor_get_text_direction (ClutterActor *self)
14323 ClutterActorPrivate *priv;
14325 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14326 CLUTTER_TEXT_DIRECTION_LTR);
14330 /* if no direction has been set yet use the default */
14331 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14332 priv->text_direction = clutter_get_default_text_direction ();
14334 return priv->text_direction;
14338 * clutter_actor_push_internal:
14339 * @self: a #ClutterActor
14341 * Should be used by actors implementing the #ClutterContainer and with
14342 * internal children added through clutter_actor_set_parent(), for instance:
14346 * my_actor_init (MyActor *self)
14348 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14350 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14352 * /* calling clutter_actor_set_parent() now will result in
14353 * * the internal flag being set on a child of MyActor
14356 * /* internal child - a background texture */
14357 * self->priv->background_tex = clutter_texture_new ();
14358 * clutter_actor_set_parent (self->priv->background_tex,
14359 * CLUTTER_ACTOR (self));
14361 * /* internal child - a label */
14362 * self->priv->label = clutter_text_new ();
14363 * clutter_actor_set_parent (self->priv->label,
14364 * CLUTTER_ACTOR (self));
14366 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14368 * /* calling clutter_actor_set_parent() now will not result in
14369 * * the internal flag being set on a child of MyActor
14374 * This function will be used by Clutter to toggle an "internal child"
14375 * flag whenever clutter_actor_set_parent() is called; internal children
14376 * are handled differently by Clutter, specifically when destroying their
14379 * Call clutter_actor_pop_internal() when you finished adding internal
14382 * Nested calls to clutter_actor_push_internal() are allowed, but each
14383 * one must by followed by a clutter_actor_pop_internal() call.
14387 * Deprecated: 1.10: All children of an actor are accessible through
14388 * the #ClutterActor API, and #ClutterActor implements the
14389 * #ClutterContainer interface, so this function is only useful
14390 * for legacy containers overriding the default implementation.
14393 clutter_actor_push_internal (ClutterActor *self)
14395 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14397 self->priv->internal_child += 1;
14401 * clutter_actor_pop_internal:
14402 * @self: a #ClutterActor
14404 * Disables the effects of clutter_actor_push_internal().
14408 * Deprecated: 1.10: All children of an actor are accessible through
14409 * the #ClutterActor API. This function is only useful for legacy
14410 * containers overriding the default implementation of the
14411 * #ClutterContainer interface.
14414 clutter_actor_pop_internal (ClutterActor *self)
14416 ClutterActorPrivate *priv;
14418 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14422 if (priv->internal_child == 0)
14424 g_warning ("Mismatched %s: you need to call "
14425 "clutter_actor_push_composite() at least once before "
14426 "calling this function", G_STRFUNC);
14430 priv->internal_child -= 1;
14434 * clutter_actor_has_pointer:
14435 * @self: a #ClutterActor
14437 * Checks whether an actor contains the pointer of a
14438 * #ClutterInputDevice
14440 * Return value: %TRUE if the actor contains the pointer, and
14446 clutter_actor_has_pointer (ClutterActor *self)
14448 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14450 return self->priv->has_pointer;
14453 /* XXX: This is a workaround for not being able to break the ABI of
14454 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14455 * clutter_actor_queue_clipped_redraw() for details.
14457 ClutterPaintVolume *
14458 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14460 return g_object_get_data (G_OBJECT (self),
14461 "-clutter-actor-queue-redraw-clip");
14465 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14466 ClutterPaintVolume *clip)
14468 g_object_set_data (G_OBJECT (self),
14469 "-clutter-actor-queue-redraw-clip",
14474 * clutter_actor_has_allocation:
14475 * @self: a #ClutterActor
14477 * Checks if the actor has an up-to-date allocation assigned to
14478 * it. This means that the actor should have an allocation: it's
14479 * visible and has a parent. It also means that there is no
14480 * outstanding relayout request in progress for the actor or its
14481 * children (There might be other outstanding layout requests in
14482 * progress that will cause the actor to get a new allocation
14483 * when the stage is laid out, however).
14485 * If this function returns %FALSE, then the actor will normally
14486 * be allocated before it is next drawn on the screen.
14488 * Return value: %TRUE if the actor has an up-to-date allocation
14493 clutter_actor_has_allocation (ClutterActor *self)
14495 ClutterActorPrivate *priv;
14497 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14501 return priv->parent != NULL &&
14502 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14503 !priv->needs_allocation;
14507 * clutter_actor_add_action:
14508 * @self: a #ClutterActor
14509 * @action: a #ClutterAction
14511 * Adds @action to the list of actions applied to @self
14513 * A #ClutterAction can only belong to one actor at a time
14515 * The #ClutterActor will hold a reference on @action until either
14516 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14522 clutter_actor_add_action (ClutterActor *self,
14523 ClutterAction *action)
14525 ClutterActorPrivate *priv;
14527 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14528 g_return_if_fail (CLUTTER_IS_ACTION (action));
14532 if (priv->actions == NULL)
14534 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14535 priv->actions->actor = self;
14538 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14540 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14544 * clutter_actor_add_action_with_name:
14545 * @self: a #ClutterActor
14546 * @name: the name to set on the action
14547 * @action: a #ClutterAction
14549 * A convenience function for setting the name of a #ClutterAction
14550 * while adding it to the list of actions applied to @self
14552 * This function is the logical equivalent of:
14555 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14556 * clutter_actor_add_action (self, action);
14562 clutter_actor_add_action_with_name (ClutterActor *self,
14564 ClutterAction *action)
14566 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14567 g_return_if_fail (name != NULL);
14568 g_return_if_fail (CLUTTER_IS_ACTION (action));
14570 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14571 clutter_actor_add_action (self, action);
14575 * clutter_actor_remove_action:
14576 * @self: a #ClutterActor
14577 * @action: a #ClutterAction
14579 * Removes @action from the list of actions applied to @self
14581 * The reference held by @self on the #ClutterAction will be released
14586 clutter_actor_remove_action (ClutterActor *self,
14587 ClutterAction *action)
14589 ClutterActorPrivate *priv;
14591 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14592 g_return_if_fail (CLUTTER_IS_ACTION (action));
14596 if (priv->actions == NULL)
14599 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14601 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14605 * clutter_actor_remove_action_by_name:
14606 * @self: a #ClutterActor
14607 * @name: the name of the action to remove
14609 * Removes the #ClutterAction with the given name from the list
14610 * of actions applied to @self
14615 clutter_actor_remove_action_by_name (ClutterActor *self,
14618 ClutterActorPrivate *priv;
14619 ClutterActorMeta *meta;
14621 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14622 g_return_if_fail (name != NULL);
14626 if (priv->actions == NULL)
14629 meta = _clutter_meta_group_get_meta (priv->actions, name);
14633 _clutter_meta_group_remove_meta (priv->actions, meta);
14635 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14639 * clutter_actor_get_actions:
14640 * @self: a #ClutterActor
14642 * Retrieves the list of actions applied to @self
14644 * Return value: (transfer container) (element-type Clutter.Action): a copy
14645 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14646 * owned by the #ClutterActor. Use g_list_free() to free the resources
14647 * allocated by the returned #GList
14652 clutter_actor_get_actions (ClutterActor *self)
14654 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14656 if (self->priv->actions == NULL)
14659 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14663 * clutter_actor_get_action:
14664 * @self: a #ClutterActor
14665 * @name: the name of the action to retrieve
14667 * Retrieves the #ClutterAction with the given name in the list
14668 * of actions applied to @self
14670 * Return value: (transfer none): a #ClutterAction for the given
14671 * name, or %NULL. The returned #ClutterAction is owned by the
14672 * actor and it should not be unreferenced directly
14677 clutter_actor_get_action (ClutterActor *self,
14680 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14681 g_return_val_if_fail (name != NULL, NULL);
14683 if (self->priv->actions == NULL)
14686 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14690 * clutter_actor_clear_actions:
14691 * @self: a #ClutterActor
14693 * Clears the list of actions applied to @self
14698 clutter_actor_clear_actions (ClutterActor *self)
14700 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14702 if (self->priv->actions == NULL)
14705 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14709 * clutter_actor_add_constraint:
14710 * @self: a #ClutterActor
14711 * @constraint: a #ClutterConstraint
14713 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14716 * The #ClutterActor will hold a reference on the @constraint until
14717 * either clutter_actor_remove_constraint() or
14718 * clutter_actor_clear_constraints() is called.
14723 clutter_actor_add_constraint (ClutterActor *self,
14724 ClutterConstraint *constraint)
14726 ClutterActorPrivate *priv;
14728 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14729 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14733 if (priv->constraints == NULL)
14735 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14736 priv->constraints->actor = self;
14739 _clutter_meta_group_add_meta (priv->constraints,
14740 CLUTTER_ACTOR_META (constraint));
14741 clutter_actor_queue_relayout (self);
14743 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14747 * clutter_actor_add_constraint_with_name:
14748 * @self: a #ClutterActor
14749 * @name: the name to set on the constraint
14750 * @constraint: a #ClutterConstraint
14752 * A convenience function for setting the name of a #ClutterConstraint
14753 * while adding it to the list of constraints applied to @self
14755 * This function is the logical equivalent of:
14758 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14759 * clutter_actor_add_constraint (self, constraint);
14765 clutter_actor_add_constraint_with_name (ClutterActor *self,
14767 ClutterConstraint *constraint)
14769 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14770 g_return_if_fail (name != NULL);
14771 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14773 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14774 clutter_actor_add_constraint (self, constraint);
14778 * clutter_actor_remove_constraint:
14779 * @self: a #ClutterActor
14780 * @constraint: a #ClutterConstraint
14782 * Removes @constraint from the list of constraints applied to @self
14784 * The reference held by @self on the #ClutterConstraint will be released
14789 clutter_actor_remove_constraint (ClutterActor *self,
14790 ClutterConstraint *constraint)
14792 ClutterActorPrivate *priv;
14794 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14795 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14799 if (priv->constraints == NULL)
14802 _clutter_meta_group_remove_meta (priv->constraints,
14803 CLUTTER_ACTOR_META (constraint));
14804 clutter_actor_queue_relayout (self);
14806 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14810 * clutter_actor_remove_constraint_by_name:
14811 * @self: a #ClutterActor
14812 * @name: the name of the constraint to remove
14814 * Removes the #ClutterConstraint with the given name from the list
14815 * of constraints applied to @self
14820 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14823 ClutterActorPrivate *priv;
14824 ClutterActorMeta *meta;
14826 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14827 g_return_if_fail (name != NULL);
14831 if (priv->constraints == NULL)
14834 meta = _clutter_meta_group_get_meta (priv->constraints, name);
14838 _clutter_meta_group_remove_meta (priv->constraints, meta);
14839 clutter_actor_queue_relayout (self);
14843 * clutter_actor_get_constraints:
14844 * @self: a #ClutterActor
14846 * Retrieves the list of constraints applied to @self
14848 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14849 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14850 * owned by the #ClutterActor. Use g_list_free() to free the resources
14851 * allocated by the returned #GList
14856 clutter_actor_get_constraints (ClutterActor *self)
14858 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14860 if (self->priv->constraints == NULL)
14863 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14867 * clutter_actor_get_constraint:
14868 * @self: a #ClutterActor
14869 * @name: the name of the constraint to retrieve
14871 * Retrieves the #ClutterConstraint with the given name in the list
14872 * of constraints applied to @self
14874 * Return value: (transfer none): a #ClutterConstraint for the given
14875 * name, or %NULL. The returned #ClutterConstraint is owned by the
14876 * actor and it should not be unreferenced directly
14880 ClutterConstraint *
14881 clutter_actor_get_constraint (ClutterActor *self,
14884 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14885 g_return_val_if_fail (name != NULL, NULL);
14887 if (self->priv->constraints == NULL)
14890 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14894 * clutter_actor_clear_constraints:
14895 * @self: a #ClutterActor
14897 * Clears the list of constraints applied to @self
14902 clutter_actor_clear_constraints (ClutterActor *self)
14904 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14906 if (self->priv->constraints == NULL)
14909 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14911 clutter_actor_queue_relayout (self);
14915 * clutter_actor_set_clip_to_allocation:
14916 * @self: a #ClutterActor
14917 * @clip_set: %TRUE to apply a clip tracking the allocation
14919 * Sets whether @self should be clipped to the same size as its
14925 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14928 ClutterActorPrivate *priv;
14930 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14932 clip_set = !!clip_set;
14936 if (priv->clip_to_allocation != clip_set)
14938 priv->clip_to_allocation = clip_set;
14940 clutter_actor_queue_redraw (self);
14942 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14947 * clutter_actor_get_clip_to_allocation:
14948 * @self: a #ClutterActor
14950 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14952 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14957 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14959 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14961 return self->priv->clip_to_allocation;
14965 * clutter_actor_add_effect:
14966 * @self: a #ClutterActor
14967 * @effect: a #ClutterEffect
14969 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14971 * The #ClutterActor will hold a reference on the @effect until either
14972 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14978 clutter_actor_add_effect (ClutterActor *self,
14979 ClutterEffect *effect)
14981 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14982 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14984 _clutter_actor_add_effect_internal (self, effect);
14986 clutter_actor_queue_redraw (self);
14988 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14992 * clutter_actor_add_effect_with_name:
14993 * @self: a #ClutterActor
14994 * @name: the name to set on the effect
14995 * @effect: a #ClutterEffect
14997 * A convenience function for setting the name of a #ClutterEffect
14998 * while adding it to the list of effectss applied to @self
15000 * This function is the logical equivalent of:
15003 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15004 * clutter_actor_add_effect (self, effect);
15010 clutter_actor_add_effect_with_name (ClutterActor *self,
15012 ClutterEffect *effect)
15014 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15015 g_return_if_fail (name != NULL);
15016 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15018 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15019 clutter_actor_add_effect (self, effect);
15023 * clutter_actor_remove_effect:
15024 * @self: a #ClutterActor
15025 * @effect: a #ClutterEffect
15027 * Removes @effect from the list of effects applied to @self
15029 * The reference held by @self on the #ClutterEffect will be released
15034 clutter_actor_remove_effect (ClutterActor *self,
15035 ClutterEffect *effect)
15037 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15038 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15040 _clutter_actor_remove_effect_internal (self, effect);
15042 clutter_actor_queue_redraw (self);
15044 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15048 * clutter_actor_remove_effect_by_name:
15049 * @self: a #ClutterActor
15050 * @name: the name of the effect to remove
15052 * Removes the #ClutterEffect with the given name from the list
15053 * of effects applied to @self
15058 clutter_actor_remove_effect_by_name (ClutterActor *self,
15061 ClutterActorPrivate *priv;
15062 ClutterActorMeta *meta;
15064 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15065 g_return_if_fail (name != NULL);
15069 if (priv->effects == NULL)
15072 meta = _clutter_meta_group_get_meta (priv->effects, name);
15076 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15080 * clutter_actor_get_effects:
15081 * @self: a #ClutterActor
15083 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15085 * Return value: (transfer container) (element-type Clutter.Effect): a list
15086 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15087 * list are owned by Clutter and they should not be freed. You should
15088 * free the returned list using g_list_free() when done
15093 clutter_actor_get_effects (ClutterActor *self)
15095 ClutterActorPrivate *priv;
15097 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15101 if (priv->effects == NULL)
15104 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15108 * clutter_actor_get_effect:
15109 * @self: a #ClutterActor
15110 * @name: the name of the effect to retrieve
15112 * Retrieves the #ClutterEffect with the given name in the list
15113 * of effects applied to @self
15115 * Return value: (transfer none): a #ClutterEffect for the given
15116 * name, or %NULL. The returned #ClutterEffect is owned by the
15117 * actor and it should not be unreferenced directly
15122 clutter_actor_get_effect (ClutterActor *self,
15125 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15126 g_return_val_if_fail (name != NULL, NULL);
15128 if (self->priv->effects == NULL)
15131 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15135 * clutter_actor_clear_effects:
15136 * @self: a #ClutterActor
15138 * Clears the list of effects applied to @self
15143 clutter_actor_clear_effects (ClutterActor *self)
15145 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15147 if (self->priv->effects == NULL)
15150 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15152 clutter_actor_queue_redraw (self);
15156 * clutter_actor_has_key_focus:
15157 * @self: a #ClutterActor
15159 * Checks whether @self is the #ClutterActor that has key focus
15161 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15166 clutter_actor_has_key_focus (ClutterActor *self)
15168 ClutterActor *stage;
15170 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15172 stage = _clutter_actor_get_stage_internal (self);
15176 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15180 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15181 ClutterPaintVolume *pv)
15183 ClutterActorPrivate *priv = self->priv;
15185 /* Actors are only expected to report a valid paint volume
15186 * while they have a valid allocation. */
15187 if (G_UNLIKELY (priv->needs_allocation))
15189 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15190 "Actor needs allocation",
15191 _clutter_actor_get_debug_name (self));
15195 /* Check if there are any handlers connected to the paint
15196 * signal. If there are then all bets are off for what the paint
15197 * volume for this actor might possibly be!
15199 * XXX: It's expected that this is going to end up being quite a
15200 * costly check to have to do here, but we haven't come up with
15201 * another solution that can reliably catch paint signal handlers at
15202 * the right time to either avoid artefacts due to invalid stage
15203 * clipping or due to incorrect culling.
15205 * Previously we checked in clutter_actor_paint(), but at that time
15206 * we may already be using a stage clip that could be derived from
15207 * an invalid paint-volume. We used to try and handle that by
15208 * queuing a follow up, unclipped, redraw but still the previous
15209 * checking wasn't enough to catch invalid volumes involved in
15210 * culling (considering that containers may derive their volume from
15211 * children that haven't yet been painted)
15213 * Longer term, improved solutions could be:
15214 * - Disallow painting in the paint signal, only allow using it
15215 * for tracking when paints happen. We can add another API that
15216 * allows monkey patching the paint of arbitrary actors but in a
15217 * more controlled way and that also supports modifying the
15219 * - If we could be notified somehow when signal handlers are
15220 * connected we wouldn't have to poll for handlers like this.
15222 if (g_signal_has_handler_pending (self,
15223 actor_signals[PAINT],
15227 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15228 "Actor has \"paint\" signal handlers",
15229 _clutter_actor_get_debug_name (self));
15233 _clutter_paint_volume_init_static (pv, self);
15235 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15237 clutter_paint_volume_free (pv);
15238 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15239 "Actor failed to report a volume",
15240 _clutter_actor_get_debug_name (self));
15244 /* since effects can modify the paint volume, we allow them to actually
15245 * do this by making get_paint_volume() "context sensitive"
15247 if (priv->effects != NULL)
15249 if (priv->current_effect != NULL)
15251 const GList *effects, *l;
15253 /* if we are being called from within the paint sequence of
15254 * an actor, get the paint volume up to the current effect
15256 effects = _clutter_meta_group_peek_metas (priv->effects);
15258 l != NULL || (l != NULL && l->data != priv->current_effect);
15261 if (!_clutter_effect_get_paint_volume (l->data, pv))
15263 clutter_paint_volume_free (pv);
15264 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15265 "Effect (%s) failed to report a volume",
15266 _clutter_actor_get_debug_name (self),
15267 _clutter_actor_meta_get_debug_name (l->data));
15274 const GList *effects, *l;
15276 /* otherwise, get the cumulative volume */
15277 effects = _clutter_meta_group_peek_metas (priv->effects);
15278 for (l = effects; l != NULL; l = l->next)
15279 if (!_clutter_effect_get_paint_volume (l->data, pv))
15281 clutter_paint_volume_free (pv);
15282 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15283 "Effect (%s) failed to report a volume",
15284 _clutter_actor_get_debug_name (self),
15285 _clutter_actor_meta_get_debug_name (l->data));
15294 /* The public clutter_actor_get_paint_volume API returns a const
15295 * pointer since we return a pointer directly to the cached
15296 * PaintVolume associated with the actor and don't want the user to
15297 * inadvertently modify it, but for internal uses we sometimes need
15298 * access to the same PaintVolume but need to apply some book-keeping
15299 * modifications to it so we don't want a const pointer.
15301 static ClutterPaintVolume *
15302 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15304 ClutterActorPrivate *priv;
15308 if (priv->paint_volume_valid)
15309 clutter_paint_volume_free (&priv->paint_volume);
15311 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15313 priv->paint_volume_valid = TRUE;
15314 return &priv->paint_volume;
15318 priv->paint_volume_valid = FALSE;
15324 * clutter_actor_get_paint_volume:
15325 * @self: a #ClutterActor
15327 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15328 * when a paint volume can't be determined.
15330 * The paint volume is defined as the 3D space occupied by an actor
15331 * when being painted.
15333 * This function will call the <function>get_paint_volume()</function>
15334 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15335 * should not usually care about overriding the default implementation,
15336 * unless they are, for instance: painting outside their allocation, or
15337 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15340 * <note>2D actors overriding <function>get_paint_volume()</function>
15341 * ensure their volume has a depth of 0. (This will be true so long as
15342 * you don't call clutter_paint_volume_set_depth().)</note>
15344 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15345 * or %NULL if no volume could be determined. The returned pointer
15346 * is not guaranteed to be valid across multiple frames; if you want
15347 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15351 const ClutterPaintVolume *
15352 clutter_actor_get_paint_volume (ClutterActor *self)
15354 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15356 return _clutter_actor_get_paint_volume_mutable (self);
15360 * clutter_actor_get_transformed_paint_volume:
15361 * @self: a #ClutterActor
15362 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15363 * (or %NULL for the stage)
15365 * Retrieves the 3D paint volume of an actor like
15366 * clutter_actor_get_paint_volume() does (Please refer to the
15367 * documentation of clutter_actor_get_paint_volume() for more
15368 * details.) and it additionally transforms the paint volume into the
15369 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15370 * is passed for @relative_to_ancestor)
15372 * This can be used by containers that base their paint volume on
15373 * the volume of their children. Such containers can query the
15374 * transformed paint volume of all of its children and union them
15375 * together using clutter_paint_volume_union().
15377 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15378 * or %NULL if no volume could be determined. The returned pointer is
15379 * not guaranteed to be valid across multiple frames; if you wish to
15380 * keep it, you will have to copy it using clutter_paint_volume_copy().
15384 const ClutterPaintVolume *
15385 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15386 ClutterActor *relative_to_ancestor)
15388 const ClutterPaintVolume *volume;
15389 ClutterActor *stage;
15390 ClutterPaintVolume *transformed_volume;
15392 stage = _clutter_actor_get_stage_internal (self);
15393 if (G_UNLIKELY (stage == NULL))
15396 if (relative_to_ancestor == NULL)
15397 relative_to_ancestor = stage;
15399 volume = clutter_actor_get_paint_volume (self);
15400 if (volume == NULL)
15403 transformed_volume =
15404 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15406 _clutter_paint_volume_copy_static (volume, transformed_volume);
15408 _clutter_paint_volume_transform_relative (transformed_volume,
15409 relative_to_ancestor);
15411 return transformed_volume;
15415 * clutter_actor_get_paint_box:
15416 * @self: a #ClutterActor
15417 * @box: (out): return location for a #ClutterActorBox
15419 * Retrieves the paint volume of the passed #ClutterActor, and
15420 * transforms it into a 2D bounding box in stage coordinates.
15422 * This function is useful to determine the on screen area occupied by
15423 * the actor. The box is only an approximation and may often be
15424 * considerably larger due to the optimizations used to calculate the
15425 * box. The box is never smaller though, so it can reliably be used
15428 * There are times when a 2D paint box can't be determined, e.g.
15429 * because the actor isn't yet parented under a stage or because
15430 * the actor is unable to determine a paint volume.
15432 * Return value: %TRUE if a 2D paint box could be determined, else
15438 clutter_actor_get_paint_box (ClutterActor *self,
15439 ClutterActorBox *box)
15441 ClutterActor *stage;
15442 ClutterPaintVolume *pv;
15444 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15445 g_return_val_if_fail (box != NULL, FALSE);
15447 stage = _clutter_actor_get_stage_internal (self);
15448 if (G_UNLIKELY (!stage))
15451 pv = _clutter_actor_get_paint_volume_mutable (self);
15452 if (G_UNLIKELY (!pv))
15455 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15461 * clutter_actor_has_overlaps:
15462 * @self: A #ClutterActor
15464 * Asks the actor's implementation whether it may contain overlapping
15467 * For example; Clutter may use this to determine whether the painting
15468 * should be redirected to an offscreen buffer to correctly implement
15469 * the opacity property.
15471 * Custom actors can override the default response by implementing the
15472 * #ClutterActor <function>has_overlaps</function> virtual function. See
15473 * clutter_actor_set_offscreen_redirect() for more information.
15475 * Return value: %TRUE if the actor may have overlapping primitives, and
15481 clutter_actor_has_overlaps (ClutterActor *self)
15483 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15485 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15489 * clutter_actor_has_effects:
15490 * @self: A #ClutterActor
15492 * Returns whether the actor has any effects applied.
15494 * Return value: %TRUE if the actor has any effects,
15500 clutter_actor_has_effects (ClutterActor *self)
15502 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15504 if (self->priv->effects == NULL)
15507 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15511 * clutter_actor_has_constraints:
15512 * @self: A #ClutterActor
15514 * Returns whether the actor has any constraints applied.
15516 * Return value: %TRUE if the actor has any constraints,
15522 clutter_actor_has_constraints (ClutterActor *self)
15524 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15526 return self->priv->constraints != NULL;
15530 * clutter_actor_has_actions:
15531 * @self: A #ClutterActor
15533 * Returns whether the actor has any actions applied.
15535 * Return value: %TRUE if the actor has any actions,
15541 clutter_actor_has_actions (ClutterActor *self)
15543 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15545 return self->priv->actions != NULL;
15549 * clutter_actor_get_n_children:
15550 * @self: a #ClutterActor
15552 * Retrieves the number of children of @self.
15554 * Return value: the number of children of an actor
15559 clutter_actor_get_n_children (ClutterActor *self)
15561 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15563 return self->priv->n_children;
15567 * clutter_actor_get_child_at_index:
15568 * @self: a #ClutterActor
15569 * @index_: the position in the list of children
15571 * Retrieves the actor at the given @index_ inside the list of
15572 * children of @self.
15574 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15579 clutter_actor_get_child_at_index (ClutterActor *self,
15582 ClutterActor *iter;
15585 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15586 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15588 for (iter = self->priv->first_child, i = 0;
15589 iter != NULL && i < index_;
15590 iter = iter->priv->next_sibling, i += 1)
15597 * _clutter_actor_foreach_child:
15598 * @actor: The actor whos children you want to iterate
15599 * @callback: The function to call for each child
15600 * @user_data: Private data to pass to @callback
15602 * Calls a given @callback once for each child of the specified @actor and
15603 * passing the @user_data pointer each time.
15605 * Return value: returns %TRUE if all children were iterated, else
15606 * %FALSE if a callback broke out of iteration early.
15609 _clutter_actor_foreach_child (ClutterActor *self,
15610 ClutterForeachCallback callback,
15611 gpointer user_data)
15613 ClutterActorPrivate *priv = self->priv;
15614 ClutterActor *iter;
15617 for (cont = TRUE, iter = priv->first_child;
15618 cont && iter != NULL;
15619 iter = iter->priv->next_sibling)
15621 cont = callback (iter, user_data);
15628 /* For debugging purposes this gives us a simple way to print out
15629 * the scenegraph e.g in gdb using:
15631 * _clutter_actor_traverse (stage,
15633 * clutter_debug_print_actor_cb,
15638 static ClutterActorTraverseVisitFlags
15639 clutter_debug_print_actor_cb (ClutterActor *actor,
15643 g_print ("%*s%s:%p\n",
15645 _clutter_actor_get_debug_name (actor),
15648 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15653 _clutter_actor_traverse_breadth (ClutterActor *actor,
15654 ClutterTraverseCallback callback,
15655 gpointer user_data)
15657 GQueue *queue = g_queue_new ();
15658 ClutterActor dummy;
15659 int current_depth = 0;
15661 g_queue_push_tail (queue, actor);
15662 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15664 while ((actor = g_queue_pop_head (queue)))
15666 ClutterActorTraverseVisitFlags flags;
15668 if (actor == &dummy)
15671 g_queue_push_tail (queue, &dummy);
15675 flags = callback (actor, current_depth, user_data);
15676 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15678 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15680 ClutterActor *iter;
15682 for (iter = actor->priv->first_child;
15684 iter = iter->priv->next_sibling)
15686 g_queue_push_tail (queue, iter);
15691 g_queue_free (queue);
15694 static ClutterActorTraverseVisitFlags
15695 _clutter_actor_traverse_depth (ClutterActor *actor,
15696 ClutterTraverseCallback before_children_callback,
15697 ClutterTraverseCallback after_children_callback,
15699 gpointer user_data)
15701 ClutterActorTraverseVisitFlags flags;
15703 flags = before_children_callback (actor, current_depth, user_data);
15704 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15705 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15707 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15709 ClutterActor *iter;
15711 for (iter = actor->priv->first_child;
15713 iter = iter->priv->next_sibling)
15715 flags = _clutter_actor_traverse_depth (iter,
15716 before_children_callback,
15717 after_children_callback,
15721 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15722 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15726 if (after_children_callback)
15727 return after_children_callback (actor, current_depth, user_data);
15729 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15732 /* _clutter_actor_traverse:
15733 * @actor: The actor to start traversing the graph from
15734 * @flags: These flags may affect how the traversal is done
15735 * @before_children_callback: A function to call before visiting the
15736 * children of the current actor.
15737 * @after_children_callback: A function to call after visiting the
15738 * children of the current actor. (Ignored if
15739 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15740 * @user_data: The private data to pass to the callbacks
15742 * Traverses the scenegraph starting at the specified @actor and
15743 * descending through all its children and its children's children.
15744 * For each actor traversed @before_children_callback and
15745 * @after_children_callback are called with the specified
15746 * @user_data, before and after visiting that actor's children.
15748 * The callbacks can return flags that affect the ongoing traversal
15749 * such as by skipping over an actors children or bailing out of
15750 * any further traversing.
15753 _clutter_actor_traverse (ClutterActor *actor,
15754 ClutterActorTraverseFlags flags,
15755 ClutterTraverseCallback before_children_callback,
15756 ClutterTraverseCallback after_children_callback,
15757 gpointer user_data)
15759 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15760 _clutter_actor_traverse_breadth (actor,
15761 before_children_callback,
15763 else /* DEPTH_FIRST */
15764 _clutter_actor_traverse_depth (actor,
15765 before_children_callback,
15766 after_children_callback,
15767 0, /* start depth */
15772 on_layout_manager_changed (ClutterLayoutManager *manager,
15773 ClutterActor *self)
15775 clutter_actor_queue_relayout (self);
15779 * clutter_actor_set_layout_manager:
15780 * @self: a #ClutterActor
15781 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15783 * Sets the #ClutterLayoutManager delegate object that will be used to
15784 * lay out the children of @self.
15786 * The #ClutterActor will take a reference on the passed @manager which
15787 * will be released either when the layout manager is removed, or when
15788 * the actor is destroyed.
15793 clutter_actor_set_layout_manager (ClutterActor *self,
15794 ClutterLayoutManager *manager)
15796 ClutterActorPrivate *priv;
15798 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15799 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15803 if (priv->layout_manager != NULL)
15805 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15806 G_CALLBACK (on_layout_manager_changed),
15808 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15809 g_object_unref (priv->layout_manager);
15812 priv->layout_manager = manager;
15814 if (priv->layout_manager != NULL)
15816 g_object_ref_sink (priv->layout_manager);
15817 clutter_layout_manager_set_container (priv->layout_manager,
15818 CLUTTER_CONTAINER (self));
15819 g_signal_connect (priv->layout_manager, "layout-changed",
15820 G_CALLBACK (on_layout_manager_changed),
15824 clutter_actor_queue_relayout (self);
15826 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15830 * clutter_actor_get_layout_manager:
15831 * @self: a #ClutterActor
15833 * Retrieves the #ClutterLayoutManager used by @self.
15835 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15840 ClutterLayoutManager *
15841 clutter_actor_get_layout_manager (ClutterActor *self)
15843 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15845 return self->priv->layout_manager;
15848 static const ClutterLayoutInfo default_layout_info = {
15851 { 0, 0, 0, 0 }, /* margin */
15852 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
15853 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
15854 0.f, 0.f, /* min_width, natural_width */
15855 0.f, 0.f, /* natual_width, natural_height */
15859 layout_info_free (gpointer data)
15861 if (G_LIKELY (data != NULL))
15862 g_slice_free (ClutterLayoutInfo, data);
15866 * _clutter_actor_get_layout_info:
15867 * @self: a #ClutterActor
15869 * Retrieves a pointer to the ClutterLayoutInfo structure.
15871 * If the actor does not have a ClutterLayoutInfo associated to it, one
15872 * will be created and initialized to the default values.
15874 * This function should be used for setters.
15876 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15879 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15881 ClutterLayoutInfo *
15882 _clutter_actor_get_layout_info (ClutterActor *self)
15884 ClutterLayoutInfo *retval;
15886 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15887 if (retval == NULL)
15889 retval = g_slice_new (ClutterLayoutInfo);
15891 *retval = default_layout_info;
15893 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15902 * _clutter_actor_get_layout_info_or_defaults:
15903 * @self: a #ClutterActor
15905 * Retrieves the ClutterLayoutInfo structure associated to an actor.
15907 * If the actor does not have a ClutterLayoutInfo structure associated to it,
15908 * then the default structure will be returned.
15910 * This function should only be used for getters.
15912 * Return value: a const pointer to the ClutterLayoutInfo structure
15914 const ClutterLayoutInfo *
15915 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15917 const ClutterLayoutInfo *info;
15919 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15921 return &default_layout_info;
15927 * clutter_actor_set_x_align:
15928 * @self: a #ClutterActor
15929 * @x_align: the horizontal alignment policy
15931 * Sets the horizontal alignment policy of a #ClutterActor, in case the
15932 * actor received extra horizontal space.
15934 * See also the #ClutterActor:x-align property.
15939 clutter_actor_set_x_align (ClutterActor *self,
15940 ClutterActorAlign x_align)
15942 ClutterLayoutInfo *info;
15944 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15946 info = _clutter_actor_get_layout_info (self);
15948 if (info->x_align != x_align)
15950 info->x_align = x_align;
15952 clutter_actor_queue_relayout (self);
15954 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15959 * clutter_actor_get_x_align:
15960 * @self: a #ClutterActor
15962 * Retrieves the horizontal alignment policy set using
15963 * clutter_actor_set_x_align().
15965 * Return value: the horizontal alignment policy.
15970 clutter_actor_get_x_align (ClutterActor *self)
15972 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15974 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15978 * clutter_actor_set_y_align:
15979 * @self: a #ClutterActor
15980 * @y_align: the vertical alignment policy
15982 * Sets the vertical alignment policy of a #ClutterActor, in case the
15983 * actor received extra vertical space.
15985 * See also the #ClutterActor:y-align property.
15990 clutter_actor_set_y_align (ClutterActor *self,
15991 ClutterActorAlign y_align)
15993 ClutterLayoutInfo *info;
15995 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15997 info = _clutter_actor_get_layout_info (self);
15999 if (info->y_align != y_align)
16001 info->y_align = y_align;
16003 clutter_actor_queue_relayout (self);
16005 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16010 * clutter_actor_get_y_align:
16011 * @self: a #ClutterActor
16013 * Retrieves the vertical alignment policy set using
16014 * clutter_actor_set_y_align().
16016 * Return value: the vertical alignment policy.
16021 clutter_actor_get_y_align (ClutterActor *self)
16023 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16025 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16030 * clutter_margin_new:
16032 * Creates a new #ClutterMargin.
16034 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16035 * clutter_margin_free() to free the resources associated with it when
16041 clutter_margin_new (void)
16043 return g_slice_new0 (ClutterMargin);
16047 * clutter_margin_copy:
16048 * @margin_: a #ClutterMargin
16050 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16051 * the newly created structure.
16053 * Return value: (transfer full): a copy of the #ClutterMargin.
16058 clutter_margin_copy (const ClutterMargin *margin_)
16060 if (G_LIKELY (margin_ != NULL))
16061 return g_slice_dup (ClutterMargin, margin_);
16067 * clutter_margin_free:
16068 * @margin_: a #ClutterMargin
16070 * Frees the resources allocated by clutter_margin_new() and
16071 * clutter_margin_copy().
16076 clutter_margin_free (ClutterMargin *margin_)
16078 if (G_LIKELY (margin_ != NULL))
16079 g_slice_free (ClutterMargin, margin_);
16082 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16083 clutter_margin_copy,
16084 clutter_margin_free)
16087 * clutter_actor_set_margin:
16088 * @self: a #ClutterActor
16089 * @margin: a #ClutterMargin
16091 * Sets all the components of the margin of a #ClutterActor.
16096 clutter_actor_set_margin (ClutterActor *self,
16097 const ClutterMargin *margin)
16099 ClutterLayoutInfo *info;
16103 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16104 g_return_if_fail (margin != NULL);
16106 obj = G_OBJECT (self);
16109 g_object_freeze_notify (obj);
16111 info = _clutter_actor_get_layout_info (self);
16113 if (info->margin.top != margin->top)
16115 info->margin.top = margin->top;
16116 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16120 if (info->margin.right != margin->right)
16122 info->margin.right = margin->right;
16123 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16127 if (info->margin.bottom != margin->bottom)
16129 info->margin.bottom = margin->bottom;
16130 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16134 if (info->margin.left != margin->left)
16136 info->margin.left = margin->left;
16137 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16142 clutter_actor_queue_relayout (self);
16144 g_object_thaw_notify (obj);
16148 * clutter_actor_get_margin:
16149 * @self: a #ClutterActor
16150 * @margin: (out caller-allocates): return location for a #ClutterMargin
16152 * Retrieves all the components of the margin of a #ClutterActor.
16157 clutter_actor_get_margin (ClutterActor *self,
16158 ClutterMargin *margin)
16160 const ClutterLayoutInfo *info;
16162 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16163 g_return_if_fail (margin != NULL);
16165 info = _clutter_actor_get_layout_info_or_defaults (self);
16167 *margin = info->margin;
16171 * clutter_actor_set_margin_top:
16172 * @self: a #ClutterActor
16173 * @margin: the top margin
16175 * Sets the margin from the top of a #ClutterActor.
16180 clutter_actor_set_margin_top (ClutterActor *self,
16183 ClutterLayoutInfo *info;
16185 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16186 g_return_if_fail (margin >= 0.f);
16188 info = _clutter_actor_get_layout_info (self);
16190 if (info->margin.top == margin)
16193 info->margin.top = margin;
16195 clutter_actor_queue_relayout (self);
16197 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16201 * clutter_actor_get_margin_top:
16202 * @self: a #ClutterActor
16204 * Retrieves the top margin of a #ClutterActor.
16206 * Return value: the top margin
16211 clutter_actor_get_margin_top (ClutterActor *self)
16213 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16215 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16219 * clutter_actor_set_margin_bottom:
16220 * @self: a #ClutterActor
16221 * @margin: the bottom margin
16223 * Sets the margin from the bottom of a #ClutterActor.
16228 clutter_actor_set_margin_bottom (ClutterActor *self,
16231 ClutterLayoutInfo *info;
16233 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16234 g_return_if_fail (margin >= 0.f);
16236 info = _clutter_actor_get_layout_info (self);
16238 if (info->margin.bottom == margin)
16241 info->margin.bottom = margin;
16243 clutter_actor_queue_relayout (self);
16245 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16249 * clutter_actor_get_margin_bottom:
16250 * @self: a #ClutterActor
16252 * Retrieves the bottom margin of a #ClutterActor.
16254 * Return value: the bottom margin
16259 clutter_actor_get_margin_bottom (ClutterActor *self)
16261 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16263 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16267 * clutter_actor_set_margin_left:
16268 * @self: a #ClutterActor
16269 * @margin: the left margin
16271 * Sets the margin from the left of a #ClutterActor.
16276 clutter_actor_set_margin_left (ClutterActor *self,
16279 ClutterLayoutInfo *info;
16281 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16282 g_return_if_fail (margin >= 0.f);
16284 info = _clutter_actor_get_layout_info (self);
16286 if (info->margin.left == margin)
16289 info->margin.left = margin;
16291 clutter_actor_queue_relayout (self);
16293 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16297 * clutter_actor_get_margin_left:
16298 * @self: a #ClutterActor
16300 * Retrieves the left margin of a #ClutterActor.
16302 * Return value: the left margin
16307 clutter_actor_get_margin_left (ClutterActor *self)
16309 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16311 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16315 * clutter_actor_set_margin_right:
16316 * @self: a #ClutterActor
16317 * @margin: the right margin
16319 * Sets the margin from the right of a #ClutterActor.
16324 clutter_actor_set_margin_right (ClutterActor *self,
16327 ClutterLayoutInfo *info;
16329 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16330 g_return_if_fail (margin >= 0.f);
16332 info = _clutter_actor_get_layout_info (self);
16334 if (info->margin.right == margin)
16337 info->margin.right = margin;
16339 clutter_actor_queue_relayout (self);
16341 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16345 * clutter_actor_get_margin_right:
16346 * @self: a #ClutterActor
16348 * Retrieves the right margin of a #ClutterActor.
16350 * Return value: the right margin
16355 clutter_actor_get_margin_right (ClutterActor *self)
16357 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16359 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16363 clutter_actor_set_background_color_internal (ClutterActor *self,
16364 const ClutterColor *color)
16366 ClutterActorPrivate *priv = self->priv;
16369 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16372 obj = G_OBJECT (self);
16374 priv->bg_color = *color;
16375 priv->bg_color_set = TRUE;
16377 clutter_actor_queue_redraw (self);
16379 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16380 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16384 * clutter_actor_set_background_color:
16385 * @self: a #ClutterActor
16386 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16389 * Sets the background color of a #ClutterActor.
16391 * The background color will be used to cover the whole allocation of the
16392 * actor. The default background color of an actor is transparent.
16394 * To check whether an actor has a background color, you can use the
16395 * #ClutterActor:background-color-set actor property.
16397 * The #ClutterActor:background-color property is animatable.
16402 clutter_actor_set_background_color (ClutterActor *self,
16403 const ClutterColor *color)
16405 ClutterActorPrivate *priv;
16407 GParamSpec *bg_color_pspec;
16409 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16411 obj = G_OBJECT (self);
16417 priv->bg_color_set = FALSE;
16418 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16419 clutter_actor_queue_redraw (self);
16423 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16424 if (clutter_actor_get_easing_duration (self) != 0)
16426 ClutterTransition *transition;
16428 transition = _clutter_actor_get_transition (self, bg_color_pspec);
16429 if (transition == NULL)
16431 transition = _clutter_actor_create_transition (self, bg_color_pspec,
16434 clutter_timeline_start (CLUTTER_TIMELINE (transition));
16437 _clutter_actor_update_transition (self, bg_color_pspec, color);
16439 clutter_actor_queue_redraw (self);
16442 clutter_actor_set_background_color_internal (self, color);
16446 * clutter_actor_get_background_color:
16447 * @self: a #ClutterActor
16448 * @color: (out caller-allocates): return location for a #ClutterColor
16450 * Retrieves the color set using clutter_actor_set_background_color().
16455 clutter_actor_get_background_color (ClutterActor *self,
16456 ClutterColor *color)
16458 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16459 g_return_if_fail (color != NULL);
16461 *color = self->priv->bg_color;
16465 * clutter_actor_get_previous_sibling:
16466 * @self: a #ClutterActor
16468 * Retrieves the sibling of @self that comes before it in the list
16469 * of children of @self's parent.
16471 * The returned pointer is only valid until the scene graph changes; it
16472 * is not safe to modify the list of children of @self while iterating
16475 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16480 clutter_actor_get_previous_sibling (ClutterActor *self)
16482 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16484 return self->priv->prev_sibling;
16488 * clutter_actor_get_next_sibling:
16489 * @self: a #ClutterActor
16491 * Retrieves the sibling of @self that comes after it in the list
16492 * of children of @self's parent.
16494 * The returned pointer is only valid until the scene graph changes; it
16495 * is not safe to modify the list of children of @self while iterating
16498 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16503 clutter_actor_get_next_sibling (ClutterActor *self)
16505 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16507 return self->priv->next_sibling;
16511 * clutter_actor_get_first_child:
16512 * @self: a #ClutterActor
16514 * Retrieves the first child of @self.
16516 * The returned pointer is only valid until the scene graph changes; it
16517 * is not safe to modify the list of children of @self while iterating
16520 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16525 clutter_actor_get_first_child (ClutterActor *self)
16527 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16529 return self->priv->first_child;
16533 * clutter_actor_get_last_child:
16534 * @self: a #ClutterActor
16536 * Retrieves the last child of @self.
16538 * The returned pointer is only valid until the scene graph changes; it
16539 * is not safe to modify the list of children of @self while iterating
16542 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16547 clutter_actor_get_last_child (ClutterActor *self)
16549 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16551 return self->priv->last_child;
16554 /* easy way to have properly named fields instead of the dummy ones
16555 * we use in the public structure
16557 typedef struct _RealActorIter
16559 ClutterActor *root; /* dummy1 */
16560 ClutterActor *current; /* dummy2 */
16561 gpointer padding_1; /* dummy3 */
16562 gint age; /* dummy4 */
16563 gpointer padding_2; /* dummy5 */
16567 * clutter_actor_iter_init:
16568 * @iter: a #ClutterActorIter
16569 * @root: a #ClutterActor
16571 * Initializes a #ClutterActorIter, which can then be used to iterate
16572 * efficiently over a section of the scene graph, and associates it
16575 * Modifying the scene graph section that contains @root will invalidate
16579 * ClutterActorIter iter;
16580 * ClutterActor *child;
16582 * clutter_actor_iter_init (&iter, container);
16583 * while (clutter_actor_iter_next (&iter, &child))
16585 * /* do something with child */
16592 clutter_actor_iter_init (ClutterActorIter *iter,
16593 ClutterActor *root)
16595 RealActorIter *ri = (RealActorIter *) iter;
16597 g_return_if_fail (iter != NULL);
16598 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16601 ri->current = NULL;
16602 ri->age = root->priv->age;
16606 * clutter_actor_iter_next:
16607 * @iter: a #ClutterActorIter
16608 * @child: (out): return location for a #ClutterActor
16610 * Advances the @iter and retrieves the next child of the root #ClutterActor
16611 * that was used to initialize the #ClutterActorIterator.
16613 * If the iterator can advance, this function returns %TRUE and sets the
16616 * If the iterator cannot advance, this function returns %FALSE, and
16617 * the contents of @child are undefined.
16619 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16624 clutter_actor_iter_next (ClutterActorIter *iter,
16625 ClutterActor **child)
16627 RealActorIter *ri = (RealActorIter *) iter;
16629 g_return_val_if_fail (iter != NULL, FALSE);
16630 g_return_val_if_fail (ri->root != NULL, FALSE);
16631 #ifndef G_DISABLE_ASSERT
16632 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16635 if (ri->current == NULL)
16636 ri->current = ri->root->priv->first_child;
16638 ri->current = ri->current->priv->next_sibling;
16641 *child = ri->current;
16643 return ri->current != NULL;
16647 * clutter_actor_iter_prev:
16648 * @iter: a #ClutterActorIter
16649 * @child: (out): return location for a #ClutterActor
16651 * Advances the @iter and retrieves the previous child of the root
16652 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16654 * If the iterator can advance, this function returns %TRUE and sets the
16657 * If the iterator cannot advance, this function returns %FALSE, and
16658 * the contents of @child are undefined.
16660 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16665 clutter_actor_iter_prev (ClutterActorIter *iter,
16666 ClutterActor **child)
16668 RealActorIter *ri = (RealActorIter *) iter;
16670 g_return_val_if_fail (iter != NULL, FALSE);
16671 g_return_val_if_fail (ri->root != NULL, FALSE);
16672 #ifndef G_DISABLE_ASSERT
16673 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16676 if (ri->current == NULL)
16677 ri->current = ri->root->priv->last_child;
16679 ri->current = ri->current->priv->prev_sibling;
16682 *child = ri->current;
16684 return ri->current != NULL;
16688 * clutter_actor_iter_remove:
16689 * @iter: a #ClutterActorIter
16691 * Safely removes the #ClutterActor currently pointer to by the iterator
16694 * This function can only be called after clutter_actor_iter_next() or
16695 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16696 * than once for the same actor.
16698 * This function will call clutter_actor_remove_child() internally.
16703 clutter_actor_iter_remove (ClutterActorIter *iter)
16705 RealActorIter *ri = (RealActorIter *) iter;
16708 g_return_if_fail (iter != NULL);
16709 g_return_if_fail (ri->root != NULL);
16710 #ifndef G_DISABLE_ASSERT
16711 g_return_if_fail (ri->age == ri->root->priv->age);
16713 g_return_if_fail (ri->current != NULL);
16719 ri->current = cur->priv->prev_sibling;
16721 clutter_actor_remove_child_internal (ri->root, cur,
16722 REMOVE_CHILD_DEFAULT_FLAGS);
16729 * clutter_actor_iter_destroy:
16730 * @iter: a #ClutterActorIter
16732 * Safely destroys the #ClutterActor currently pointer to by the iterator
16735 * This function can only be called after clutter_actor_iter_next() or
16736 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16737 * than once for the same actor.
16739 * This function will call clutter_actor_destroy() internally.
16744 clutter_actor_iter_destroy (ClutterActorIter *iter)
16746 RealActorIter *ri = (RealActorIter *) iter;
16749 g_return_if_fail (iter != NULL);
16750 g_return_if_fail (ri->root != NULL);
16751 #ifndef G_DISABLE_ASSERT
16752 g_return_if_fail (ri->age == ri->root->priv->age);
16754 g_return_if_fail (ri->current != NULL);
16760 ri->current = cur->priv->prev_sibling;
16762 clutter_actor_destroy (cur);
16768 static const ClutterAnimationInfo default_animation_info = {
16769 NULL, /* transitions */
16771 NULL, /* cur_state */
16775 clutter_animation_info_free (gpointer data)
16779 ClutterAnimationInfo *info = data;
16781 if (info->transitions != NULL)
16782 g_hash_table_unref (info->transitions);
16784 if (info->states != NULL)
16785 g_array_unref (info->states);
16787 g_slice_free (ClutterAnimationInfo, info);
16791 const ClutterAnimationInfo *
16792 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16794 const ClutterAnimationInfo *res;
16795 GObject *obj = G_OBJECT (self);
16797 res = g_object_get_qdata (obj, quark_actor_animation_info);
16801 return &default_animation_info;
16804 ClutterAnimationInfo *
16805 _clutter_actor_get_animation_info (ClutterActor *self)
16807 GObject *obj = G_OBJECT (self);
16808 ClutterAnimationInfo *res;
16810 res = g_object_get_qdata (obj, quark_actor_animation_info);
16813 res = g_slice_new (ClutterAnimationInfo);
16815 *res = default_animation_info;
16817 g_object_set_qdata_full (obj, quark_actor_animation_info,
16819 clutter_animation_info_free);
16825 ClutterTransition *
16826 _clutter_actor_get_transition (ClutterActor *actor,
16829 const ClutterAnimationInfo *info;
16831 info = _clutter_actor_get_animation_info_or_defaults (actor);
16833 if (info->transitions == NULL)
16836 return g_hash_table_lookup (info->transitions, pspec->name);
16839 typedef struct _TransitionClosure
16841 ClutterActor *actor;
16842 ClutterTransition *transition;
16844 gulong completed_id;
16845 } TransitionClosure;
16848 transition_closure_free (gpointer data)
16850 if (G_LIKELY (data != NULL))
16852 TransitionClosure *clos = data;
16854 g_signal_handler_disconnect (clos->transition, clos->completed_id);
16855 g_free (clos->name);
16857 g_slice_free (TransitionClosure, clos);
16862 on_transition_completed (ClutterTransition *transition,
16863 TransitionClosure *clos)
16865 ClutterAnimationInfo *info;
16867 info = _clutter_actor_get_animation_info (clos->actor);
16869 /* this will take care of cleaning clos for us */
16870 g_hash_table_remove (info->transitions, clos->name);
16874 _clutter_actor_update_transition (ClutterActor *actor,
16878 TransitionClosure *clos;
16879 ClutterInterval *interval;
16880 const ClutterAnimationInfo *info;
16883 GValue initial = G_VALUE_INIT;
16884 GValue final = G_VALUE_INIT;
16885 char *error = NULL;
16887 info = _clutter_actor_get_animation_info_or_defaults (actor);
16889 if (info->transitions == NULL)
16892 clos = g_hash_table_lookup (info->transitions, pspec->name);
16896 va_start (var_args, pspec);
16898 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16900 g_value_init (&initial, ptype);
16901 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16905 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16908 g_critical ("%s: %s", G_STRLOC, error);
16913 interval = clutter_transition_get_interval (clos->transition);
16914 clutter_interval_set_initial_value (interval, &initial);
16915 clutter_interval_set_final_value (interval, &final);
16917 clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16920 g_value_unset (&initial);
16921 g_value_unset (&final);
16927 * _clutter_actor_create_transition:
16928 * @actor: a #ClutterActor
16929 * @pspec: the property used for the transition
16930 * @...: initial and final state
16932 * Creates a #ClutterTransition for the property represented by @pspec.
16934 * Return value: a #ClutterTransition
16936 ClutterTransition *
16937 _clutter_actor_create_transition (ClutterActor *actor,
16941 ClutterAnimationInfo *info;
16942 ClutterTransition *res = NULL;
16943 gboolean call_restore = FALSE;
16944 TransitionClosure *clos;
16947 info = _clutter_actor_get_animation_info (actor);
16949 if (info->states == NULL)
16951 clutter_actor_save_easing_state (actor);
16952 call_restore = TRUE;
16955 if (info->transitions == NULL)
16956 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
16958 transition_closure_free);
16960 va_start (var_args, pspec);
16962 clos = g_hash_table_lookup (info->transitions, pspec->name);
16965 ClutterInterval *interval;
16966 GValue initial = G_VALUE_INIT;
16967 GValue final = G_VALUE_INIT;
16971 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16973 G_VALUE_COLLECT_INIT (&initial, ptype,
16978 g_critical ("%s: %s", G_STRLOC, error);
16983 G_VALUE_COLLECT_INIT (&final, ptype,
16989 g_critical ("%s: %s", G_STRLOC, error);
16990 g_value_unset (&initial);
16995 interval = clutter_interval_new_with_values (ptype, &initial, &final);
16997 g_value_unset (&initial);
16998 g_value_unset (&final);
17000 res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17003 clutter_transition_set_interval (res, interval);
17004 clutter_transition_set_remove_on_complete (res, TRUE);
17006 clutter_actor_add_transition (actor, pspec->name, res);
17009 res = clos->transition;
17013 clutter_actor_restore_easing_state (actor);
17021 * clutter_actor_add_transition:
17022 * @self: a #ClutterActor
17023 * @name: the name of the transition to add
17024 * @transition: the #ClutterTransition to add
17026 * Adds a @transition to the #ClutterActor's list of animations.
17028 * The @name string is a per-actor unique identifier of the @transition: only
17029 * one #ClutterTransition can be associated to the specified @name.
17031 * The @transition will be given the easing duration, mode, and delay
17032 * associated to the actor's current easing state; it is possible to modify
17033 * these values after calling clutter_actor_add_transition().
17035 * This function is usually called implicitly when modifying an animatable
17041 clutter_actor_add_transition (ClutterActor *self,
17043 ClutterTransition *transition)
17045 ClutterTimeline *timeline;
17046 TransitionClosure *clos;
17047 ClutterAnimationInfo *info;
17049 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17050 g_return_if_fail (name != NULL);
17051 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17053 info = _clutter_actor_get_animation_info (self);
17055 if (info->cur_state == NULL)
17057 g_warning ("No easing state is defined for the actor '%s'; you "
17058 "must call clutter_actor_save_easing_state() before "
17059 "calling clutter_actor_add_transition().",
17060 _clutter_actor_get_debug_name (self));
17064 if (info->transitions == NULL)
17065 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17067 transition_closure_free);
17069 if (g_hash_table_lookup (info->transitions, name) != NULL)
17071 g_warning ("A transition with name '%s' already exists for "
17074 _clutter_actor_get_debug_name (self));
17078 timeline = CLUTTER_TIMELINE (transition);
17080 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17081 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17082 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17084 clos = g_slice_new (TransitionClosure);
17085 clos->actor = self;
17086 clos->transition = transition;
17087 clos->name = g_strdup (name);
17088 clos->completed_id = g_signal_connect (timeline, "completed",
17089 G_CALLBACK (on_transition_completed),
17092 g_hash_table_insert (info->transitions, clos->name, clos);
17096 * clutter_actor_remove_transition:
17097 * @self: a #ClutterActor
17098 * @name: the name of the transition to remove
17100 * Removes the transition stored inside a #ClutterActor using @name
17106 clutter_actor_remove_transition (ClutterActor *self,
17109 const ClutterAnimationInfo *info;
17111 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17112 g_return_if_fail (name != NULL);
17114 info = _clutter_actor_get_animation_info_or_defaults (self);
17116 if (info->transitions == NULL)
17119 g_hash_table_remove (info->transitions, name);
17123 * clutter_actor_remove_all_transitions:
17124 * @self: a #ClutterActor
17126 * Removes all transitions associated to @self.
17131 clutter_actor_remove_all_transitions (ClutterActor *self)
17133 const ClutterAnimationInfo *info;
17135 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17137 info = _clutter_actor_get_animation_info_or_defaults (self);
17138 if (info->transitions == NULL)
17141 g_hash_table_remove_all (info->transitions);
17145 * clutter_actor_set_easing_duration:
17146 * @self: a #ClutterActor
17147 * @msecs: the duration of the easing, or %NULL
17149 * Sets the duration of the tweening for animatable properties
17150 * of @self for the current easing state.
17152 * Calling this function will implicitly call
17153 * clutter_actor_save_easing_state() if no previous call to
17154 * that function was made.
17159 clutter_actor_set_easing_duration (ClutterActor *self,
17162 ClutterAnimationInfo *info;
17164 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17166 info = _clutter_actor_get_animation_info (self);
17168 if (info->states == NULL)
17169 clutter_actor_save_easing_state (self);
17171 if (info->cur_state->easing_duration != msecs)
17172 info->cur_state->easing_duration = msecs;
17176 * clutter_actor_get_easing_duration:
17177 * @self: a #ClutterActor
17179 * Retrieves the duration of the tweening for animatable
17180 * properties of @self for the current easing state.
17182 * Return value: the duration of the tweening, in milliseconds
17187 clutter_actor_get_easing_duration (ClutterActor *self)
17189 const ClutterAnimationInfo *info;
17191 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17193 info = _clutter_actor_get_animation_info_or_defaults (self);
17195 if (info->cur_state != NULL)
17196 return info->cur_state->easing_duration;
17202 * clutter_actor_set_easing_mode:
17203 * @self: a #ClutterActor
17204 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17206 * Sets the easing mode for the tweening of animatable properties
17209 * Calling this function will implicitly call
17210 * clutter_actor_save_easing_state() if no previous calls to
17211 * that function were made.
17216 clutter_actor_set_easing_mode (ClutterActor *self,
17217 ClutterAnimationMode mode)
17219 ClutterAnimationInfo *info;
17221 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17222 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17223 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17225 info = _clutter_actor_get_animation_info (self);
17227 if (info->states == NULL)
17228 clutter_actor_save_easing_state (self);
17230 if (info->cur_state->easing_mode != mode)
17231 info->cur_state->easing_mode = mode;
17235 * clutter_actor_get_easing_mode:
17236 * @self: a #ClutterActor
17238 * Retrieves the easing mode for the tweening of animatable properties
17239 * of @self for the current easing state.
17241 * Return value: an easing mode
17245 ClutterAnimationMode
17246 clutter_actor_get_easing_mode (ClutterActor *self)
17248 const ClutterAnimationInfo *info;
17250 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17252 info = _clutter_actor_get_animation_info_or_defaults (self);
17254 if (info->cur_state != NULL)
17255 return info->cur_state->easing_mode;
17257 return CLUTTER_EASE_OUT_CUBIC;
17261 * clutter_actor_set_easing_delay:
17262 * @self: a #ClutterActor
17263 * @msecs: the delay before the start of the tweening, in milliseconds
17265 * Sets the delay that should be applied before tweening animatable
17268 * Calling this function will implicitly call
17269 * clutter_actor_save_easing_state() if no previous calls to
17270 * that function were made.
17275 clutter_actor_set_easing_delay (ClutterActor *self,
17278 ClutterAnimationInfo *info;
17280 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17282 info = _clutter_actor_get_animation_info (self);
17284 if (info->states == NULL)
17285 clutter_actor_save_easing_state (self);
17287 if (info->cur_state->easing_delay != msecs)
17288 info->cur_state->easing_delay = msecs;
17292 * clutter_actor_get_easing_delay:
17293 * @self: a #ClutterActor
17295 * Retrieves the delay that should be applied when tweening animatable
17298 * Return value: a delay, in milliseconds
17303 clutter_actor_get_easing_delay (ClutterActor *self)
17305 const ClutterAnimationInfo *info;
17307 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17309 info = _clutter_actor_get_animation_info_or_defaults (self);
17311 if (info->cur_state != NULL)
17312 return info->cur_state->easing_delay;
17318 * clutter_actor_get_transition:
17319 * @self: a #ClutterActor
17320 * @name: the name of the transition
17322 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17323 * transition @name.
17325 * Transitions created for animatable properties use the name of the
17326 * property itself, for instance the code below:
17329 * clutter_actor_set_easing_duration (actor, 1000);
17330 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17332 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17333 * g_signal_connect (transition, "completed",
17334 * G_CALLBACK (on_transition_complete),
17338 * will call the <function>on_transition_complete</function> callback when
17339 * the transition is complete.
17341 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17342 * was found to match the passed name; the returned instance is owned
17343 * by Clutter and it should not be freed
17347 ClutterTransition *
17348 clutter_actor_get_transition (ClutterActor *self,
17351 TransitionClosure *clos;
17352 const ClutterAnimationInfo *info;
17354 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17355 g_return_val_if_fail (name != NULL, NULL);
17357 info = _clutter_actor_get_animation_info_or_defaults (self);
17359 if (info->transitions == NULL)
17362 clos = g_hash_table_lookup (info->transitions, name);
17366 return clos->transition;
17370 * clutter_actor_save_easing_state:
17371 * @self: a #ClutterActor
17373 * Saves the current easing state for animatable properties, and creates
17374 * a new state with the default values for easing mode and duration.
17379 clutter_actor_save_easing_state (ClutterActor *self)
17381 ClutterAnimationInfo *info;
17384 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17386 info = _clutter_actor_get_animation_info (self);
17388 if (info->states == NULL)
17389 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17391 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17392 new_state.easing_duration = 250;
17393 new_state.easing_delay = 0;
17395 g_array_append_val (info->states, new_state);
17397 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17401 * clutter_actor_restore_easing_state:
17402 * @self: a #ClutterActor
17404 * Restores the easing state as it was prior to a call to
17405 * clutter_actor_save_easing_state().
17410 clutter_actor_restore_easing_state (ClutterActor *self)
17412 ClutterAnimationInfo *info;
17414 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17416 info = _clutter_actor_get_animation_info (self);
17418 if (info->states == NULL)
17420 g_critical ("The function clutter_actor_restore_easing_state() has "
17421 "called without a previous call to "
17422 "clutter_actor_save_easing_state().");
17426 g_array_remove_index (info->states, info->states->len - 1);
17427 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17431 * clutter_actor_set_content:
17432 * @self: a #ClutterActor
17433 * @content: (allow-none): a #ClutterContent, or %NULL
17435 * Sets the contents of a #ClutterActor.
17440 clutter_actor_set_content (ClutterActor *self,
17441 ClutterContent *content)
17443 ClutterActorPrivate *priv;
17445 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17446 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17450 if (priv->content != NULL)
17452 _clutter_content_detached (priv->content, self);
17453 g_object_unref (priv->content);
17456 priv->content = content;
17458 if (priv->content != NULL)
17460 g_object_ref (priv->content);
17461 _clutter_content_attached (priv->content, self);
17464 /* given that the content is always painted within the allocation,
17465 * we only need to queue a redraw here
17467 clutter_actor_queue_redraw (self);
17469 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17471 /* if the content gravity is not resize-fill, and the new content has a
17472 * different preferred size than the previous one, then the content box
17473 * may have been changed. since we compute that lazily, we just notify
17474 * here, and let whomever watches :content-box do whatever they need to
17477 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17478 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17482 * clutter_actor_get_content:
17483 * @self: a #ClutterActor
17485 * Retrieves the contents of @self.
17487 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17488 * or %NULL if none was set
17493 clutter_actor_get_content (ClutterActor *self)
17495 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17497 return self->priv->content;
17501 * clutter_actor_set_content_gravity:
17502 * @self: a #ClutterActor
17503 * @gravity: the #ClutterContentGravity
17505 * Sets the gravity of the #ClutterContent used by @self.
17507 * See the description of the #ClutterActor:content-gravity property for
17508 * more information.
17513 clutter_actor_set_content_gravity (ClutterActor *self,
17514 ClutterContentGravity gravity)
17516 ClutterActorPrivate *priv;
17518 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17522 if (priv->content_gravity == gravity)
17525 priv->content_gravity = gravity;
17527 clutter_actor_queue_redraw (self);
17529 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17530 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17534 * clutter_actor_get_content_gravity:
17535 * @self: a #ClutterActor
17537 * Retrieves the content gravity as set using
17538 * clutter_actor_get_content_gravity().
17540 * Return value: the content gravity
17544 ClutterContentGravity
17545 clutter_actor_get_content_gravity (ClutterActor *self)
17547 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17548 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17550 return self->priv->content_gravity;
17554 * clutter_actor_get_content_box:
17555 * @self: a #ClutterActor
17556 * @box: (out caller-allocates): the return location for the bounding
17557 * box for the #ClutterContent
17559 * Retrieves the bounding box for the #ClutterContent of @self.
17561 * If no #ClutterContent is set for @self, or if @self has not been
17562 * allocated yet, then the result is undefined.
17564 * The content box is guaranteed to be, at most, as big as the allocation
17565 * of the #ClutterActor.
17567 * If the #ClutterContent used by the actor has a preferred size, then
17568 * it is possible to modify the content box by using the
17569 * #ClutterActor:content-gravity property.
17574 clutter_actor_get_content_box (ClutterActor *self,
17575 ClutterActorBox *box)
17577 ClutterActorPrivate *priv;
17578 gfloat content_w, content_h;
17579 gfloat alloc_w, alloc_h;
17581 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17582 g_return_if_fail (box != NULL);
17586 if (!clutter_actor_has_allocation (self))
17589 if (priv->content == NULL)
17592 *box = priv->allocation;
17594 /* no need to do any more work */
17595 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17598 /* if the content does not have a preferred size then there is
17599 * no point in computing the content box
17601 if (!_clutter_content_get_preferred_size (priv->content,
17606 clutter_actor_box_get_size (&priv->allocation, &alloc_w, &alloc_h);
17608 switch (priv->content_gravity)
17610 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17611 box->x2 = box->x1 + MIN (content_w, alloc_w);
17612 box->y2 = box->y1 + MIN (content_h, alloc_h);
17615 case CLUTTER_CONTENT_GRAVITY_TOP:
17616 if (alloc_w > content_w)
17618 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17619 box->x2 = box->x1 + content_w;
17621 box->y2 = box->y1 + MIN (content_h, alloc_h);
17624 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17625 if (alloc_w > content_w)
17627 box->x1 += (alloc_w - content_w);
17628 box->x2 = box->x1 + content_w;
17630 box->y2 = box->y1 + MIN (content_h, alloc_h);
17633 case CLUTTER_CONTENT_GRAVITY_LEFT:
17634 box->x2 = box->x1 + MIN (content_w, alloc_w);
17635 if (alloc_h > content_h)
17637 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17638 box->y2 = box->y1 + content_h;
17642 case CLUTTER_CONTENT_GRAVITY_CENTER:
17643 if (alloc_w > content_w)
17645 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17646 box->x2 = box->x1 + content_w;
17648 if (alloc_h > content_h)
17650 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17651 box->y2 = box->y1 + content_h;
17655 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17656 if (alloc_w > content_w)
17658 box->x1 += (alloc_w - content_w);
17659 box->x2 = box->x1 + content_w;
17661 if (alloc_h > content_h)
17663 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17664 box->y2 = box->y1 + content_h;
17668 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17669 box->x2 = box->x1 + MIN (content_w, alloc_w);
17670 if (alloc_h > content_h)
17672 box->y1 += (alloc_h - content_h);
17673 box->y2 = box->y1 + content_h;
17677 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17678 if (alloc_w > content_w)
17680 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17681 box->x2 = box->x1 + content_w;
17683 if (alloc_h > content_h)
17685 box->y1 += (alloc_h - content_h);
17686 box->y2 = box->y1 + content_h;
17690 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17691 if (alloc_w > content_w)
17693 box->x1 += (alloc_w - content_w);
17694 box->x2 = box->x1 + content_w;
17696 if (alloc_h > content_h)
17698 box->y1 += (alloc_h - content_h);
17699 box->y2 = box->y1 + content_h;
17703 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17704 g_assert_not_reached ();
17707 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17708 if (content_w >= content_h && content_h > 0)
17710 double ratio = content_w / content_h;
17712 box->x2 = box->x1 + alloc_w;
17714 box->y1 += ceilf ((alloc_h - (alloc_h / ratio)) / 2.0);
17715 box->y2 = box->y1 + (alloc_h / ratio);
17717 else if (content_h > content_w && content_w > 0)
17719 double ratio = content_h / content_w;
17721 box->x1 += ceilf ((alloc_w - (alloc_w / ratio)) / 2.0);
17722 box->x2 = box->x2 + (alloc_w / ratio);
17724 box->y2 = box->x1 + alloc_h;