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-events">
119 * <title>Handling events on an actor</title>
120 * <para>A #ClutterActor can receive and handle input device events, for
121 * instance pointer events and key events, as long as its
122 * #ClutterActor:reactive property is set to %TRUE.</para>
123 * <para>Once an actor has been determined to be the source of an event,
124 * Clutter will traverse the scene graph from the top-level actor towards the
125 * event source, emitting the #ClutterActor::captured-event signal on each
126 * ancestor until it reaches the source; this phase is also called
127 * <emphasis>the capture phase</emphasis>. If the event propagation was not
128 * stopped, the graph is walked backwards, from the source actor to the
129 * top-level, and the #ClutterActor::event signal, along with other event
130 * signals if needed, is emitted; this phase is also called <emphasis>the
131 * bubble phase</emphasis>. At any point of the signal emission, signal
132 * handlers can stop the propagation through the scene graph by returning
133 * %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134 * returning %CLUTTER_EVENT_PROPAGATE.</para>
137 * <refsect2 id="ClutterActor-subclassing">
138 * <title>Implementing an actor</title>
139 * <para>Careful consideration should be given when deciding to implement
140 * a #ClutterActor sub-class. It is generally recommended to implement a
141 * sub-class of #ClutterActor only for actors that should be used as leaf
142 * nodes of a scene graph.</para>
143 * <para>If your actor should be painted in a custom way, you should
144 * override the #ClutterActor::paint signal class handler. You can either
145 * opt to chain up to the parent class implementation or decide to fully
146 * override the default paint implementation; Clutter will set up the
147 * transformations and clip regions prior to emitting the #ClutterActor::paint
149 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
150 * #ClutterActorClass.get_preferred_height() virtual functions it is
151 * possible to change or provide the preferred size of an actor; similarly,
152 * by overriding the #ClutterActorClass.allocate() virtual function it is
153 * possible to control the layout of the children of an actor. Make sure to
154 * always chain up to the parent implementation of the
155 * #ClutterActorClass.allocate() virtual function.</para>
156 * <para>In general, it is strongly encouraged to use delegation and
157 * composition instead of direct subclassing.</para>
160 * <refsect2 id="ClutterActor-script">
161 * <title>ClutterActor custom properties for #ClutterScript</title>
162 * <para>#ClutterActor defines a custom "rotation" property which
163 * allows a short-hand description of the rotations to be applied
164 * to an actor.</para>
165 * <para>The syntax of the "rotation" property is the following:</para>
169 * { "<axis>" : [ <angle>, [ <center> ] ] }
173 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175 * floating point value representing the rotation angle on the given axis,
177 * <para>The <emphasis>center</emphasis> array is optional, and if present
178 * it must contain the center of rotation as described by two coordinates:
179 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
181 * <para>#ClutterActor will also parse every positional and dimensional
182 * property defined as a string through clutter_units_from_string(); you
183 * should read the documentation for the #ClutterUnits parser format for
184 * the valid units and syntax.</para>
187 * <refsect2 id="ClutterActor-animating">
188 * <title>Custom animatable properties</title>
189 * <para>#ClutterActor allows accessing properties of #ClutterAction
190 * and #ClutterConstraint instances associated to an actor instance
191 * for animation purposes.</para>
192 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193 * property it is necessary to set the #ClutterActorMeta:name property on the
194 * given action or constraint.</para>
195 * <para>The property can be accessed using the following syntax:</para>
198 * @<section>.<meta-name>.<property-name>
201 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202 * <para>The <emphasis>section</emphasis> fragment can be one between
203 * "actions", "constraints" and "effects".</para>
204 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205 * action or constraint, as specified by the #ClutterActorMeta:name
207 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
208 * action or constraint property to be animated.</para>
209 * <para>The example below animates a #ClutterBindConstraint applied to an
210 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
212 * its initial state is fully transparent and overlapping the actor to
213 * which is bound to. </para>
214 * <informalexample><programlisting>
215 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217 * clutter_actor_add_constraint (rect, constraint);
219 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221 * clutter_actor_add_constraint (rect, constraint);
223 * clutter_actor_set_reactive (rect, TRUE);
224 * clutter_actor_set_opacity (rect, 0);
226 * g_signal_connect (rect, "button-press-event",
227 * G_CALLBACK (on_button_press),
229 * </programlisting></informalexample>
230 * <para>On button press, the rectangle "slides" from behind the actor to
231 * which is bound to, using the #ClutterBindConstraint:offset property and
232 * the #ClutterActor:opacity property.</para>
233 * <informalexample><programlisting>
234 * float new_offset = clutter_actor_get_width (origin) + h_padding;
236 * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
238 * "@constraints.bind-x.offset", new_offset,
240 * </programlisting></informalexample>
243 * <refsect2 id="ClutterActor-animatable-properties">
244 * <title>Animatable properties</title>
245 * <para>Certain properties on #ClutterActor are marked as "animatable";
246 * these properties will be automatically tweened between the current
247 * value and the new value when one is set.</para>
248 * <para>For backward compatibility, animatable properties will only be
249 * tweened if the easing duration is greater than 0, or if a new easing
250 * state is set, for instance the following example:</para>
251 * <informalexample><programlisting>
252 * clutter_actor_save_easing_state (actor);
253 * clutter_actor_set_position (actor, 200, 200);
254 * clutter_actor_restore_easing_state (actor);
255 * </programlisting></informalexample>
256 * <para>will tween the actor to the (200, 200) coordinates using the default
257 * easing mode and duration of a new easing state. The example above is
258 * equivalent to the following code:</para>
259 * <informalexample><programlisting>
260 * clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
261 * clutter_actor_set_easing_duration (actor, 250);
262 * clutter_actor_set_position (actor, 200, 200);
263 * clutter_actor_restore_easing_state (actor);
264 * </programlisting></informalexample>
265 * <para>It is possible to nest easing states to tween animatable
266 * properties using different modes and durations, for instance:</para>
267 * <informalexample><programlisting>
268 * clutter_actor_save_easing_state (actor); /* outer state */
270 * /* set the duration of the animation to 2 seconds and change position */
271 * clutter_actor_set_easing_duration (actor, 2000);
272 * clutter_actor_set_position (actor, 0, 0);
274 * clutter_actor_save_easing_state (actor); /* inner state */
276 * /* set the duration of the animation to 5 seconds and change depth and opacity */
277 * clutter_actor_set_easing_duration (actor, 5000);
278 * clutter_actor_set_depth (actor, 200);
279 * clutter_actor_set_opacity (actor, 0);
281 * clutter_actor_restore_easing_state (actor);
283 * clutter_actor_restore_easing_state (actor);
284 * </programlisting></informalexample>
289 * CLUTTER_ACTOR_IS_MAPPED:
290 * @a: a #ClutterActor
292 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
294 * The mapped state is set when the actor is visible and all its parents up
295 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
297 * This check can be used to see if an actor is going to be painted, as only
298 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
300 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
301 * not be checked directly; instead, the recommended usage is to connect a
302 * handler on the #GObject::notify signal for the #ClutterActor:mapped
303 * property of #ClutterActor, and check the presence of
304 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
306 * It is also important to note that Clutter may delay the changes of
307 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
308 * limitations, or during the reparenting of an actor, to optimize
309 * unnecessary (and potentially expensive) state changes.
315 * CLUTTER_ACTOR_IS_REALIZED:
316 * @a: a #ClutterActor
318 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
320 * The realized state has an actor-dependant interpretation. If an
321 * actor wants to delay allocating resources until it is attached to a
322 * stage, it may use the realize state to do so. However it is
323 * perfectly acceptable for an actor to allocate Cogl resources before
324 * being realized because there is only one drawing context used by Clutter
325 * so any resources will work on any stage. If an actor is mapped it
326 * must also be realized, but an actor can be realized and unmapped
327 * (this is so hiding an actor temporarily doesn't do an expensive
328 * unrealize/realize).
330 * To be realized an actor must be inside a stage, and all its parents
337 * CLUTTER_ACTOR_IS_VISIBLE:
338 * @a: a #ClutterActor
340 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
341 * Equivalent to the ClutterActor::visible object property.
343 * Note that an actor is only painted onscreen if it's mapped, which
344 * means it's visible, and all its parents are visible, and one of the
345 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
351 * CLUTTER_ACTOR_IS_REACTIVE:
352 * @a: a #ClutterActor
354 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
356 * Only reactive actors will receive event-related signals.
367 #include <gobject/gvaluecollector.h>
369 #include <cogl/cogl.h>
371 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
372 #define CLUTTER_ENABLE_EXPERIMENTAL_API
374 #include "clutter-actor-private.h"
376 #include "clutter-action.h"
377 #include "clutter-actor-meta-private.h"
378 #include "clutter-animatable.h"
379 #include "clutter-color-static.h"
380 #include "clutter-color.h"
381 #include "clutter-constraint.h"
382 #include "clutter-container.h"
383 #include "clutter-content-private.h"
384 #include "clutter-debug.h"
385 #include "clutter-effect-private.h"
386 #include "clutter-enum-types.h"
387 #include "clutter-fixed-layout.h"
388 #include "clutter-flatten-effect.h"
389 #include "clutter-interval.h"
390 #include "clutter-main.h"
391 #include "clutter-marshal.h"
392 #include "clutter-paint-nodes.h"
393 #include "clutter-paint-node-private.h"
394 #include "clutter-paint-volume-private.h"
395 #include "clutter-private.h"
396 #include "clutter-profile.h"
397 #include "clutter-property-transition.h"
398 #include "clutter-scriptable.h"
399 #include "clutter-script-private.h"
400 #include "clutter-stage-private.h"
401 #include "clutter-timeline.h"
402 #include "clutter-transition.h"
403 #include "clutter-units.h"
405 #include "deprecated/clutter-actor.h"
406 #include "deprecated/clutter-behaviour.h"
407 #include "deprecated/clutter-container.h"
409 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
410 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
412 /* Internal enum used to control mapped state update. This is a hint
413 * which indicates when to do something other than just enforce
417 MAP_STATE_CHECK, /* just enforce invariants. */
418 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
419 * used when about to unparent.
421 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
422 * used to set mapped on toplevels.
424 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
425 * used just before unmapping parent.
429 /* 3 entries should be a good compromise, few layout managers
430 * will ask for 3 different preferred size in each allocation cycle */
431 #define N_CACHED_SIZE_REQUESTS 3
433 struct _ClutterActorPrivate
436 ClutterRequestMode request_mode;
438 /* our cached size requests for different width / height */
439 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
440 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
442 /* An age of 0 means the entry is not set */
443 guint cached_height_age;
444 guint cached_width_age;
446 /* the bounding box of the actor, relative to the parent's
449 ClutterActorBox allocation;
450 ClutterAllocationFlags allocation_flags;
452 /* clip, in actor coordinates */
453 cairo_rectangle_t clip;
455 /* the cached transformation matrix; see apply_transform() */
456 CoglMatrix transform;
459 gint opacity_override;
461 ClutterOffscreenRedirect offscreen_redirect;
463 /* This is an internal effect used to implement the
464 offscreen-redirect property */
465 ClutterEffect *flatten_effect;
468 ClutterActor *parent;
469 ClutterActor *prev_sibling;
470 ClutterActor *next_sibling;
471 ClutterActor *first_child;
472 ClutterActor *last_child;
476 /* tracks whenever the children of an actor are changed; the
477 * age is incremented by 1 whenever an actor is added or
478 * removed. the age is not incremented when the first or the
479 * last child pointers are changed, or when grandchildren of
480 * an actor are changed.
484 gchar *name; /* a non-unique name, used for debugging */
485 guint32 id; /* unique id, used for backward compatibility */
487 gint32 pick_id; /* per-stage unique id, used for picking */
489 /* a back-pointer to the Pango context that we can use
490 * to create pre-configured PangoLayout
492 PangoContext *pango_context;
494 /* the text direction configured for this child - either by
495 * application code, or by the actor's parent
497 ClutterTextDirection text_direction;
499 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
503 ClutterMetaGroup *actions;
504 ClutterMetaGroup *constraints;
505 ClutterMetaGroup *effects;
507 /* delegate object used to allocate the children of this actor */
508 ClutterLayoutManager *layout_manager;
510 /* delegate object used to paint the contents of this actor */
511 ClutterContent *content;
513 ClutterContentGravity content_gravity;
515 /* used when painting, to update the paint volume */
516 ClutterEffect *current_effect;
518 /* This is used to store an effect which needs to be redrawn. A
519 redraw can be queued to start from a particular effect. This is
520 used by parametrised effects that can cache an image of the
521 actor. If a parameter of the effect changes then it only needs to
522 redraw the cached image, not the actual actor. The pointer is
523 only valid if is_dirty == TRUE. If the pointer is NULL then the
524 whole actor is dirty. */
525 ClutterEffect *effect_to_redraw;
527 /* This is used when painting effects to implement the
528 clutter_actor_continue_paint() function. It points to the node in
529 the list of effects that is next in the chain */
530 const GList *next_effect_to_paint;
532 ClutterPaintVolume paint_volume;
534 /* NB: This volume isn't relative to this actor, it is in eye
535 * coordinates so that it can remain valid after the actor changes.
537 ClutterPaintVolume last_paint_volume;
539 ClutterStageQueueRedrawEntry *queue_redraw_entry;
541 ClutterColor bg_color;
545 /* fixed position and sizes */
546 guint position_set : 1;
547 guint min_width_set : 1;
548 guint min_height_set : 1;
549 guint natural_width_set : 1;
550 guint natural_height_set : 1;
551 /* cached request is invalid (implies allocation is too) */
552 guint needs_width_request : 1;
553 /* cached request is invalid (implies allocation is too) */
554 guint needs_height_request : 1;
555 /* cached allocation is invalid (request has changed, probably) */
556 guint needs_allocation : 1;
557 guint show_on_set_parent : 1;
559 guint clip_to_allocation : 1;
560 guint enable_model_view_transform : 1;
561 guint enable_paint_unmapped : 1;
562 guint has_pointer : 1;
563 guint propagated_one_redraw : 1;
564 guint paint_volume_valid : 1;
565 guint last_paint_volume_valid : 1;
566 guint in_clone_paint : 1;
567 guint transform_valid : 1;
568 /* This is TRUE if anything has queued a redraw since we were last
569 painted. In this case effect_to_redraw will point to an effect
570 the redraw was queued from or it will be NULL if the redraw was
571 queued without an effect. */
573 guint bg_color_set : 1;
582 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
583 * when set they force a size request, when gotten they
584 * get the allocation if the allocation is valid, and the
592 /* Then the rest of these size-related properties are the "actual"
593 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
598 PROP_FIXED_POSITION_SET,
607 PROP_NATURAL_WIDTH_SET,
610 PROP_NATURAL_HEIGHT_SET,
614 /* Allocation properties are read-only */
621 PROP_CLIP_TO_ALLOCATION,
625 PROP_OFFSCREEN_REDIRECT,
638 PROP_ROTATION_ANGLE_X,
639 PROP_ROTATION_ANGLE_Y,
640 PROP_ROTATION_ANGLE_Z,
641 PROP_ROTATION_CENTER_X,
642 PROP_ROTATION_CENTER_Y,
643 PROP_ROTATION_CENTER_Z,
644 /* This property only makes sense for the z rotation because the
645 others would depend on the actor having a size along the
647 PROP_ROTATION_CENTER_Z_GRAVITY,
653 PROP_SHOW_ON_SET_PARENT,
671 PROP_BACKGROUND_COLOR,
672 PROP_BACKGROUND_COLOR_SET,
678 PROP_CONTENT_GRAVITY,
684 static GParamSpec *obj_props[PROP_LAST];
703 BUTTON_RELEASE_EVENT,
715 static guint actor_signals[LAST_SIGNAL] = { 0, };
717 static void clutter_container_iface_init (ClutterContainerIface *iface);
718 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
719 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
720 static void atk_implementor_iface_init (AtkImplementorIface *iface);
722 /* These setters are all static for now, maybe they should be in the
723 * public API, but they are perhaps obscure enough to leave only as
726 static void clutter_actor_set_min_width (ClutterActor *self,
728 static void clutter_actor_set_min_height (ClutterActor *self,
730 static void clutter_actor_set_natural_width (ClutterActor *self,
731 gfloat natural_width);
732 static void clutter_actor_set_natural_height (ClutterActor *self,
733 gfloat natural_height);
734 static void clutter_actor_set_min_width_set (ClutterActor *self,
735 gboolean use_min_width);
736 static void clutter_actor_set_min_height_set (ClutterActor *self,
737 gboolean use_min_height);
738 static void clutter_actor_set_natural_width_set (ClutterActor *self,
739 gboolean use_natural_width);
740 static void clutter_actor_set_natural_height_set (ClutterActor *self,
741 gboolean use_natural_height);
742 static void clutter_actor_update_map_state (ClutterActor *self,
743 MapStateChange change);
744 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
746 /* Helper routines for managing anchor coords */
747 static void clutter_anchor_coord_get_units (ClutterActor *self,
748 const AnchorCoord *coord,
752 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
757 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
758 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
759 ClutterGravity gravity);
761 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
763 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
765 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
766 ClutterActor *ancestor,
769 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
771 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
773 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
774 const ClutterColor *color);
776 static void on_layout_manager_changed (ClutterLayoutManager *manager,
779 /* Helper macro which translates by the anchor coord, applies the
780 given transformation and then translates back */
781 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
782 gfloat _tx, _ty, _tz; \
783 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
784 cogl_matrix_translate ((m), _tx, _ty, _tz); \
786 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
788 static GQuark quark_shader_data = 0;
789 static GQuark quark_actor_layout_info = 0;
790 static GQuark quark_actor_transform_info = 0;
791 static GQuark quark_actor_animation_info = 0;
793 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
795 G_TYPE_INITIALLY_UNOWNED,
796 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
797 clutter_container_iface_init)
798 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
799 clutter_scriptable_iface_init)
800 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
801 clutter_animatable_iface_init)
802 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
803 atk_implementor_iface_init));
806 * clutter_actor_get_debug_name:
807 * @actor: a #ClutterActor
809 * Retrieves a printable name of @actor for debugging messages
811 * Return value: a string with a printable name
814 _clutter_actor_get_debug_name (ClutterActor *actor)
816 return actor->priv->name != NULL ? actor->priv->name
817 : G_OBJECT_TYPE_NAME (actor);
820 #ifdef CLUTTER_ENABLE_DEBUG
821 /* XXX - this is for debugging only, remove once working (or leave
822 * in only in some debug mode). Should leave it for a little while
823 * until we're confident in the new map/realize/visible handling.
826 clutter_actor_verify_map_state (ClutterActor *self)
828 ClutterActorPrivate *priv = self->priv;
830 if (CLUTTER_ACTOR_IS_REALIZED (self))
832 /* all bets are off during reparent when we're potentially realized,
833 * but should not be according to invariants
835 if (!CLUTTER_ACTOR_IN_REPARENT (self))
837 if (priv->parent == NULL)
839 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
843 g_warning ("Realized non-toplevel actor '%s' should "
845 _clutter_actor_get_debug_name (self));
847 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
849 g_warning ("Realized actor %s has an unrealized parent %s",
850 _clutter_actor_get_debug_name (self),
851 _clutter_actor_get_debug_name (priv->parent));
856 if (CLUTTER_ACTOR_IS_MAPPED (self))
858 if (!CLUTTER_ACTOR_IS_REALIZED (self))
859 g_warning ("Actor '%s' is mapped but not realized",
860 _clutter_actor_get_debug_name (self));
862 /* remaining bets are off during reparent when we're potentially
863 * mapped, but should not be according to invariants
865 if (!CLUTTER_ACTOR_IN_REPARENT (self))
867 if (priv->parent == NULL)
869 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
871 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
872 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
874 g_warning ("Toplevel actor '%s' is mapped "
876 _clutter_actor_get_debug_name (self));
881 g_warning ("Mapped actor '%s' should have a parent",
882 _clutter_actor_get_debug_name (self));
887 ClutterActor *iter = self;
889 /* check for the enable_paint_unmapped flag on the actor
890 * and parents; if the flag is enabled at any point of this
891 * branch of the scene graph then all the later checks
896 if (iter->priv->enable_paint_unmapped)
899 iter = iter->priv->parent;
902 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
904 g_warning ("Actor '%s' should not be mapped if parent '%s'"
906 _clutter_actor_get_debug_name (self),
907 _clutter_actor_get_debug_name (priv->parent));
910 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
912 g_warning ("Actor '%s' should not be mapped if parent '%s'"
914 _clutter_actor_get_debug_name (self),
915 _clutter_actor_get_debug_name (priv->parent));
918 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
920 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
921 g_warning ("Actor '%s' is mapped but its non-toplevel "
922 "parent '%s' is not mapped",
923 _clutter_actor_get_debug_name (self),
924 _clutter_actor_get_debug_name (priv->parent));
931 #endif /* CLUTTER_ENABLE_DEBUG */
934 clutter_actor_set_mapped (ClutterActor *self,
937 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
942 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
943 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
947 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
948 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
952 /* this function updates the mapped and realized states according to
953 * invariants, in the appropriate order.
956 clutter_actor_update_map_state (ClutterActor *self,
957 MapStateChange change)
961 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
963 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
965 /* the mapped flag on top-level actors must be set by the
966 * per-backend implementation because it might be asynchronous.
968 * That is, the MAPPED flag on toplevels currently tracks the X
969 * server mapped-ness of the window, while the expected behavior
970 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
971 * This creates some weird complexity by breaking the invariant
972 * that if we're visible and all ancestors shown then we are
973 * also mapped - instead, we are mapped if all ancestors
974 * _possibly excepting_ the stage are mapped. The stage
975 * will map/unmap for example when it is minimized or
976 * moved to another workspace.
978 * So, the only invariant on the stage is that if visible it
979 * should be realized, and that it has to be visible to be
982 if (CLUTTER_ACTOR_IS_VISIBLE (self))
983 clutter_actor_realize (self);
987 case MAP_STATE_CHECK:
990 case MAP_STATE_MAKE_MAPPED:
991 g_assert (!was_mapped);
992 clutter_actor_set_mapped (self, TRUE);
995 case MAP_STATE_MAKE_UNMAPPED:
996 g_assert (was_mapped);
997 clutter_actor_set_mapped (self, FALSE);
1000 case MAP_STATE_MAKE_UNREALIZED:
1001 /* we only use MAKE_UNREALIZED in unparent,
1002 * and unparenting a stage isn't possible.
1003 * If someone wants to just unrealize a stage
1004 * then clutter_actor_unrealize() doesn't
1005 * go through this codepath.
1007 g_warning ("Trying to force unrealize stage is not allowed");
1011 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1012 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1013 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1015 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1016 "it is somehow still mapped",
1017 _clutter_actor_get_debug_name (self));
1022 ClutterActorPrivate *priv = self->priv;
1023 ClutterActor *parent = priv->parent;
1024 gboolean should_be_mapped;
1025 gboolean may_be_realized;
1026 gboolean must_be_realized;
1028 should_be_mapped = FALSE;
1029 may_be_realized = TRUE;
1030 must_be_realized = FALSE;
1032 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1034 may_be_realized = FALSE;
1038 /* Maintain invariant that if parent is mapped, and we are
1039 * visible, then we are mapped ... unless parent is a
1040 * stage, in which case we map regardless of parent's map
1041 * state but do require stage to be visible and realized.
1043 * If parent is realized, that does not force us to be
1044 * realized; but if parent is unrealized, that does force
1045 * us to be unrealized.
1047 * The reason we don't force children to realize with
1048 * parents is _clutter_actor_rerealize(); if we require that
1049 * a realized parent means children are realized, then to
1050 * unrealize an actor we would have to unrealize its
1051 * parents, which would end up meaning unrealizing and
1052 * hiding the entire stage. So we allow unrealizing a
1053 * child (as long as that child is not mapped) while that
1054 * child still has a realized parent.
1056 * Also, if we unrealize from leaf nodes to root, and
1057 * realize from root to leaf, the invariants are never
1058 * violated if we allow children to be unrealized
1059 * while parents are realized.
1061 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1062 * to force us to unmap, even though parent is still
1063 * mapped. This is because we're unmapping from leaf nodes
1066 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1067 change != MAP_STATE_MAKE_UNMAPPED)
1069 gboolean parent_is_visible_realized_toplevel;
1071 parent_is_visible_realized_toplevel =
1072 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1073 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1074 CLUTTER_ACTOR_IS_REALIZED (parent));
1076 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1077 parent_is_visible_realized_toplevel)
1079 must_be_realized = TRUE;
1080 should_be_mapped = TRUE;
1084 /* if the actor has been set to be painted even if unmapped
1085 * then we should map it and check for realization as well;
1086 * this is an override for the branch of the scene graph
1087 * which begins with this node
1089 if (priv->enable_paint_unmapped)
1091 if (priv->parent == NULL)
1092 g_warning ("Attempting to map an unparented actor '%s'",
1093 _clutter_actor_get_debug_name (self));
1095 should_be_mapped = TRUE;
1096 must_be_realized = TRUE;
1099 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1100 may_be_realized = FALSE;
1103 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1106 g_warning ("Attempting to map a child that does not "
1107 "meet the necessary invariants: the actor '%s' "
1109 _clutter_actor_get_debug_name (self));
1111 g_warning ("Attempting to map a child that does not "
1112 "meet the necessary invariants: the actor '%s' "
1113 "is parented to an unmapped actor '%s'",
1114 _clutter_actor_get_debug_name (self),
1115 _clutter_actor_get_debug_name (priv->parent));
1118 /* If in reparent, we temporarily suspend unmap and unrealize.
1120 * We want to go in the order "realize, map" and "unmap, unrealize"
1124 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1125 clutter_actor_set_mapped (self, FALSE);
1128 if (must_be_realized)
1129 clutter_actor_realize (self);
1131 /* if we must be realized then we may be, presumably */
1132 g_assert (!(must_be_realized && !may_be_realized));
1135 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1136 clutter_actor_unrealize_not_hiding (self);
1139 if (should_be_mapped)
1141 if (!must_be_realized)
1142 g_warning ("Somehow we think actor '%s' should be mapped but "
1143 "not realized, which isn't allowed",
1144 _clutter_actor_get_debug_name (self));
1146 /* realization is allowed to fail (though I don't know what
1147 * an app is supposed to do about that - shouldn't it just
1148 * be a g_error? anyway, we have to avoid mapping if this
1151 if (CLUTTER_ACTOR_IS_REALIZED (self))
1152 clutter_actor_set_mapped (self, TRUE);
1156 #ifdef CLUTTER_ENABLE_DEBUG
1157 /* check all invariants were kept */
1158 clutter_actor_verify_map_state (self);
1163 clutter_actor_real_map (ClutterActor *self)
1165 ClutterActorPrivate *priv = self->priv;
1166 ClutterActor *stage, *iter;
1168 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1170 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1171 _clutter_actor_get_debug_name (self));
1173 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1175 stage = _clutter_actor_get_stage_internal (self);
1176 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1178 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1180 _clutter_actor_get_debug_name (self));
1182 /* notify on parent mapped before potentially mapping
1183 * children, so apps see a top-down notification.
1185 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1187 for (iter = self->priv->first_child;
1189 iter = iter->priv->next_sibling)
1191 clutter_actor_map (iter);
1196 * clutter_actor_map:
1197 * @self: A #ClutterActor
1199 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1200 * and realizes its children if they are visible. Does nothing if the
1201 * actor is not visible.
1203 * Calling this function is strongly disencouraged: the default
1204 * implementation of #ClutterActorClass.map() will map all the children
1205 * of an actor when mapping its parent.
1207 * When overriding map, it is mandatory to chain up to the parent
1213 clutter_actor_map (ClutterActor *self)
1215 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1217 if (CLUTTER_ACTOR_IS_MAPPED (self))
1220 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1223 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1227 clutter_actor_real_unmap (ClutterActor *self)
1229 ClutterActorPrivate *priv = self->priv;
1232 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1234 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1235 _clutter_actor_get_debug_name (self));
1237 for (iter = self->priv->first_child;
1239 iter = iter->priv->next_sibling)
1241 clutter_actor_unmap (iter);
1244 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1246 /* clear the contents of the last paint volume, so that hiding + moving +
1247 * showing will not result in the wrong area being repainted
1249 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1250 priv->last_paint_volume_valid = TRUE;
1252 /* notify on parent mapped after potentially unmapping
1253 * children, so apps see a bottom-up notification.
1255 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1257 /* relinquish keyboard focus if we were unmapped while owning it */
1258 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1260 ClutterStage *stage;
1262 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1265 _clutter_stage_release_pick_id (stage, priv->pick_id);
1269 if (stage != NULL &&
1270 clutter_stage_get_key_focus (stage) == self)
1272 clutter_stage_set_key_focus (stage, NULL);
1278 * clutter_actor_unmap:
1279 * @self: A #ClutterActor
1281 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1282 * unmaps its children if they were mapped.
1284 * Calling this function is not encouraged: the default #ClutterActor
1285 * implementation of #ClutterActorClass.unmap() will also unmap any
1286 * eventual children by default when their parent is unmapped.
1288 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1289 * chain up to the parent implementation.
1291 * <note>It is important to note that the implementation of the
1292 * #ClutterActorClass.unmap() virtual function may be called after
1293 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1294 * implementation, but it is guaranteed to be called before the
1295 * #GObjectClass.finalize() implementation.</note>
1300 clutter_actor_unmap (ClutterActor *self)
1302 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1304 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1307 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1311 clutter_actor_real_show (ClutterActor *self)
1313 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1315 ClutterActorPrivate *priv = self->priv;
1317 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1319 /* we notify on the "visible" flag in the clutter_actor_show()
1320 * wrapper so the entire show signal emission completes first
1323 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1325 /* we queue a relayout unless the actor is inside a
1326 * container that explicitly told us not to
1328 if (priv->parent != NULL &&
1329 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1331 /* While an actor is hidden the parent may not have
1332 * allocated/requested so we need to start from scratch
1333 * and avoid the short-circuiting in
1334 * clutter_actor_queue_relayout().
1336 priv->needs_width_request = FALSE;
1337 priv->needs_height_request = FALSE;
1338 priv->needs_allocation = FALSE;
1339 clutter_actor_queue_relayout (self);
1345 set_show_on_set_parent (ClutterActor *self,
1348 ClutterActorPrivate *priv = self->priv;
1350 set_show = !!set_show;
1352 if (priv->show_on_set_parent == set_show)
1355 if (priv->parent == NULL)
1357 priv->show_on_set_parent = set_show;
1358 g_object_notify_by_pspec (G_OBJECT (self),
1359 obj_props[PROP_SHOW_ON_SET_PARENT]);
1364 * clutter_actor_show:
1365 * @self: A #ClutterActor
1367 * Flags an actor to be displayed. An actor that isn't shown will not
1368 * be rendered on the stage.
1370 * Actors are visible by default.
1372 * If this function is called on an actor without a parent, the
1373 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1377 clutter_actor_show (ClutterActor *self)
1379 ClutterActorPrivate *priv;
1381 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1383 /* simple optimization */
1384 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1386 /* we still need to set the :show-on-set-parent property, in
1387 * case show() is called on an unparented actor
1389 set_show_on_set_parent (self, TRUE);
1393 #ifdef CLUTTER_ENABLE_DEBUG
1394 clutter_actor_verify_map_state (self);
1399 g_object_freeze_notify (G_OBJECT (self));
1401 set_show_on_set_parent (self, TRUE);
1403 g_signal_emit (self, actor_signals[SHOW], 0);
1404 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1406 if (priv->parent != NULL)
1407 clutter_actor_queue_redraw (priv->parent);
1409 g_object_thaw_notify (G_OBJECT (self));
1413 * clutter_actor_show_all:
1414 * @self: a #ClutterActor
1416 * Calls clutter_actor_show() on all children of an actor (if any).
1420 * Deprecated: 1.10: Actors are visible by default
1423 clutter_actor_show_all (ClutterActor *self)
1425 ClutterActorClass *klass;
1427 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1429 klass = CLUTTER_ACTOR_GET_CLASS (self);
1430 if (klass->show_all)
1431 klass->show_all (self);
1435 clutter_actor_real_hide (ClutterActor *self)
1437 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1439 ClutterActorPrivate *priv = self->priv;
1441 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1443 /* we notify on the "visible" flag in the clutter_actor_hide()
1444 * wrapper so the entire hide signal emission completes first
1447 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1449 /* we queue a relayout unless the actor is inside a
1450 * container that explicitly told us not to
1452 if (priv->parent != NULL &&
1453 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1454 clutter_actor_queue_relayout (priv->parent);
1459 * clutter_actor_hide:
1460 * @self: A #ClutterActor
1462 * Flags an actor to be hidden. A hidden actor will not be
1463 * rendered on the stage.
1465 * Actors are visible by default.
1467 * If this function is called on an actor without a parent, the
1468 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1472 clutter_actor_hide (ClutterActor *self)
1474 ClutterActorPrivate *priv;
1476 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1478 /* simple optimization */
1479 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1481 /* we still need to set the :show-on-set-parent property, in
1482 * case hide() is called on an unparented actor
1484 set_show_on_set_parent (self, FALSE);
1488 #ifdef CLUTTER_ENABLE_DEBUG
1489 clutter_actor_verify_map_state (self);
1494 g_object_freeze_notify (G_OBJECT (self));
1496 set_show_on_set_parent (self, FALSE);
1498 g_signal_emit (self, actor_signals[HIDE], 0);
1499 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1501 if (priv->parent != NULL)
1502 clutter_actor_queue_redraw (priv->parent);
1504 g_object_thaw_notify (G_OBJECT (self));
1508 * clutter_actor_hide_all:
1509 * @self: a #ClutterActor
1511 * Calls clutter_actor_hide() on all child actors (if any).
1515 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1516 * prevent its children from being painted as well.
1519 clutter_actor_hide_all (ClutterActor *self)
1521 ClutterActorClass *klass;
1523 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1525 klass = CLUTTER_ACTOR_GET_CLASS (self);
1526 if (klass->hide_all)
1527 klass->hide_all (self);
1531 * clutter_actor_realize:
1532 * @self: A #ClutterActor
1534 * Realization informs the actor that it is attached to a stage. It
1535 * can use this to allocate resources if it wanted to delay allocation
1536 * until it would be rendered. However it is perfectly acceptable for
1537 * an actor to create resources before being realized because Clutter
1538 * only ever has a single rendering context so that actor is free to
1539 * be moved from one stage to another.
1541 * This function does nothing if the actor is already realized.
1543 * Because a realized actor must have realized parent actors, calling
1544 * clutter_actor_realize() will also realize all parents of the actor.
1546 * This function does not realize child actors, except in the special
1547 * case that realizing the stage, when the stage is visible, will
1548 * suddenly map (and thus realize) the children of the stage.
1551 clutter_actor_realize (ClutterActor *self)
1553 ClutterActorPrivate *priv;
1555 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1559 #ifdef CLUTTER_ENABLE_DEBUG
1560 clutter_actor_verify_map_state (self);
1563 if (CLUTTER_ACTOR_IS_REALIZED (self))
1566 /* To be realized, our parent actors must be realized first.
1567 * This will only succeed if we're inside a toplevel.
1569 if (priv->parent != NULL)
1570 clutter_actor_realize (priv->parent);
1572 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1574 /* toplevels can be realized at any time */
1578 /* "Fail" the realization if parent is missing or unrealized;
1579 * this should really be a g_warning() not some kind of runtime
1580 * failure; how can an app possibly recover? Instead it's a bug
1581 * in the app and the app should get an explanatory warning so
1582 * someone can fix it. But for now it's too hard to fix this
1583 * because e.g. ClutterTexture needs reworking.
1585 if (priv->parent == NULL ||
1586 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1590 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1592 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1593 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1595 g_signal_emit (self, actor_signals[REALIZE], 0);
1597 /* Stage actor is allowed to unset the realized flag again in its
1598 * default signal handler, though that is a pathological situation.
1601 /* If realization "failed" we'll have to update child state. */
1602 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1606 clutter_actor_real_unrealize (ClutterActor *self)
1608 /* we must be unmapped (implying our children are also unmapped) */
1609 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1613 * clutter_actor_unrealize:
1614 * @self: A #ClutterActor
1616 * Unrealization informs the actor that it may be being destroyed or
1617 * moved to another stage. The actor may want to destroy any
1618 * underlying graphics resources at this point. However it is
1619 * perfectly acceptable for it to retain the resources until the actor
1620 * is destroyed because Clutter only ever uses a single rendering
1621 * context and all of the graphics resources are valid on any stage.
1623 * Because mapped actors must be realized, actors may not be
1624 * unrealized if they are mapped. This function hides the actor to be
1625 * sure it isn't mapped, an application-visible side effect that you
1626 * may not be expecting.
1628 * This function should not be called by application code.
1631 clutter_actor_unrealize (ClutterActor *self)
1633 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1634 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1636 /* This function should not really be in the public API, because
1637 * there isn't a good reason to call it. ClutterActor will already
1638 * unrealize things for you when it's important to do so.
1640 * If you were using clutter_actor_unrealize() in a dispose
1641 * implementation, then don't, just chain up to ClutterActor's
1644 * If you were using clutter_actor_unrealize() to implement
1645 * unrealizing children of your container, then don't, ClutterActor
1646 * will already take care of that.
1648 * If you were using clutter_actor_unrealize() to re-realize to
1649 * create your resources in a different way, then use
1650 * _clutter_actor_rerealize() (inside Clutter) or just call your
1651 * code that recreates your resources directly (outside Clutter).
1654 #ifdef CLUTTER_ENABLE_DEBUG
1655 clutter_actor_verify_map_state (self);
1658 clutter_actor_hide (self);
1660 clutter_actor_unrealize_not_hiding (self);
1663 static ClutterActorTraverseVisitFlags
1664 unrealize_actor_before_children_cb (ClutterActor *self,
1668 /* If an actor is already unrealized we know its children have also
1669 * already been unrealized... */
1670 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1671 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1673 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1675 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1678 static ClutterActorTraverseVisitFlags
1679 unrealize_actor_after_children_cb (ClutterActor *self,
1683 /* We want to unset the realized flag only _after_
1684 * child actors are unrealized, to maintain invariants.
1686 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1687 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1688 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1692 * clutter_actor_unrealize_not_hiding:
1693 * @self: A #ClutterActor
1695 * Unrealization informs the actor that it may be being destroyed or
1696 * moved to another stage. The actor may want to destroy any
1697 * underlying graphics resources at this point. However it is
1698 * perfectly acceptable for it to retain the resources until the actor
1699 * is destroyed because Clutter only ever uses a single rendering
1700 * context and all of the graphics resources are valid on any stage.
1702 * Because mapped actors must be realized, actors may not be
1703 * unrealized if they are mapped. You must hide the actor or one of
1704 * its parents before attempting to unrealize.
1706 * This function is separate from clutter_actor_unrealize() because it
1707 * does not automatically hide the actor.
1708 * Actors need not be hidden to be unrealized, they just need to
1709 * be unmapped. In fact we don't want to mess up the application's
1710 * setting of the "visible" flag, so hiding is very undesirable.
1712 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1713 * backward compatibility.
1716 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1718 _clutter_actor_traverse (self,
1719 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1720 unrealize_actor_before_children_cb,
1721 unrealize_actor_after_children_cb,
1726 * _clutter_actor_rerealize:
1727 * @self: A #ClutterActor
1728 * @callback: Function to call while unrealized
1729 * @data: data for callback
1731 * If an actor is already unrealized, this just calls the callback.
1733 * If it is realized, it unrealizes temporarily, calls the callback,
1734 * and then re-realizes the actor.
1736 * As a side effect, leaves all children of the actor unrealized if
1737 * the actor was realized but not showing. This is because when we
1738 * unrealize the actor temporarily we must unrealize its children
1739 * (e.g. children of a stage can't be realized if stage window is
1740 * gone). And we aren't clever enough to save the realization state of
1741 * all children. In most cases this should not matter, because
1742 * the children will automatically realize when they next become mapped.
1745 _clutter_actor_rerealize (ClutterActor *self,
1746 ClutterCallback callback,
1749 gboolean was_mapped;
1750 gboolean was_showing;
1751 gboolean was_realized;
1753 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1755 #ifdef CLUTTER_ENABLE_DEBUG
1756 clutter_actor_verify_map_state (self);
1759 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1760 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1761 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1763 /* Must be unmapped to unrealize. Note we only have to hide this
1764 * actor if it was mapped (if all parents were showing). If actor
1765 * is merely visible (but not mapped), then that's fine, we can
1769 clutter_actor_hide (self);
1771 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1773 /* unrealize self and all children */
1774 clutter_actor_unrealize_not_hiding (self);
1776 if (callback != NULL)
1778 (* callback) (self, data);
1782 clutter_actor_show (self); /* will realize only if mapping implies it */
1783 else if (was_realized)
1784 clutter_actor_realize (self); /* realize self and all parents */
1788 clutter_actor_real_pick (ClutterActor *self,
1789 const ClutterColor *color)
1791 /* the default implementation is just to paint a rectangle
1792 * with the same size of the actor using the passed color
1794 if (clutter_actor_should_pick_paint (self))
1796 ClutterActorBox box = { 0, };
1797 float width, height;
1799 clutter_actor_get_allocation_box (self, &box);
1801 width = box.x2 - box.x1;
1802 height = box.y2 - box.y1;
1804 cogl_set_source_color4ub (color->red,
1809 cogl_rectangle (0, 0, width, height);
1812 /* XXX - this thoroughly sucks, but we need to maintain compatibility
1813 * with existing container classes that override the pick() virtual
1814 * and chain up to the default implementation - otherwise we'll end up
1815 * painting our children twice.
1817 * this has to go away for 2.0; hopefully along the pick() itself.
1819 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1823 for (iter = self->priv->first_child;
1825 iter = iter->priv->next_sibling)
1826 clutter_actor_paint (iter);
1831 * clutter_actor_should_pick_paint:
1832 * @self: A #ClutterActor
1834 * Should be called inside the implementation of the
1835 * #ClutterActor::pick virtual function in order to check whether
1836 * the actor should paint itself in pick mode or not.
1838 * This function should never be called directly by applications.
1840 * Return value: %TRUE if the actor should paint its silhouette,
1844 clutter_actor_should_pick_paint (ClutterActor *self)
1846 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1848 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1849 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1850 CLUTTER_ACTOR_IS_REACTIVE (self)))
1857 clutter_actor_real_get_preferred_width (ClutterActor *self,
1859 gfloat *min_width_p,
1860 gfloat *natural_width_p)
1862 ClutterActorPrivate *priv = self->priv;
1864 if (priv->n_children != 0 &&
1865 priv->layout_manager != NULL)
1867 ClutterContainer *container = CLUTTER_CONTAINER (self);
1869 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1870 "for the preferred width",
1871 G_OBJECT_TYPE_NAME (priv->layout_manager),
1872 priv->layout_manager);
1874 clutter_layout_manager_get_preferred_width (priv->layout_manager,
1883 /* Default implementation is always 0x0, usually an actor
1884 * using this default is relying on someone to set the
1887 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1892 if (natural_width_p)
1893 *natural_width_p = 0;
1897 clutter_actor_real_get_preferred_height (ClutterActor *self,
1899 gfloat *min_height_p,
1900 gfloat *natural_height_p)
1902 ClutterActorPrivate *priv = self->priv;
1904 if (priv->n_children != 0 &&
1905 priv->layout_manager != NULL)
1907 ClutterContainer *container = CLUTTER_CONTAINER (self);
1909 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1910 "for the preferred height",
1911 G_OBJECT_TYPE_NAME (priv->layout_manager),
1912 priv->layout_manager);
1914 clutter_layout_manager_get_preferred_height (priv->layout_manager,
1922 /* Default implementation is always 0x0, usually an actor
1923 * using this default is relying on someone to set the
1926 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1931 if (natural_height_p)
1932 *natural_height_p = 0;
1936 clutter_actor_store_old_geometry (ClutterActor *self,
1937 ClutterActorBox *box)
1939 *box = self->priv->allocation;
1943 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
1944 const ClutterActorBox *old)
1946 ClutterActorPrivate *priv = self->priv;
1947 GObject *obj = G_OBJECT (self);
1949 g_object_freeze_notify (obj);
1951 /* to avoid excessive requisition or allocation cycles we
1952 * use the cached values.
1954 * - if we don't have an allocation we assume that we need
1956 * - if we don't have a width or a height request we notify
1958 * - if we have a valid allocation then we check the old
1959 * bounding box with the current allocation and we notify
1962 if (priv->needs_allocation)
1964 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1965 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1966 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1967 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1969 else if (priv->needs_width_request || priv->needs_height_request)
1971 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1972 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1977 gfloat widthu, heightu;
1979 xu = priv->allocation.x1;
1980 yu = priv->allocation.y1;
1981 widthu = priv->allocation.x2 - priv->allocation.x1;
1982 heightu = priv->allocation.y2 - priv->allocation.y1;
1985 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1988 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1990 if (widthu != (old->x2 - old->x1))
1991 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1993 if (heightu != (old->y2 - old->y1))
1994 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1997 g_object_thaw_notify (obj);
2001 * clutter_actor_set_allocation_internal:
2002 * @self: a #ClutterActor
2003 * @box: a #ClutterActorBox
2004 * @flags: allocation flags
2006 * Stores the allocation of @self.
2008 * This function only performs basic storage and property notification.
2010 * This function should be called by clutter_actor_set_allocation()
2011 * and by the default implementation of #ClutterActorClass.allocate().
2013 * Return value: %TRUE if the allocation of the #ClutterActor has been
2014 * changed, and %FALSE otherwise
2016 static inline gboolean
2017 clutter_actor_set_allocation_internal (ClutterActor *self,
2018 const ClutterActorBox *box,
2019 ClutterAllocationFlags flags)
2021 ClutterActorPrivate *priv = self->priv;
2023 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2024 gboolean flags_changed;
2026 ClutterActorBox old_alloc = { 0, };
2028 obj = G_OBJECT (self);
2030 g_object_freeze_notify (obj);
2032 clutter_actor_store_old_geometry (self, &old_alloc);
2034 x1_changed = priv->allocation.x1 != box->x1;
2035 y1_changed = priv->allocation.y1 != box->y1;
2036 x2_changed = priv->allocation.x2 != box->x2;
2037 y2_changed = priv->allocation.y2 != box->y2;
2039 flags_changed = priv->allocation_flags != flags;
2041 priv->allocation = *box;
2042 priv->allocation_flags = flags;
2044 /* allocation is authoritative */
2045 priv->needs_width_request = FALSE;
2046 priv->needs_height_request = FALSE;
2047 priv->needs_allocation = FALSE;
2049 if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
2051 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2052 _clutter_actor_get_debug_name (self));
2054 priv->transform_valid = FALSE;
2056 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2058 /* if the allocation changes, so does the content box */
2059 if (priv->content != NULL)
2060 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2067 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2069 g_object_thaw_notify (obj);
2074 static void clutter_actor_real_allocate (ClutterActor *self,
2075 const ClutterActorBox *box,
2076 ClutterAllocationFlags flags);
2079 clutter_actor_maybe_layout_children (ClutterActor *self,
2080 const ClutterActorBox *allocation,
2081 ClutterAllocationFlags flags)
2083 ClutterActorPrivate *priv = self->priv;
2085 /* this is going to be a bit hard to follow, so let's put an explanation
2088 * we want ClutterActor to have a default layout manager if the actor was
2089 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2091 * we also want any subclass of ClutterActor that does not override the
2092 * ::allocate() virtual function to delegate to a layout manager.
2094 * finally, we want to allow people subclassing ClutterActor and overriding
2095 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2097 * on the other hand, we want existing actor subclasses overriding the
2098 * ::allocate() virtual function and chaining up to the parent's
2099 * implementation to continue working without allocating their children
2100 * twice, or without entering an allocation loop.
2102 * for the first two points, we check if the class of the actor is
2103 * overridding the ::allocate() virtual function; if it isn't, then we
2104 * follow through with checking whether we have children and a layout
2105 * manager, and eventually calling clutter_layout_manager_allocate().
2107 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2108 * allocation flags that we got passed, and if it is present, we continue
2109 * with the check above.
2111 * if neither of these two checks yields a positive result, we just
2112 * assume that the ::allocate() virtual function that resulted in this
2113 * function being called will also allocate the children of the actor.
2116 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2119 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2125 if (priv->n_children != 0 &&
2126 priv->layout_manager != NULL)
2128 ClutterContainer *container = CLUTTER_CONTAINER (self);
2129 ClutterAllocationFlags children_flags;
2130 ClutterActorBox children_box;
2132 /* normalize the box passed to the layout manager */
2133 children_box.x1 = children_box.y1 = 0.f;
2134 children_box.x2 = (allocation->x2 - allocation->x1);
2135 children_box.y2 = (allocation->y2 - allocation->y1);
2137 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2138 * the actor's children, since it refers only to the current
2139 * actor's allocation.
2141 children_flags = flags;
2142 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2144 CLUTTER_NOTE (LAYOUT,
2145 "Allocating %d children of %s "
2146 "at { %.2f, %.2f - %.2f x %.2f } "
2149 _clutter_actor_get_debug_name (self),
2152 (allocation->x2 - allocation->x1),
2153 (allocation->y2 - allocation->y1),
2154 G_OBJECT_TYPE_NAME (priv->layout_manager));
2156 clutter_layout_manager_allocate (priv->layout_manager,
2164 clutter_actor_real_allocate (ClutterActor *self,
2165 const ClutterActorBox *box,
2166 ClutterAllocationFlags flags)
2168 ClutterActorPrivate *priv = self->priv;
2171 g_object_freeze_notify (G_OBJECT (self));
2173 changed = clutter_actor_set_allocation_internal (self, box, flags);
2175 /* we allocate our children before we notify changes in our geometry,
2176 * so that people connecting to properties will be able to get valid
2177 * data out of the sub-tree of the scene graph that has this actor at
2180 clutter_actor_maybe_layout_children (self, box, flags);
2184 ClutterActorBox signal_box = priv->allocation;
2185 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2187 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2192 g_object_thaw_notify (G_OBJECT (self));
2196 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2197 ClutterActor *origin)
2199 /* no point in queuing a redraw on a destroyed actor */
2200 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2203 /* NB: We can't bail out early here if the actor is hidden in case
2204 * the actor bas been cloned. In this case the clone will need to
2205 * receive the signal so it can queue its own redraw.
2208 /* calls klass->queue_redraw in default handler */
2209 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2213 clutter_actor_real_queue_redraw (ClutterActor *self,
2214 ClutterActor *origin)
2216 ClutterActor *parent;
2218 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2219 _clutter_actor_get_debug_name (self),
2220 origin != NULL ? _clutter_actor_get_debug_name (origin)
2223 /* no point in queuing a redraw on a destroyed actor */
2224 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2227 /* If the queue redraw is coming from a child then the actor has
2228 become dirty and any queued effect is no longer valid */
2231 self->priv->is_dirty = TRUE;
2232 self->priv->effect_to_redraw = NULL;
2235 /* If the actor isn't visible, we still had to emit the signal
2236 * to allow for a ClutterClone, but the appearance of the parent
2237 * won't change so we don't have to propagate up the hierarchy.
2239 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2242 /* Although we could determine here that a full stage redraw
2243 * has already been queued and immediately bail out, we actually
2244 * guarantee that we will propagate a queue-redraw signal to our
2245 * parent at least once so that it's possible to implement a
2246 * container that tracks which of its children have queued a
2249 if (self->priv->propagated_one_redraw)
2251 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2252 if (stage != NULL &&
2253 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2257 self->priv->propagated_one_redraw = TRUE;
2259 /* notify parents, if they are all visible eventually we'll
2260 * queue redraw on the stage, which queues the redraw idle.
2262 parent = clutter_actor_get_parent (self);
2265 /* this will go up recursively */
2266 _clutter_actor_signal_queue_redraw (parent, origin);
2271 clutter_actor_real_queue_relayout (ClutterActor *self)
2273 ClutterActorPrivate *priv = self->priv;
2275 /* no point in queueing a redraw on a destroyed actor */
2276 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2279 priv->needs_width_request = TRUE;
2280 priv->needs_height_request = TRUE;
2281 priv->needs_allocation = TRUE;
2283 /* reset the cached size requests */
2284 memset (priv->width_requests, 0,
2285 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2286 memset (priv->height_requests, 0,
2287 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2289 /* We need to go all the way up the hierarchy */
2290 if (priv->parent != NULL)
2291 _clutter_actor_queue_only_relayout (priv->parent);
2295 * clutter_actor_apply_relative_transform_to_point:
2296 * @self: A #ClutterActor
2297 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2298 * default #ClutterStage
2299 * @point: A point as #ClutterVertex
2300 * @vertex: (out caller-allocates): The translated #ClutterVertex
2302 * Transforms @point in coordinates relative to the actor into
2303 * ancestor-relative coordinates using the relevant transform
2304 * stack (i.e. scale, rotation, etc).
2306 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2307 * this case, the coordinates returned will be the coordinates on
2308 * the stage before the projection is applied. This is different from
2309 * the behaviour of clutter_actor_apply_transform_to_point().
2314 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2315 ClutterActor *ancestor,
2316 const ClutterVertex *point,
2317 ClutterVertex *vertex)
2322 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2323 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2324 g_return_if_fail (point != NULL);
2325 g_return_if_fail (vertex != NULL);
2330 if (ancestor == NULL)
2331 ancestor = _clutter_actor_get_stage_internal (self);
2333 if (ancestor == NULL)
2339 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2340 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2344 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2345 const ClutterVertex *vertices_in,
2346 ClutterVertex *vertices_out,
2349 ClutterActor *stage;
2350 CoglMatrix modelview;
2351 CoglMatrix projection;
2354 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2356 stage = _clutter_actor_get_stage_internal (self);
2358 /* We really can't do anything meaningful in this case so don't try
2359 * to do any transform */
2363 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2364 * that gets us to stage coordinates, we want to go all the way to eye
2366 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2368 /* Fetch the projection and viewport */
2369 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2370 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2376 _clutter_util_fully_transform_vertices (&modelview,
2387 * clutter_actor_apply_transform_to_point:
2388 * @self: A #ClutterActor
2389 * @point: A point as #ClutterVertex
2390 * @vertex: (out caller-allocates): The translated #ClutterVertex
2392 * Transforms @point in coordinates relative to the actor
2393 * into screen-relative coordinates with the current actor
2394 * transformation (i.e. scale, rotation, etc)
2399 clutter_actor_apply_transform_to_point (ClutterActor *self,
2400 const ClutterVertex *point,
2401 ClutterVertex *vertex)
2403 g_return_if_fail (point != NULL);
2404 g_return_if_fail (vertex != NULL);
2405 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2409 * _clutter_actor_get_relative_transformation_matrix:
2410 * @self: The actor whose coordinate space you want to transform from.
2411 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2412 * or %NULL if you want to transform all the way to eye coordinates.
2413 * @matrix: A #CoglMatrix to store the transformation
2415 * This gets a transformation @matrix that will transform coordinates from the
2416 * coordinate space of @self into the coordinate space of @ancestor.
2418 * For example if you need a matrix that can transform the local actor
2419 * coordinates of @self into stage coordinates you would pass the actor's stage
2420 * pointer as the @ancestor.
2422 * If you pass %NULL then the transformation will take you all the way through
2423 * to eye coordinates. This can be useful if you want to extract the entire
2424 * modelview transform that Clutter applies before applying the projection
2425 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2426 * using cogl_set_modelview_matrix() for example then you would want a matrix
2427 * that transforms into eye coordinates.
2429 * <note><para>This function explicitly initializes the given @matrix. If you just
2430 * want clutter to multiply a relative transformation with an existing matrix
2431 * you can use clutter_actor_apply_relative_transformation_matrix()
2432 * instead.</para></note>
2435 /* XXX: We should consider caching the stage relative modelview along with
2436 * the actor itself */
2438 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2439 ClutterActor *ancestor,
2442 cogl_matrix_init_identity (matrix);
2444 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2447 /* Project the given @box into stage window coordinates, writing the
2448 * transformed vertices to @verts[]. */
2450 _clutter_actor_transform_and_project_box (ClutterActor *self,
2451 const ClutterActorBox *box,
2452 ClutterVertex verts[])
2454 ClutterVertex box_vertices[4];
2456 box_vertices[0].x = box->x1;
2457 box_vertices[0].y = box->y1;
2458 box_vertices[0].z = 0;
2459 box_vertices[1].x = box->x2;
2460 box_vertices[1].y = box->y1;
2461 box_vertices[1].z = 0;
2462 box_vertices[2].x = box->x1;
2463 box_vertices[2].y = box->y2;
2464 box_vertices[2].z = 0;
2465 box_vertices[3].x = box->x2;
2466 box_vertices[3].y = box->y2;
2467 box_vertices[3].z = 0;
2470 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2474 * clutter_actor_get_allocation_vertices:
2475 * @self: A #ClutterActor
2476 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2477 * against, or %NULL to use the #ClutterStage
2478 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2479 * location for an array of 4 #ClutterVertex in which to store the result
2481 * Calculates the transformed coordinates of the four corners of the
2482 * actor in the plane of @ancestor. The returned vertices relate to
2483 * the #ClutterActorBox coordinates as follows:
2485 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2486 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2487 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2488 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2491 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2492 * this case, the coordinates returned will be the coordinates on
2493 * the stage before the projection is applied. This is different from
2494 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2499 clutter_actor_get_allocation_vertices (ClutterActor *self,
2500 ClutterActor *ancestor,
2501 ClutterVertex verts[])
2503 ClutterActorPrivate *priv;
2504 ClutterActorBox box;
2505 ClutterVertex vertices[4];
2506 CoglMatrix modelview;
2508 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2509 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2511 if (ancestor == NULL)
2512 ancestor = _clutter_actor_get_stage_internal (self);
2514 /* Fallback to a NOP transform if the actor isn't parented under a
2516 if (ancestor == NULL)
2521 /* if the actor needs to be allocated we force a relayout, so that
2522 * we will have valid values to use in the transformations */
2523 if (priv->needs_allocation)
2525 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2527 _clutter_stage_maybe_relayout (stage);
2530 box.x1 = box.y1 = 0;
2531 /* The result isn't really meaningful in this case but at
2532 * least try to do something *vaguely* reasonable... */
2533 clutter_actor_get_size (self, &box.x2, &box.y2);
2537 clutter_actor_get_allocation_box (self, &box);
2539 vertices[0].x = box.x1;
2540 vertices[0].y = box.y1;
2542 vertices[1].x = box.x2;
2543 vertices[1].y = box.y1;
2545 vertices[2].x = box.x1;
2546 vertices[2].y = box.y2;
2548 vertices[3].x = box.x2;
2549 vertices[3].y = box.y2;
2552 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2555 cogl_matrix_transform_points (&modelview,
2557 sizeof (ClutterVertex),
2559 sizeof (ClutterVertex),
2565 * clutter_actor_get_abs_allocation_vertices:
2566 * @self: A #ClutterActor
2567 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2568 * of 4 #ClutterVertex where to store the result.
2570 * Calculates the transformed screen coordinates of the four corners of
2571 * the actor; the returned vertices relate to the #ClutterActorBox
2572 * coordinates as follows:
2574 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2575 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2576 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2577 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2583 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2584 ClutterVertex verts[])
2586 ClutterActorPrivate *priv;
2587 ClutterActorBox actor_space_allocation;
2589 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2593 /* if the actor needs to be allocated we force a relayout, so that
2594 * the actor allocation box will be valid for
2595 * _clutter_actor_transform_and_project_box()
2597 if (priv->needs_allocation)
2599 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2600 /* There's nothing meaningful we can do now */
2604 _clutter_stage_maybe_relayout (stage);
2607 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2608 * own coordinate space... */
2609 actor_space_allocation.x1 = 0;
2610 actor_space_allocation.y1 = 0;
2611 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2612 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2613 _clutter_actor_transform_and_project_box (self,
2614 &actor_space_allocation,
2619 clutter_actor_real_apply_transform (ClutterActor *self,
2622 ClutterActorPrivate *priv = self->priv;
2624 if (!priv->transform_valid)
2626 CoglMatrix *transform = &priv->transform;
2627 const ClutterTransformInfo *info;
2629 info = _clutter_actor_get_transform_info_or_defaults (self);
2631 cogl_matrix_init_identity (transform);
2633 cogl_matrix_translate (transform,
2634 priv->allocation.x1,
2635 priv->allocation.y1,
2639 cogl_matrix_translate (transform, 0, 0, info->depth);
2642 * because the rotation involves translations, we must scale
2643 * before applying the rotations (if we apply the scale after
2644 * the rotations, the translations included in the rotation are
2645 * not scaled and so the entire object will move on the screen
2646 * as a result of rotating it).
2648 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2650 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2651 &info->scale_center,
2652 cogl_matrix_scale (transform,
2659 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2661 cogl_matrix_rotate (transform,
2666 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2668 cogl_matrix_rotate (transform,
2673 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2675 cogl_matrix_rotate (transform,
2679 if (!clutter_anchor_coord_is_zero (&info->anchor))
2683 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2684 cogl_matrix_translate (transform, -x, -y, -z);
2687 priv->transform_valid = TRUE;
2690 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2693 /* Applies the transforms associated with this actor to the given
2696 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2699 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2703 * clutter_actor_apply_relative_transformation_matrix:
2704 * @self: The actor whose coordinate space you want to transform from.
2705 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2706 * or %NULL if you want to transform all the way to eye coordinates.
2707 * @matrix: A #CoglMatrix to apply the transformation too.
2709 * This multiplies a transform with @matrix that will transform coordinates
2710 * from the coordinate space of @self into the coordinate space of @ancestor.
2712 * For example if you need a matrix that can transform the local actor
2713 * coordinates of @self into stage coordinates you would pass the actor's stage
2714 * pointer as the @ancestor.
2716 * If you pass %NULL then the transformation will take you all the way through
2717 * to eye coordinates. This can be useful if you want to extract the entire
2718 * modelview transform that Clutter applies before applying the projection
2719 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2720 * using cogl_set_modelview_matrix() for example then you would want a matrix
2721 * that transforms into eye coordinates.
2723 * <note>This function doesn't initialize the given @matrix, it simply
2724 * multiplies the requested transformation matrix with the existing contents of
2725 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2726 * before calling this function, or you can use
2727 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2730 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2731 ClutterActor *ancestor,
2734 ClutterActor *parent;
2736 /* Note we terminate before ever calling stage->apply_transform()
2737 * since that would conceptually be relative to the underlying
2738 * window OpenGL coordinates so we'd need a special @ancestor
2739 * value to represent the fake parent of the stage. */
2740 if (self == ancestor)
2743 parent = clutter_actor_get_parent (self);
2746 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2749 _clutter_actor_apply_modelview_transform (self, matrix);
2753 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2754 ClutterPaintVolume *pv,
2756 const CoglColor *color)
2758 static CoglPipeline *outline = NULL;
2759 CoglPrimitive *prim;
2760 ClutterVertex line_ends[12 * 2];
2763 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2764 /* XXX: at some point we'll query this from the stage but we can't
2765 * do that until the osx backend uses Cogl natively. */
2766 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2768 if (outline == NULL)
2769 outline = cogl_pipeline_new (ctx);
2771 _clutter_paint_volume_complete (pv);
2773 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2776 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2777 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2778 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2779 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2784 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2785 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2786 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2787 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2789 /* Lines connecting front face to back face */
2790 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2791 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2792 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2793 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2796 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2798 (CoglVertexP3 *)line_ends);
2800 cogl_pipeline_set_color (outline, color);
2801 cogl_framebuffer_draw_primitive (fb, outline, prim);
2802 cogl_object_unref (prim);
2806 PangoLayout *layout;
2807 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2808 pango_layout_set_text (layout, label, -1);
2809 cogl_pango_render_layout (layout,
2814 g_object_unref (layout);
2819 _clutter_actor_draw_paint_volume (ClutterActor *self)
2821 ClutterPaintVolume *pv;
2824 pv = _clutter_actor_get_paint_volume_mutable (self);
2827 gfloat width, height;
2828 ClutterPaintVolume fake_pv;
2830 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2831 _clutter_paint_volume_init_static (&fake_pv, stage);
2833 clutter_actor_get_size (self, &width, &height);
2834 clutter_paint_volume_set_width (&fake_pv, width);
2835 clutter_paint_volume_set_height (&fake_pv, height);
2837 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2838 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2839 _clutter_actor_get_debug_name (self),
2842 clutter_paint_volume_free (&fake_pv);
2846 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2847 _clutter_actor_draw_paint_volume_full (self, pv,
2848 _clutter_actor_get_debug_name (self),
2854 _clutter_actor_paint_cull_result (ClutterActor *self,
2856 ClutterCullResult result)
2858 ClutterPaintVolume *pv;
2863 if (result == CLUTTER_CULL_RESULT_IN)
2864 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2865 else if (result == CLUTTER_CULL_RESULT_OUT)
2866 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2868 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2871 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2873 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2874 _clutter_actor_draw_paint_volume_full (self, pv,
2875 _clutter_actor_get_debug_name (self),
2879 PangoLayout *layout;
2881 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2882 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2883 cogl_set_source_color (&color);
2885 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2886 pango_layout_set_text (layout, label, -1);
2887 cogl_pango_render_layout (layout,
2893 g_object_unref (layout);
2897 static int clone_paint_level = 0;
2900 _clutter_actor_push_clone_paint (void)
2902 clone_paint_level++;
2906 _clutter_actor_pop_clone_paint (void)
2908 clone_paint_level--;
2912 in_clone_paint (void)
2914 return clone_paint_level > 0;
2917 /* Returns TRUE if the actor can be ignored */
2918 /* FIXME: we should return a ClutterCullResult, and
2919 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2920 * means there's no point in trying to cull descendants of the current
2923 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2925 ClutterActorPrivate *priv = self->priv;
2926 ClutterActor *stage;
2927 const ClutterPlane *stage_clip;
2929 if (!priv->last_paint_volume_valid)
2931 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2932 "->last_paint_volume_valid == FALSE",
2933 _clutter_actor_get_debug_name (self));
2937 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2940 stage = _clutter_actor_get_stage_internal (self);
2941 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2942 if (G_UNLIKELY (!stage_clip))
2944 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2945 "No stage clip set",
2946 _clutter_actor_get_debug_name (self));
2950 if (cogl_get_draw_framebuffer () !=
2951 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2953 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2954 "Current framebuffer doesn't correspond to stage",
2955 _clutter_actor_get_debug_name (self));
2960 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2965 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2967 ClutterActorPrivate *priv = self->priv;
2968 const ClutterPaintVolume *pv;
2970 if (priv->last_paint_volume_valid)
2972 clutter_paint_volume_free (&priv->last_paint_volume);
2973 priv->last_paint_volume_valid = FALSE;
2976 pv = clutter_actor_get_paint_volume (self);
2979 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2980 "Actor failed to report a paint volume",
2981 _clutter_actor_get_debug_name (self));
2985 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2987 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2988 NULL); /* eye coordinates */
2990 priv->last_paint_volume_valid = TRUE;
2993 static inline gboolean
2994 actor_has_shader_data (ClutterActor *self)
2996 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3000 _clutter_actor_get_pick_id (ClutterActor *self)
3002 if (self->priv->pick_id < 0)
3005 return self->priv->pick_id;
3008 /* This is the same as clutter_actor_add_effect except that it doesn't
3009 queue a redraw and it doesn't notify on the effect property */
3011 _clutter_actor_add_effect_internal (ClutterActor *self,
3012 ClutterEffect *effect)
3014 ClutterActorPrivate *priv = self->priv;
3016 if (priv->effects == NULL)
3018 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3019 priv->effects->actor = self;
3022 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3025 /* This is the same as clutter_actor_remove_effect except that it doesn't
3026 queue a redraw and it doesn't notify on the effect property */
3028 _clutter_actor_remove_effect_internal (ClutterActor *self,
3029 ClutterEffect *effect)
3031 ClutterActorPrivate *priv = self->priv;
3033 if (priv->effects == NULL)
3036 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3040 needs_flatten_effect (ClutterActor *self)
3042 ClutterActorPrivate *priv = self->priv;
3044 if (G_UNLIKELY (clutter_paint_debug_flags &
3045 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3048 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3050 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3052 if (clutter_actor_get_paint_opacity (self) < 255 &&
3053 clutter_actor_has_overlaps (self))
3061 add_or_remove_flatten_effect (ClutterActor *self)
3063 ClutterActorPrivate *priv = self->priv;
3065 /* Add or remove the flatten effect depending on the
3066 offscreen-redirect property. */
3067 if (needs_flatten_effect (self))
3069 if (priv->flatten_effect == NULL)
3071 ClutterActorMeta *actor_meta;
3074 priv->flatten_effect = _clutter_flatten_effect_new ();
3075 /* Keep a reference to the effect so that we can queue
3077 g_object_ref_sink (priv->flatten_effect);
3079 /* Set the priority of the effect to high so that it will
3080 always be applied to the actor first. It uses an internal
3081 priority so that it won't be visible to applications */
3082 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3083 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3084 _clutter_actor_meta_set_priority (actor_meta, priority);
3086 /* This will add the effect without queueing a redraw */
3087 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3092 if (priv->flatten_effect != NULL)
3094 /* Destroy the effect so that it will lose its fbo cache of
3096 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3097 g_object_unref (priv->flatten_effect);
3098 priv->flatten_effect = NULL;
3104 clutter_actor_paint_node (ClutterActor *actor,
3105 ClutterPaintNode *root)
3107 ClutterActorPrivate *priv = actor->priv;
3109 if (priv->bg_color_set)
3111 ClutterPaintNode *node;
3112 ClutterColor bg_color;
3114 bg_color = priv->bg_color;
3115 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3116 * priv->bg_color.alpha
3119 node = clutter_color_node_new (&bg_color);
3120 clutter_paint_node_set_name (node, "backgroundColor");
3121 clutter_paint_node_add_rectangle (node, &priv->allocation);
3122 clutter_paint_node_add_child (root, node);
3123 clutter_paint_node_unref (node);
3126 if (priv->content != NULL)
3127 _clutter_content_paint_content (priv->content, actor, root);
3129 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3130 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3132 if (clutter_paint_node_get_n_children (root) == 0)
3135 _clutter_paint_node_paint (root);
3139 clutter_actor_real_paint (ClutterActor *actor)
3141 ClutterActorPrivate *priv = actor->priv;
3144 for (iter = priv->first_child;
3146 iter = iter->priv->next_sibling)
3148 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3149 _clutter_actor_get_debug_name (iter),
3150 _clutter_actor_get_debug_name (actor),
3151 iter->priv->allocation.x1,
3152 iter->priv->allocation.y1,
3153 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3154 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3156 clutter_actor_paint (iter);
3161 * clutter_actor_paint:
3162 * @self: A #ClutterActor
3164 * Renders the actor to display.
3166 * This function should not be called directly by applications.
3167 * Call clutter_actor_queue_redraw() to queue paints, instead.
3169 * This function is context-aware, and will either cause a
3170 * regular paint or a pick paint.
3172 * This function will emit the #ClutterActor::paint signal or
3173 * the #ClutterActor::pick signal, depending on the context.
3175 * This function does not paint the actor if the actor is set to 0,
3176 * unless it is performing a pick paint.
3179 clutter_actor_paint (ClutterActor *self)
3181 ClutterActorPrivate *priv;
3182 ClutterPickMode pick_mode;
3183 gboolean clip_set = FALSE;
3184 gboolean shader_applied = FALSE;
3186 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3187 "Actor real-paint counter",
3188 "Increments each time any actor is painted",
3189 0 /* no application private data */);
3190 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3191 "Actor pick-paint counter",
3192 "Increments each time any actor is painted "
3194 0 /* no application private data */);
3196 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3198 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3203 pick_mode = _clutter_context_get_pick_mode ();
3205 if (pick_mode == CLUTTER_PICK_NONE)
3206 priv->propagated_one_redraw = FALSE;
3208 /* It's an important optimization that we consider painting of
3209 * actors with 0 opacity to be a NOP... */
3210 if (pick_mode == CLUTTER_PICK_NONE &&
3211 /* ignore top-levels, since they might be transparent */
3212 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3213 /* Use the override opacity if its been set */
3214 ((priv->opacity_override >= 0) ?
3215 priv->opacity_override : priv->opacity) == 0)
3218 /* if we aren't paintable (not in a toplevel with all
3219 * parents paintable) then do nothing.
3221 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3224 /* mark that we are in the paint process */
3225 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3229 if (priv->enable_model_view_transform)
3233 /* XXX: It could be better to cache the modelview with the actor
3234 * instead of progressively building up the transformations on
3235 * the matrix stack every time we paint. */
3236 cogl_get_modelview_matrix (&matrix);
3237 _clutter_actor_apply_modelview_transform (self, &matrix);
3239 #ifdef CLUTTER_ENABLE_DEBUG
3240 /* Catch when out-of-band transforms have been made by actors not as part
3241 * of an apply_transform vfunc... */
3242 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3244 CoglMatrix expected_matrix;
3246 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3249 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3251 GString *buf = g_string_sized_new (1024);
3252 ClutterActor *parent;
3255 while (parent != NULL)
3257 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3259 if (parent->priv->parent != NULL)
3260 g_string_append (buf, "->");
3262 parent = parent->priv->parent;
3265 g_warning ("Unexpected transform found when painting actor "
3266 "\"%s\". This will be caused by one of the actor's "
3267 "ancestors (%s) using the Cogl API directly to transform "
3268 "children instead of using ::apply_transform().",
3269 _clutter_actor_get_debug_name (self),
3272 g_string_free (buf, TRUE);
3275 #endif /* CLUTTER_ENABLE_DEBUG */
3277 cogl_set_modelview_matrix (&matrix);
3282 cogl_clip_push_rectangle (priv->clip.x,
3284 priv->clip.x + priv->clip.width,
3285 priv->clip.y + priv->clip.height);
3288 else if (priv->clip_to_allocation)
3290 gfloat width, height;
3292 width = priv->allocation.x2 - priv->allocation.x1;
3293 height = priv->allocation.y2 - priv->allocation.y1;
3295 cogl_clip_push_rectangle (0, 0, width, height);
3299 if (pick_mode == CLUTTER_PICK_NONE)
3301 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3303 /* We check whether we need to add the flatten effect before
3304 each paint so that we can avoid having a mechanism for
3305 applications to notify when the value of the
3306 has_overlaps virtual changes. */
3307 add_or_remove_flatten_effect (self);
3310 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3312 /* We save the current paint volume so that the next time the
3313 * actor queues a redraw we can constrain the redraw to just
3314 * cover the union of the new bounding box and the old.
3316 * We also fetch the current paint volume to perform culling so
3317 * we can avoid painting actors outside the current clip region.
3319 * If we are painting inside a clone, we should neither update
3320 * the paint volume or use it to cull painting, since the paint
3321 * box represents the location of the source actor on the
3324 * XXX: We are starting to do a lot of vertex transforms on
3325 * the CPU in a typical paint, so at some point we should
3326 * audit these and consider caching some things.
3328 * NB: We don't perform culling while picking at this point because
3329 * clutter-stage.c doesn't setup the clipping planes appropriately.
3331 * NB: We don't want to update the last-paint-volume during picking
3332 * because the last-paint-volume is used to determine the old screen
3333 * space location of an actor that has moved so we can know the
3334 * minimal region to redraw to clear an old view of the actor. If we
3335 * update this during picking then by the time we come around to
3336 * paint then the last-paint-volume would likely represent the new
3337 * actor position not the old.
3339 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3342 /* annoyingly gcc warns if uninitialized even though
3343 * the initialization is redundant :-( */
3344 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3346 if (G_LIKELY ((clutter_paint_debug_flags &
3347 (CLUTTER_DEBUG_DISABLE_CULLING |
3348 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3349 (CLUTTER_DEBUG_DISABLE_CULLING |
3350 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3351 _clutter_actor_update_last_paint_volume (self);
3353 success = cull_actor (self, &result);
3355 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3356 _clutter_actor_paint_cull_result (self, success, result);
3357 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3361 if (priv->effects == NULL)
3363 if (pick_mode == CLUTTER_PICK_NONE &&
3364 actor_has_shader_data (self))
3366 _clutter_actor_shader_pre_paint (self, FALSE);
3367 shader_applied = TRUE;
3370 priv->next_effect_to_paint = NULL;
3373 priv->next_effect_to_paint =
3374 _clutter_meta_group_peek_metas (priv->effects);
3376 clutter_actor_continue_paint (self);
3379 _clutter_actor_shader_post_paint (self);
3381 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3382 pick_mode == CLUTTER_PICK_NONE))
3383 _clutter_actor_draw_paint_volume (self);
3386 /* If we make it here then the actor has run through a complete
3387 paint run including all the effects so it's no longer dirty */
3388 if (pick_mode == CLUTTER_PICK_NONE)
3389 priv->is_dirty = FALSE;
3396 /* paint sequence complete */
3397 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3401 * clutter_actor_continue_paint:
3402 * @self: A #ClutterActor
3404 * Run the next stage of the paint sequence. This function should only
3405 * be called within the implementation of the ‘run’ virtual of a
3406 * #ClutterEffect. It will cause the run method of the next effect to
3407 * be applied, or it will paint the actual actor if the current effect
3408 * is the last effect in the chain.
3413 clutter_actor_continue_paint (ClutterActor *self)
3415 ClutterActorPrivate *priv;
3417 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3418 /* This should only be called from with in the ‘run’ implementation
3419 of a ClutterEffect */
3420 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3424 /* Skip any effects that are disabled */
3425 while (priv->next_effect_to_paint &&
3426 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3427 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3429 /* If this has come from the last effect then we'll just paint the
3431 if (priv->next_effect_to_paint == NULL)
3433 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3435 ClutterPaintNode *dummy;
3437 /* XXX - this will go away in 2.0, when we can get rid of this
3438 * stuff and switch to a pure retained render tree of PaintNodes
3439 * for the entire frame, starting from the Stage.
3441 dummy = _clutter_dummy_node_new ();
3442 clutter_paint_node_set_name (dummy, "Root");
3443 clutter_actor_paint_node (self, dummy);
3445 if (clutter_paint_node_get_n_children (dummy) != 0)
3447 #ifdef CLUTTER_ENABLE_DEBUG
3448 if (CLUTTER_HAS_DEBUG (PAINT))
3450 /* dump the tree only if we have one */
3451 _clutter_paint_node_dump_tree (dummy);
3453 #endif /* CLUTTER_ENABLE_DEBUG */
3455 _clutter_paint_node_paint (dummy);
3458 clutter_paint_node_unref (dummy);
3460 g_signal_emit (self, actor_signals[PAINT], 0);
3464 ClutterColor col = { 0, };
3466 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3468 /* Actor will then paint silhouette of itself in supplied
3469 * color. See clutter_stage_get_actor_at_pos() for where
3470 * picking is enabled.
3472 g_signal_emit (self, actor_signals[PICK], 0, &col);
3477 ClutterEffect *old_current_effect;
3478 ClutterEffectPaintFlags run_flags = 0;
3480 /* Cache the current effect so that we can put it back before
3482 old_current_effect = priv->current_effect;
3484 priv->current_effect = priv->next_effect_to_paint->data;
3485 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3487 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3491 /* If there's an effect queued with this redraw then all
3492 effects up to that one will be considered dirty. It
3493 is expected the queued effect will paint the cached
3494 image and not call clutter_actor_continue_paint again
3495 (although it should work ok if it does) */
3496 if (priv->effect_to_redraw == NULL ||
3497 priv->current_effect != priv->effect_to_redraw)
3498 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3501 _clutter_effect_paint (priv->current_effect, run_flags);
3505 /* We can't determine when an actor has been modified since
3506 its last pick so lets just assume it has always been
3508 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3510 _clutter_effect_pick (priv->current_effect, run_flags);
3513 priv->current_effect = old_current_effect;
3517 static ClutterActorTraverseVisitFlags
3518 invalidate_queue_redraw_entry (ClutterActor *self,
3522 ClutterActorPrivate *priv = self->priv;
3524 if (priv->queue_redraw_entry != NULL)
3526 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3527 priv->queue_redraw_entry = NULL;
3530 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3534 remove_child (ClutterActor *self,
3535 ClutterActor *child)
3537 ClutterActor *prev_sibling, *next_sibling;
3539 prev_sibling = child->priv->prev_sibling;
3540 next_sibling = child->priv->next_sibling;
3542 if (prev_sibling != NULL)
3543 prev_sibling->priv->next_sibling = next_sibling;
3545 if (next_sibling != NULL)
3546 next_sibling->priv->prev_sibling = prev_sibling;
3548 if (self->priv->first_child == child)
3549 self->priv->first_child = next_sibling;
3551 if (self->priv->last_child == child)
3552 self->priv->last_child = prev_sibling;
3554 child->priv->parent = NULL;
3555 child->priv->prev_sibling = NULL;
3556 child->priv->next_sibling = NULL;
3560 REMOVE_CHILD_DESTROY_META = 1 << 0,
3561 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3562 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3563 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3564 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3565 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3567 /* default flags for public API */
3568 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3569 REMOVE_CHILD_EMIT_PARENT_SET |
3570 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3571 REMOVE_CHILD_CHECK_STATE |
3572 REMOVE_CHILD_FLUSH_QUEUE |
3573 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3575 /* flags for legacy/deprecated API */
3576 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3577 REMOVE_CHILD_FLUSH_QUEUE |
3578 REMOVE_CHILD_EMIT_PARENT_SET |
3579 REMOVE_CHILD_NOTIFY_FIRST_LAST
3580 } ClutterActorRemoveChildFlags;
3583 * clutter_actor_remove_child_internal:
3584 * @self: a #ClutterActor
3585 * @child: the child of @self that has to be removed
3586 * @flags: control the removal operations
3588 * Removes @child from the list of children of @self.
3591 clutter_actor_remove_child_internal (ClutterActor *self,
3592 ClutterActor *child,
3593 ClutterActorRemoveChildFlags flags)
3595 ClutterActor *old_first, *old_last;
3596 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3597 gboolean flush_queue;
3598 gboolean notify_first_last;
3599 gboolean was_mapped;
3601 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3602 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3603 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3604 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3605 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3606 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3608 g_object_freeze_notify (G_OBJECT (self));
3611 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3615 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3617 /* we need to unrealize *before* we set parent_actor to NULL,
3618 * because in an unrealize method actors are dissociating from the
3619 * stage, which means they need to be able to
3620 * clutter_actor_get_stage().
3622 * yhis should unmap and unrealize, unless we're reparenting.
3624 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3631 /* We take this opportunity to invalidate any queue redraw entry
3632 * associated with the actor and descendants since we won't be able to
3633 * determine the appropriate stage after this.
3635 * we do this after we updated the mapped state because actors might
3636 * end up queueing redraws inside their mapped/unmapped virtual
3637 * functions, and if we invalidate the redraw entry we could end up
3638 * with an inconsistent state and weird memory corruption. see
3641 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3642 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3644 _clutter_actor_traverse (child,
3646 invalidate_queue_redraw_entry,
3651 old_first = self->priv->first_child;
3652 old_last = self->priv->last_child;
3654 remove_child (self, child);
3656 self->priv->n_children -= 1;
3658 self->priv->age += 1;
3660 /* clutter_actor_reparent() will emit ::parent-set for us */
3661 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3662 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3664 /* if the child was mapped then we need to relayout ourselves to account
3665 * for the removed child
3668 clutter_actor_queue_relayout (self);
3670 /* we need to emit the signal before dropping the reference */
3671 if (emit_actor_removed)
3672 g_signal_emit_by_name (self, "actor-removed", child);
3674 if (notify_first_last)
3676 if (old_first != self->priv->first_child)
3677 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3679 if (old_last != self->priv->last_child)
3680 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3683 g_object_thaw_notify (G_OBJECT (self));
3685 /* remove the reference we acquired in clutter_actor_add_child() */
3686 g_object_unref (child);
3689 static const ClutterTransformInfo default_transform_info = {
3690 0.0, { 0, }, /* rotation-x */
3691 0.0, { 0, }, /* rotation-y */
3692 0.0, { 0, }, /* rotation-z */
3694 1.0, 1.0, { 0, }, /* scale */
3696 { 0, }, /* anchor */
3702 * _clutter_actor_get_transform_info_or_defaults:
3703 * @self: a #ClutterActor
3705 * Retrieves the ClutterTransformInfo structure associated to an actor.
3707 * If the actor does not have a ClutterTransformInfo structure associated
3708 * to it, then the default structure will be returned.
3710 * This function should only be used for getters.
3712 * Return value: a const pointer to the ClutterTransformInfo structure
3714 const ClutterTransformInfo *
3715 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3717 ClutterTransformInfo *info;
3719 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3723 return &default_transform_info;
3727 clutter_transform_info_free (gpointer data)
3730 g_slice_free (ClutterTransformInfo, data);
3734 * _clutter_actor_get_transform_info:
3735 * @self: a #ClutterActor
3737 * Retrieves a pointer to the ClutterTransformInfo structure.
3739 * If the actor does not have a ClutterTransformInfo associated to it, one
3740 * will be created and initialized to the default values.
3742 * This function should be used for setters.
3744 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3747 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3750 ClutterTransformInfo *
3751 _clutter_actor_get_transform_info (ClutterActor *self)
3753 ClutterTransformInfo *info;
3755 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3758 info = g_slice_new (ClutterTransformInfo);
3760 *info = default_transform_info;
3762 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3764 clutter_transform_info_free);
3771 * clutter_actor_set_rotation_angle_internal:
3772 * @self: a #ClutterActor
3773 * @axis: the axis of the angle to change
3774 * @angle: the angle of rotation
3776 * Sets the rotation angle on the given axis without affecting the
3777 * rotation center point.
3780 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3781 ClutterRotateAxis axis,
3784 GObject *obj = G_OBJECT (self);
3785 ClutterTransformInfo *info;
3787 info = _clutter_actor_get_transform_info (self);
3789 g_object_freeze_notify (obj);
3793 case CLUTTER_X_AXIS:
3794 info->rx_angle = angle;
3795 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3798 case CLUTTER_Y_AXIS:
3799 info->ry_angle = angle;
3800 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3803 case CLUTTER_Z_AXIS:
3804 info->rz_angle = angle;
3805 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3809 self->priv->transform_valid = FALSE;
3811 g_object_thaw_notify (obj);
3813 clutter_actor_queue_redraw (self);
3817 clutter_actor_set_rotation_angle (ClutterActor *self,
3818 ClutterRotateAxis axis,
3821 ClutterTransformInfo *info;
3823 info = _clutter_actor_get_transform_info (self);
3825 if (clutter_actor_get_easing_duration (self) != 0)
3827 ClutterTransition *transition;
3828 GParamSpec *pspec = NULL;
3829 double *cur_angle_p = NULL;
3833 case CLUTTER_X_AXIS:
3834 cur_angle_p = &info->rx_angle;
3835 pspec = obj_props[PROP_ROTATION_ANGLE_X];
3838 case CLUTTER_Y_AXIS:
3839 cur_angle_p = &info->ry_angle;
3840 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3843 case CLUTTER_Z_AXIS:
3844 cur_angle_p = &info->rz_angle;
3845 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3849 g_assert (pspec != NULL);
3850 g_assert (cur_angle_p != NULL);
3852 transition = _clutter_actor_get_transition (self, pspec);
3853 if (transition == NULL)
3855 transition = _clutter_actor_create_transition (self, pspec,
3858 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3861 _clutter_actor_update_transition (self, pspec, angle);
3863 self->priv->transform_valid = FALSE;
3864 clutter_actor_queue_redraw (self);
3867 clutter_actor_set_rotation_angle_internal (self, axis, angle);
3871 * clutter_actor_set_rotation_center_internal:
3872 * @self: a #ClutterActor
3873 * @axis: the axis of the center to change
3874 * @center: the coordinates of the rotation center
3876 * Sets the rotation center on the given axis without affecting the
3880 clutter_actor_set_rotation_center_internal (ClutterActor *self,
3881 ClutterRotateAxis axis,
3882 const ClutterVertex *center)
3884 GObject *obj = G_OBJECT (self);
3885 ClutterTransformInfo *info;
3886 ClutterVertex v = { 0, 0, 0 };
3888 info = _clutter_actor_get_transform_info (self);
3893 g_object_freeze_notify (obj);
3897 case CLUTTER_X_AXIS:
3898 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3899 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3902 case CLUTTER_Y_AXIS:
3903 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3904 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3907 case CLUTTER_Z_AXIS:
3908 /* if the previously set rotation center was fractional, then
3909 * setting explicit coordinates will have to notify the
3910 * :rotation-center-z-gravity property as well
3912 if (info->rz_center.is_fractional)
3913 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3915 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3916 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3920 self->priv->transform_valid = FALSE;
3922 g_object_thaw_notify (obj);
3924 clutter_actor_queue_redraw (self);
3928 clutter_actor_animate_scale_factor (ClutterActor *self,
3933 ClutterTransition *transition;
3935 transition = _clutter_actor_get_transition (self, pspec);
3936 if (transition == NULL)
3938 transition = _clutter_actor_create_transition (self, pspec,
3941 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3944 _clutter_actor_update_transition (self, pspec, new_factor);
3947 self->priv->transform_valid = FALSE;
3948 clutter_actor_queue_redraw (self);
3952 clutter_actor_set_scale_factor_internal (ClutterActor *self,
3956 GObject *obj = G_OBJECT (self);
3957 ClutterTransformInfo *info;
3959 info = _clutter_actor_get_transform_info (self);
3961 if (pspec == obj_props[PROP_SCALE_X])
3962 info->scale_x = factor;
3964 info->scale_y = factor;
3966 self->priv->transform_valid = FALSE;
3967 clutter_actor_queue_redraw (self);
3968 g_object_notify_by_pspec (obj, pspec);
3972 clutter_actor_set_scale_factor (ClutterActor *self,
3973 ClutterRotateAxis axis,
3976 GObject *obj = G_OBJECT (self);
3977 ClutterTransformInfo *info;
3980 info = _clutter_actor_get_transform_info (self);
3982 g_object_freeze_notify (obj);
3986 case CLUTTER_X_AXIS:
3987 pspec = obj_props[PROP_SCALE_X];
3989 if (clutter_actor_get_easing_duration (self) != 0)
3990 clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
3992 clutter_actor_set_scale_factor_internal (self, factor, pspec);
3995 case CLUTTER_Y_AXIS:
3996 pspec = obj_props[PROP_SCALE_Y];
3998 if (clutter_actor_get_easing_duration (self) != 0)
3999 clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4001 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4005 g_assert_not_reached ();
4008 g_object_thaw_notify (obj);
4012 clutter_actor_set_scale_center (ClutterActor *self,
4013 ClutterRotateAxis axis,
4016 GObject *obj = G_OBJECT (self);
4017 ClutterTransformInfo *info;
4018 gfloat center_x, center_y;
4020 info = _clutter_actor_get_transform_info (self);
4022 g_object_freeze_notify (obj);
4024 /* get the current scale center coordinates */
4025 clutter_anchor_coord_get_units (self, &info->scale_center,
4030 /* we need to notify this too, because setting explicit coordinates will
4031 * change the gravity as a side effect
4033 if (info->scale_center.is_fractional)
4034 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4038 case CLUTTER_X_AXIS:
4039 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4040 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4043 case CLUTTER_Y_AXIS:
4044 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4045 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4049 g_assert_not_reached ();
4052 self->priv->transform_valid = FALSE;
4054 clutter_actor_queue_redraw (self);
4056 g_object_thaw_notify (obj);
4060 clutter_actor_set_anchor_coord (ClutterActor *self,
4061 ClutterRotateAxis axis,
4064 GObject *obj = G_OBJECT (self);
4065 ClutterTransformInfo *info;
4066 gfloat anchor_x, anchor_y;
4068 info = _clutter_actor_get_transform_info (self);
4070 g_object_freeze_notify (obj);
4072 clutter_anchor_coord_get_units (self, &info->anchor,
4077 if (info->anchor.is_fractional)
4078 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4082 case CLUTTER_X_AXIS:
4083 clutter_anchor_coord_set_units (&info->anchor,
4087 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4090 case CLUTTER_Y_AXIS:
4091 clutter_anchor_coord_set_units (&info->anchor,
4095 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4099 g_assert_not_reached ();
4102 self->priv->transform_valid = FALSE;
4104 clutter_actor_queue_redraw (self);
4106 g_object_thaw_notify (obj);
4110 clutter_actor_set_property (GObject *object,
4112 const GValue *value,
4115 ClutterActor *actor = CLUTTER_ACTOR (object);
4116 ClutterActorPrivate *priv = actor->priv;
4121 clutter_actor_set_x (actor, g_value_get_float (value));
4125 clutter_actor_set_y (actor, g_value_get_float (value));
4129 clutter_actor_set_width (actor, g_value_get_float (value));
4133 clutter_actor_set_height (actor, g_value_get_float (value));
4137 clutter_actor_set_x (actor, g_value_get_float (value));
4141 clutter_actor_set_y (actor, g_value_get_float (value));
4144 case PROP_FIXED_POSITION_SET:
4145 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4148 case PROP_MIN_WIDTH:
4149 clutter_actor_set_min_width (actor, g_value_get_float (value));
4152 case PROP_MIN_HEIGHT:
4153 clutter_actor_set_min_height (actor, g_value_get_float (value));
4156 case PROP_NATURAL_WIDTH:
4157 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4160 case PROP_NATURAL_HEIGHT:
4161 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4164 case PROP_MIN_WIDTH_SET:
4165 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4168 case PROP_MIN_HEIGHT_SET:
4169 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4172 case PROP_NATURAL_WIDTH_SET:
4173 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4176 case PROP_NATURAL_HEIGHT_SET:
4177 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4180 case PROP_REQUEST_MODE:
4181 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4185 clutter_actor_set_depth (actor, g_value_get_float (value));
4189 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4192 case PROP_OFFSCREEN_REDIRECT:
4193 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4197 clutter_actor_set_name (actor, g_value_get_string (value));
4201 if (g_value_get_boolean (value) == TRUE)
4202 clutter_actor_show (actor);
4204 clutter_actor_hide (actor);
4208 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4209 g_value_get_double (value));
4213 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4214 g_value_get_double (value));
4217 case PROP_SCALE_CENTER_X:
4218 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4219 g_value_get_float (value));
4222 case PROP_SCALE_CENTER_Y:
4223 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4224 g_value_get_float (value));
4227 case PROP_SCALE_GRAVITY:
4229 const ClutterTransformInfo *info;
4230 ClutterGravity gravity;
4232 info = _clutter_actor_get_transform_info_or_defaults (actor);
4233 gravity = g_value_get_enum (value);
4235 clutter_actor_set_scale_with_gravity (actor,
4244 const ClutterGeometry *geom = g_value_get_boxed (value);
4246 clutter_actor_set_clip (actor,
4248 geom->width, geom->height);
4252 case PROP_CLIP_TO_ALLOCATION:
4253 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4257 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4260 case PROP_ROTATION_ANGLE_X:
4261 clutter_actor_set_rotation_angle (actor,
4263 g_value_get_double (value));
4266 case PROP_ROTATION_ANGLE_Y:
4267 clutter_actor_set_rotation_angle (actor,
4269 g_value_get_double (value));
4272 case PROP_ROTATION_ANGLE_Z:
4273 clutter_actor_set_rotation_angle (actor,
4275 g_value_get_double (value));
4278 case PROP_ROTATION_CENTER_X:
4279 clutter_actor_set_rotation_center_internal (actor,
4281 g_value_get_boxed (value));
4284 case PROP_ROTATION_CENTER_Y:
4285 clutter_actor_set_rotation_center_internal (actor,
4287 g_value_get_boxed (value));
4290 case PROP_ROTATION_CENTER_Z:
4291 clutter_actor_set_rotation_center_internal (actor,
4293 g_value_get_boxed (value));
4296 case PROP_ROTATION_CENTER_Z_GRAVITY:
4298 const ClutterTransformInfo *info;
4300 info = _clutter_actor_get_transform_info_or_defaults (actor);
4301 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4302 g_value_get_enum (value));
4307 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4308 g_value_get_float (value));
4312 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4313 g_value_get_float (value));
4316 case PROP_ANCHOR_GRAVITY:
4317 clutter_actor_set_anchor_point_from_gravity (actor,
4318 g_value_get_enum (value));
4321 case PROP_SHOW_ON_SET_PARENT:
4322 priv->show_on_set_parent = g_value_get_boolean (value);
4325 case PROP_TEXT_DIRECTION:
4326 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4330 clutter_actor_add_action (actor, g_value_get_object (value));
4333 case PROP_CONSTRAINTS:
4334 clutter_actor_add_constraint (actor, g_value_get_object (value));
4338 clutter_actor_add_effect (actor, g_value_get_object (value));
4341 case PROP_LAYOUT_MANAGER:
4342 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4346 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4350 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4353 case PROP_MARGIN_TOP:
4354 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4357 case PROP_MARGIN_BOTTOM:
4358 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4361 case PROP_MARGIN_LEFT:
4362 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4365 case PROP_MARGIN_RIGHT:
4366 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4369 case PROP_BACKGROUND_COLOR:
4370 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4374 clutter_actor_set_content (actor, g_value_get_object (value));
4377 case PROP_CONTENT_GRAVITY:
4378 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4382 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4388 clutter_actor_get_property (GObject *object,
4393 ClutterActor *actor = CLUTTER_ACTOR (object);
4394 ClutterActorPrivate *priv = actor->priv;
4399 g_value_set_float (value, clutter_actor_get_x (actor));
4403 g_value_set_float (value, clutter_actor_get_y (actor));
4407 g_value_set_float (value, clutter_actor_get_width (actor));
4411 g_value_set_float (value, clutter_actor_get_height (actor));
4416 const ClutterLayoutInfo *info;
4418 info = _clutter_actor_get_layout_info_or_defaults (actor);
4419 g_value_set_float (value, info->fixed_x);
4425 const ClutterLayoutInfo *info;
4427 info = _clutter_actor_get_layout_info_or_defaults (actor);
4428 g_value_set_float (value, info->fixed_y);
4432 case PROP_FIXED_POSITION_SET:
4433 g_value_set_boolean (value, priv->position_set);
4436 case PROP_MIN_WIDTH:
4438 const ClutterLayoutInfo *info;
4440 info = _clutter_actor_get_layout_info_or_defaults (actor);
4441 g_value_set_float (value, info->min_width);
4445 case PROP_MIN_HEIGHT:
4447 const ClutterLayoutInfo *info;
4449 info = _clutter_actor_get_layout_info_or_defaults (actor);
4450 g_value_set_float (value, info->min_height);
4454 case PROP_NATURAL_WIDTH:
4456 const ClutterLayoutInfo *info;
4458 info = _clutter_actor_get_layout_info_or_defaults (actor);
4459 g_value_set_float (value, info->natural_width);
4463 case PROP_NATURAL_HEIGHT:
4465 const ClutterLayoutInfo *info;
4467 info = _clutter_actor_get_layout_info_or_defaults (actor);
4468 g_value_set_float (value, info->natural_height);
4472 case PROP_MIN_WIDTH_SET:
4473 g_value_set_boolean (value, priv->min_width_set);
4476 case PROP_MIN_HEIGHT_SET:
4477 g_value_set_boolean (value, priv->min_height_set);
4480 case PROP_NATURAL_WIDTH_SET:
4481 g_value_set_boolean (value, priv->natural_width_set);
4484 case PROP_NATURAL_HEIGHT_SET:
4485 g_value_set_boolean (value, priv->natural_height_set);
4488 case PROP_REQUEST_MODE:
4489 g_value_set_enum (value, priv->request_mode);
4492 case PROP_ALLOCATION:
4493 g_value_set_boxed (value, &priv->allocation);
4497 g_value_set_float (value, clutter_actor_get_depth (actor));
4501 g_value_set_uint (value, priv->opacity);
4504 case PROP_OFFSCREEN_REDIRECT:
4505 g_value_set_enum (value, priv->offscreen_redirect);
4509 g_value_set_string (value, priv->name);
4513 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4517 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4521 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4525 g_value_set_boolean (value, priv->has_clip);
4530 ClutterGeometry clip;
4532 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4533 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4534 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4535 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4537 g_value_set_boxed (value, &clip);
4541 case PROP_CLIP_TO_ALLOCATION:
4542 g_value_set_boolean (value, priv->clip_to_allocation);
4547 const ClutterTransformInfo *info;
4549 info = _clutter_actor_get_transform_info_or_defaults (actor);
4550 g_value_set_double (value, info->scale_x);
4556 const ClutterTransformInfo *info;
4558 info = _clutter_actor_get_transform_info_or_defaults (actor);
4559 g_value_set_double (value, info->scale_y);
4563 case PROP_SCALE_CENTER_X:
4567 clutter_actor_get_scale_center (actor, ¢er, NULL);
4569 g_value_set_float (value, center);
4573 case PROP_SCALE_CENTER_Y:
4577 clutter_actor_get_scale_center (actor, NULL, ¢er);
4579 g_value_set_float (value, center);
4583 case PROP_SCALE_GRAVITY:
4584 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4588 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4591 case PROP_ROTATION_ANGLE_X:
4593 const ClutterTransformInfo *info;
4595 info = _clutter_actor_get_transform_info_or_defaults (actor);
4596 g_value_set_double (value, info->rx_angle);
4600 case PROP_ROTATION_ANGLE_Y:
4602 const ClutterTransformInfo *info;
4604 info = _clutter_actor_get_transform_info_or_defaults (actor);
4605 g_value_set_double (value, info->ry_angle);
4609 case PROP_ROTATION_ANGLE_Z:
4611 const ClutterTransformInfo *info;
4613 info = _clutter_actor_get_transform_info_or_defaults (actor);
4614 g_value_set_double (value, info->rz_angle);
4618 case PROP_ROTATION_CENTER_X:
4620 ClutterVertex center;
4622 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4627 g_value_set_boxed (value, ¢er);
4631 case PROP_ROTATION_CENTER_Y:
4633 ClutterVertex center;
4635 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4640 g_value_set_boxed (value, ¢er);
4644 case PROP_ROTATION_CENTER_Z:
4646 ClutterVertex center;
4648 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4653 g_value_set_boxed (value, ¢er);
4657 case PROP_ROTATION_CENTER_Z_GRAVITY:
4658 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4663 const ClutterTransformInfo *info;
4666 info = _clutter_actor_get_transform_info_or_defaults (actor);
4667 clutter_anchor_coord_get_units (actor, &info->anchor,
4671 g_value_set_float (value, anchor_x);
4677 const ClutterTransformInfo *info;
4680 info = _clutter_actor_get_transform_info_or_defaults (actor);
4681 clutter_anchor_coord_get_units (actor, &info->anchor,
4685 g_value_set_float (value, anchor_y);
4689 case PROP_ANCHOR_GRAVITY:
4690 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4693 case PROP_SHOW_ON_SET_PARENT:
4694 g_value_set_boolean (value, priv->show_on_set_parent);
4697 case PROP_TEXT_DIRECTION:
4698 g_value_set_enum (value, priv->text_direction);
4701 case PROP_HAS_POINTER:
4702 g_value_set_boolean (value, priv->has_pointer);
4705 case PROP_LAYOUT_MANAGER:
4706 g_value_set_object (value, priv->layout_manager);
4711 const ClutterLayoutInfo *info;
4713 info = _clutter_actor_get_layout_info_or_defaults (actor);
4714 g_value_set_enum (value, info->x_align);
4720 const ClutterLayoutInfo *info;
4722 info = _clutter_actor_get_layout_info_or_defaults (actor);
4723 g_value_set_enum (value, info->y_align);
4727 case PROP_MARGIN_TOP:
4729 const ClutterLayoutInfo *info;
4731 info = _clutter_actor_get_layout_info_or_defaults (actor);
4732 g_value_set_float (value, info->margin.top);
4736 case PROP_MARGIN_BOTTOM:
4738 const ClutterLayoutInfo *info;
4740 info = _clutter_actor_get_layout_info_or_defaults (actor);
4741 g_value_set_float (value, info->margin.bottom);
4745 case PROP_MARGIN_LEFT:
4747 const ClutterLayoutInfo *info;
4749 info = _clutter_actor_get_layout_info_or_defaults (actor);
4750 g_value_set_float (value, info->margin.left);
4754 case PROP_MARGIN_RIGHT:
4756 const ClutterLayoutInfo *info;
4758 info = _clutter_actor_get_layout_info_or_defaults (actor);
4759 g_value_set_float (value, info->margin.right);
4763 case PROP_BACKGROUND_COLOR_SET:
4764 g_value_set_boolean (value, priv->bg_color_set);
4767 case PROP_BACKGROUND_COLOR:
4768 g_value_set_boxed (value, &priv->bg_color);
4771 case PROP_FIRST_CHILD:
4772 g_value_set_object (value, priv->first_child);
4775 case PROP_LAST_CHILD:
4776 g_value_set_object (value, priv->last_child);
4780 g_value_set_object (value, priv->content);
4783 case PROP_CONTENT_GRAVITY:
4784 g_value_set_enum (value, priv->content_gravity);
4787 case PROP_CONTENT_BOX:
4789 ClutterActorBox box = { 0, };
4791 clutter_actor_get_content_box (actor, &box);
4792 g_value_set_boxed (value, &box);
4797 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4803 clutter_actor_dispose (GObject *object)
4805 ClutterActor *self = CLUTTER_ACTOR (object);
4806 ClutterActorPrivate *priv = self->priv;
4808 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4810 g_type_name (G_OBJECT_TYPE (self)),
4813 g_signal_emit (self, actor_signals[DESTROY], 0);
4815 /* avoid recursing when called from clutter_actor_destroy() */
4816 if (priv->parent != NULL)
4818 ClutterActor *parent = priv->parent;
4820 /* go through the Container implementation unless this
4821 * is an internal child and has been marked as such.
4823 * removing the actor from its parent will reset the
4824 * realized and mapped states.
4826 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4827 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4829 clutter_actor_remove_child_internal (parent, self,
4830 REMOVE_CHILD_LEGACY_FLAGS);
4833 /* parent must be gone at this point */
4834 g_assert (priv->parent == NULL);
4836 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4838 /* can't be mapped or realized with no parent */
4839 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4840 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4843 g_clear_object (&priv->pango_context);
4844 g_clear_object (&priv->actions);
4845 g_clear_object (&priv->constraints);
4846 g_clear_object (&priv->effects);
4847 g_clear_object (&priv->flatten_effect);
4849 if (priv->layout_manager != NULL)
4851 clutter_layout_manager_set_container (priv->layout_manager, NULL);
4852 g_clear_object (&priv->layout_manager);
4855 if (priv->content != NULL)
4857 _clutter_content_detached (priv->content, self);
4858 g_clear_object (&priv->content);
4861 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4865 clutter_actor_finalize (GObject *object)
4867 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4869 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4870 priv->name != NULL ? priv->name : "<none>",
4872 g_type_name (G_OBJECT_TYPE (object)));
4874 _clutter_context_release_id (priv->id);
4876 g_free (priv->name);
4878 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4883 * clutter_actor_get_accessible:
4884 * @self: a #ClutterActor
4886 * Returns the accessible object that describes the actor to an
4887 * assistive technology.
4889 * If no class-specific #AtkObject implementation is available for the
4890 * actor instance in question, it will inherit an #AtkObject
4891 * implementation from the first ancestor class for which such an
4892 * implementation is defined.
4894 * The documentation of the <ulink
4895 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4896 * library contains more information about accessible objects and
4899 * Returns: (transfer none): the #AtkObject associated with @actor
4902 clutter_actor_get_accessible (ClutterActor *self)
4904 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4906 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4910 clutter_actor_real_get_accessible (ClutterActor *actor)
4912 return atk_gobject_accessible_for_object (G_OBJECT (actor));
4916 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4918 AtkObject *accessible;
4920 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4921 if (accessible != NULL)
4922 g_object_ref (accessible);
4928 atk_implementor_iface_init (AtkImplementorIface *iface)
4930 iface->ref_accessible = _clutter_actor_ref_accessible;
4934 clutter_actor_update_default_paint_volume (ClutterActor *self,
4935 ClutterPaintVolume *volume)
4937 ClutterActorPrivate *priv = self->priv;
4938 gboolean res = FALSE;
4940 /* we start from the allocation */
4941 clutter_paint_volume_set_width (volume,
4942 priv->allocation.x2 - priv->allocation.x1);
4943 clutter_paint_volume_set_height (volume,
4944 priv->allocation.y2 - priv->allocation.y1);
4946 /* if the actor has a clip set then we have a pretty definite
4947 * size for the paint volume: the actor cannot possibly paint
4948 * outside the clip region.
4950 if (priv->clip_to_allocation)
4952 /* the allocation has already been set, so we just flip the
4959 ClutterActor *child;
4961 if (priv->has_clip &&
4962 priv->clip.width >= 0 &&
4963 priv->clip.height >= 0)
4965 ClutterVertex origin;
4967 origin.x = priv->clip.x;
4968 origin.y = priv->clip.y;
4971 clutter_paint_volume_set_origin (volume, &origin);
4972 clutter_paint_volume_set_width (volume, priv->clip.width);
4973 clutter_paint_volume_set_height (volume, priv->clip.height);
4978 /* if we don't have children we just bail out here... */
4979 if (priv->n_children == 0)
4982 /* ...but if we have children then we ask for their paint volume in
4983 * our coordinates. if any of our children replies that it doesn't
4984 * have a paint volume, we bail out
4986 for (child = priv->first_child;
4988 child = child->priv->next_sibling)
4990 const ClutterPaintVolume *child_volume;
4992 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4993 if (child_volume == NULL)
4999 clutter_paint_volume_union (volume, child_volume);
5009 clutter_actor_real_get_paint_volume (ClutterActor *self,
5010 ClutterPaintVolume *volume)
5012 ClutterActorClass *klass;
5015 klass = CLUTTER_ACTOR_GET_CLASS (self);
5017 /* XXX - this thoroughly sucks, but we don't want to penalize users
5018 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5019 * redraw. This should go away in 2.0.
5021 if (klass->paint == clutter_actor_real_paint &&
5022 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5028 /* this is the default return value: we cannot know if a class
5029 * is going to paint outside its allocation, so we take the
5030 * conservative approach.
5035 if (clutter_actor_update_default_paint_volume (self, volume))
5042 * clutter_actor_get_default_paint_volume:
5043 * @self: a #ClutterActor
5045 * Retrieves the default paint volume for @self.
5047 * This function provides the same #ClutterPaintVolume that would be
5048 * computed by the default implementation inside #ClutterActor of the
5049 * #ClutterActorClass.get_paint_volume() virtual function.
5051 * This function should only be used by #ClutterActor subclasses that
5052 * cannot chain up to the parent implementation when computing their
5055 * Return value: (transfer none): a pointer to the default
5056 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5057 * the actor could not compute a valid paint volume. The returned value
5058 * is not guaranteed to be stable across multiple frames, so if you
5059 * want to retain it, you will need to copy it using
5060 * clutter_paint_volume_copy().
5064 const ClutterPaintVolume *
5065 clutter_actor_get_default_paint_volume (ClutterActor *self)
5067 ClutterPaintVolume volume;
5068 ClutterPaintVolume *res;
5070 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5073 _clutter_paint_volume_init_static (&volume, self);
5074 if (clutter_actor_update_default_paint_volume (self, &volume))
5076 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5080 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5081 _clutter_paint_volume_copy_static (&volume, res);
5085 clutter_paint_volume_free (&volume);
5091 clutter_actor_real_has_overlaps (ClutterActor *self)
5093 /* By default we'll assume that all actors need an offscreen redirect to get
5094 * the correct opacity. Actors such as ClutterTexture that would never need
5095 * an offscreen redirect can override this to return FALSE. */
5100 clutter_actor_real_destroy (ClutterActor *actor)
5102 ClutterActorIter iter;
5104 clutter_actor_iter_init (&iter, actor);
5105 while (clutter_actor_iter_next (&iter, NULL))
5106 clutter_actor_iter_destroy (&iter);
5110 clutter_actor_constructor (GType gtype,
5112 GObjectConstructParam *props)
5114 GObjectClass *gobject_class;
5118 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5119 retval = gobject_class->constructor (gtype, n_props, props);
5120 self = CLUTTER_ACTOR (retval);
5122 if (self->priv->layout_manager == NULL)
5124 ClutterLayoutManager *default_layout;
5126 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5128 default_layout = clutter_fixed_layout_new ();
5129 clutter_actor_set_layout_manager (self, default_layout);
5136 clutter_actor_class_init (ClutterActorClass *klass)
5138 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5140 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5141 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5142 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5143 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5145 object_class->constructor = clutter_actor_constructor;
5146 object_class->set_property = clutter_actor_set_property;
5147 object_class->get_property = clutter_actor_get_property;
5148 object_class->dispose = clutter_actor_dispose;
5149 object_class->finalize = clutter_actor_finalize;
5151 klass->show = clutter_actor_real_show;
5152 klass->show_all = clutter_actor_show;
5153 klass->hide = clutter_actor_real_hide;
5154 klass->hide_all = clutter_actor_hide;
5155 klass->map = clutter_actor_real_map;
5156 klass->unmap = clutter_actor_real_unmap;
5157 klass->unrealize = clutter_actor_real_unrealize;
5158 klass->pick = clutter_actor_real_pick;
5159 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5160 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5161 klass->allocate = clutter_actor_real_allocate;
5162 klass->queue_redraw = clutter_actor_real_queue_redraw;
5163 klass->queue_relayout = clutter_actor_real_queue_relayout;
5164 klass->apply_transform = clutter_actor_real_apply_transform;
5165 klass->get_accessible = clutter_actor_real_get_accessible;
5166 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5167 klass->has_overlaps = clutter_actor_real_has_overlaps;
5168 klass->paint = clutter_actor_real_paint;
5169 klass->destroy = clutter_actor_real_destroy;
5171 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5176 * X coordinate of the actor in pixels. If written, forces a fixed
5177 * position for the actor. If read, returns the fixed position if any,
5178 * otherwise the allocation if available, otherwise 0.
5180 * The #ClutterActor:x property is animatable.
5183 g_param_spec_float ("x",
5185 P_("X coordinate of the actor"),
5186 -G_MAXFLOAT, G_MAXFLOAT,
5189 G_PARAM_STATIC_STRINGS |
5190 CLUTTER_PARAM_ANIMATABLE);
5195 * Y coordinate of the actor in pixels. If written, forces a fixed
5196 * position for the actor. If read, returns the fixed position if
5197 * any, otherwise the allocation if available, otherwise 0.
5199 * The #ClutterActor:y property is animatable.
5202 g_param_spec_float ("y",
5204 P_("Y coordinate of the actor"),
5205 -G_MAXFLOAT, G_MAXFLOAT,
5208 G_PARAM_STATIC_STRINGS |
5209 CLUTTER_PARAM_ANIMATABLE);
5212 * ClutterActor:width:
5214 * Width of the actor (in pixels). If written, forces the minimum and
5215 * natural size request of the actor to the given width. If read, returns
5216 * the allocated width if available, otherwise the width request.
5218 * The #ClutterActor:width property is animatable.
5220 obj_props[PROP_WIDTH] =
5221 g_param_spec_float ("width",
5223 P_("Width of the actor"),
5227 G_PARAM_STATIC_STRINGS |
5228 CLUTTER_PARAM_ANIMATABLE);
5231 * ClutterActor:height:
5233 * Height of the actor (in pixels). If written, forces the minimum and
5234 * natural size request of the actor to the given height. If read, returns
5235 * the allocated height if available, otherwise the height request.
5237 * The #ClutterActor:height property is animatable.
5239 obj_props[PROP_HEIGHT] =
5240 g_param_spec_float ("height",
5242 P_("Height of the actor"),
5246 G_PARAM_STATIC_STRINGS |
5247 CLUTTER_PARAM_ANIMATABLE);
5250 * ClutterActor:fixed-x:
5252 * The fixed X position of the actor in pixels.
5254 * Writing this property sets #ClutterActor:fixed-position-set
5255 * property as well, as a side effect
5259 obj_props[PROP_FIXED_X] =
5260 g_param_spec_float ("fixed-x",
5262 P_("Forced X position of the actor"),
5263 -G_MAXFLOAT, G_MAXFLOAT,
5265 CLUTTER_PARAM_READWRITE);
5268 * ClutterActor:fixed-y:
5270 * The fixed Y position of the actor in pixels.
5272 * Writing this property sets the #ClutterActor:fixed-position-set
5273 * property as well, as a side effect
5277 obj_props[PROP_FIXED_Y] =
5278 g_param_spec_float ("fixed-y",
5280 P_("Forced Y position of the actor"),
5281 -G_MAXFLOAT, G_MAXFLOAT,
5283 CLUTTER_PARAM_READWRITE);
5286 * ClutterActor:fixed-position-set:
5288 * This flag controls whether the #ClutterActor:fixed-x and
5289 * #ClutterActor:fixed-y properties are used
5293 obj_props[PROP_FIXED_POSITION_SET] =
5294 g_param_spec_boolean ("fixed-position-set",
5295 P_("Fixed position set"),
5296 P_("Whether to use fixed positioning for the actor"),
5298 CLUTTER_PARAM_READWRITE);
5301 * ClutterActor:min-width:
5303 * A forced minimum width request for the actor, in pixels
5305 * Writing this property sets the #ClutterActor:min-width-set property
5306 * as well, as a side effect.
5308 *This property overrides the usual width request of the actor.
5312 obj_props[PROP_MIN_WIDTH] =
5313 g_param_spec_float ("min-width",
5315 P_("Forced minimum width request for the actor"),
5318 CLUTTER_PARAM_READWRITE);
5321 * ClutterActor:min-height:
5323 * A forced minimum height request for the actor, in pixels
5325 * Writing this property sets the #ClutterActor:min-height-set property
5326 * as well, as a side effect. This property overrides the usual height
5327 * request of the actor.
5331 obj_props[PROP_MIN_HEIGHT] =
5332 g_param_spec_float ("min-height",
5334 P_("Forced minimum height request for the actor"),
5337 CLUTTER_PARAM_READWRITE);
5340 * ClutterActor:natural-width:
5342 * A forced natural width request for the actor, in pixels
5344 * Writing this property sets the #ClutterActor:natural-width-set
5345 * property as well, as a side effect. This property overrides the
5346 * usual width request of the actor
5350 obj_props[PROP_NATURAL_WIDTH] =
5351 g_param_spec_float ("natural-width",
5352 P_("Natural Width"),
5353 P_("Forced natural width request for the actor"),
5356 CLUTTER_PARAM_READWRITE);
5359 * ClutterActor:natural-height:
5361 * A forced natural height request for the actor, in pixels
5363 * Writing this property sets the #ClutterActor:natural-height-set
5364 * property as well, as a side effect. This property overrides the
5365 * usual height request of the actor
5369 obj_props[PROP_NATURAL_HEIGHT] =
5370 g_param_spec_float ("natural-height",
5371 P_("Natural Height"),
5372 P_("Forced natural height request for the actor"),
5375 CLUTTER_PARAM_READWRITE);
5378 * ClutterActor:min-width-set:
5380 * This flag controls whether the #ClutterActor:min-width property
5385 obj_props[PROP_MIN_WIDTH_SET] =
5386 g_param_spec_boolean ("min-width-set",
5387 P_("Minimum width set"),
5388 P_("Whether to use the min-width property"),
5390 CLUTTER_PARAM_READWRITE);
5393 * ClutterActor:min-height-set:
5395 * This flag controls whether the #ClutterActor:min-height property
5400 obj_props[PROP_MIN_HEIGHT_SET] =
5401 g_param_spec_boolean ("min-height-set",
5402 P_("Minimum height set"),
5403 P_("Whether to use the min-height property"),
5405 CLUTTER_PARAM_READWRITE);
5408 * ClutterActor:natural-width-set:
5410 * This flag controls whether the #ClutterActor:natural-width property
5415 obj_props[PROP_NATURAL_WIDTH_SET] =
5416 g_param_spec_boolean ("natural-width-set",
5417 P_("Natural width set"),
5418 P_("Whether to use the natural-width property"),
5420 CLUTTER_PARAM_READWRITE);
5423 * ClutterActor:natural-height-set:
5425 * This flag controls whether the #ClutterActor:natural-height property
5430 obj_props[PROP_NATURAL_HEIGHT_SET] =
5431 g_param_spec_boolean ("natural-height-set",
5432 P_("Natural height set"),
5433 P_("Whether to use the natural-height property"),
5435 CLUTTER_PARAM_READWRITE);
5438 * ClutterActor:allocation:
5440 * The allocation for the actor, in pixels
5442 * This is property is read-only, but you might monitor it to know when an
5443 * actor moves or resizes
5447 obj_props[PROP_ALLOCATION] =
5448 g_param_spec_boxed ("allocation",
5450 P_("The actor's allocation"),
5451 CLUTTER_TYPE_ACTOR_BOX,
5452 CLUTTER_PARAM_READABLE);
5455 * ClutterActor:request-mode:
5457 * Request mode for the #ClutterActor. The request mode determines the
5458 * type of geometry management used by the actor, either height for width
5459 * (the default) or width for height.
5461 * For actors implementing height for width, the parent container should get
5462 * the preferred width first, and then the preferred height for that width.
5464 * For actors implementing width for height, the parent container should get
5465 * the preferred height first, and then the preferred width for that height.
5470 * ClutterRequestMode mode;
5471 * gfloat natural_width, min_width;
5472 * gfloat natural_height, min_height;
5474 * mode = clutter_actor_get_request_mode (child);
5475 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5477 * clutter_actor_get_preferred_width (child, -1,
5479 * &natural_width);
5480 * clutter_actor_get_preferred_height (child, natural_width,
5482 * &natural_height);
5486 * clutter_actor_get_preferred_height (child, -1,
5488 * &natural_height);
5489 * clutter_actor_get_preferred_width (child, natural_height,
5491 * &natural_width);
5495 * will retrieve the minimum and natural width and height depending on the
5496 * preferred request mode of the #ClutterActor "child".
5498 * The clutter_actor_get_preferred_size() function will implement this
5503 obj_props[PROP_REQUEST_MODE] =
5504 g_param_spec_enum ("request-mode",
5506 P_("The actor's request mode"),
5507 CLUTTER_TYPE_REQUEST_MODE,
5508 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5509 CLUTTER_PARAM_READWRITE);
5512 * ClutterActor:depth:
5514 * The position of the actor on the Z axis.
5516 * The #ClutterActor:depth property is relative to the parent's
5519 * The #ClutterActor:depth property is animatable.
5523 obj_props[PROP_DEPTH] =
5524 g_param_spec_float ("depth",
5526 P_("Position on the Z axis"),
5527 -G_MAXFLOAT, G_MAXFLOAT,
5530 G_PARAM_STATIC_STRINGS |
5531 CLUTTER_PARAM_ANIMATABLE);
5534 * ClutterActor:opacity:
5536 * Opacity of an actor, between 0 (fully transparent) and
5537 * 255 (fully opaque)
5539 * The #ClutterActor:opacity property is animatable.
5541 obj_props[PROP_OPACITY] =
5542 g_param_spec_uint ("opacity",
5544 P_("Opacity of an actor"),
5548 G_PARAM_STATIC_STRINGS |
5549 CLUTTER_PARAM_ANIMATABLE);
5552 * ClutterActor:offscreen-redirect:
5554 * Determines the conditions in which the actor will be redirected
5555 * to an offscreen framebuffer while being painted. For example this
5556 * can be used to cache an actor in a framebuffer or for improved
5557 * handling of transparent actors. See
5558 * clutter_actor_set_offscreen_redirect() for details.
5562 obj_props[PROP_OFFSCREEN_REDIRECT] =
5563 g_param_spec_flags ("offscreen-redirect",
5564 P_("Offscreen redirect"),
5565 P_("Flags controlling when to flatten the actor into a single image"),
5566 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5568 CLUTTER_PARAM_READWRITE);
5571 * ClutterActor:visible:
5573 * Whether the actor is set to be visible or not
5575 * See also #ClutterActor:mapped
5577 obj_props[PROP_VISIBLE] =
5578 g_param_spec_boolean ("visible",
5580 P_("Whether the actor is visible or not"),
5582 CLUTTER_PARAM_READWRITE);
5585 * ClutterActor:mapped:
5587 * Whether the actor is mapped (will be painted when the stage
5588 * to which it belongs is mapped)
5592 obj_props[PROP_MAPPED] =
5593 g_param_spec_boolean ("mapped",
5595 P_("Whether the actor will be painted"),
5597 CLUTTER_PARAM_READABLE);
5600 * ClutterActor:realized:
5602 * Whether the actor has been realized
5606 obj_props[PROP_REALIZED] =
5607 g_param_spec_boolean ("realized",
5609 P_("Whether the actor has been realized"),
5611 CLUTTER_PARAM_READABLE);
5614 * ClutterActor:reactive:
5616 * Whether the actor is reactive to events or not
5618 * Only reactive actors will emit event-related signals
5622 obj_props[PROP_REACTIVE] =
5623 g_param_spec_boolean ("reactive",
5625 P_("Whether the actor is reactive to events"),
5627 CLUTTER_PARAM_READWRITE);
5630 * ClutterActor:has-clip:
5632 * Whether the actor has the #ClutterActor:clip property set or not
5634 obj_props[PROP_HAS_CLIP] =
5635 g_param_spec_boolean ("has-clip",
5637 P_("Whether the actor has a clip set"),
5639 CLUTTER_PARAM_READABLE);
5642 * ClutterActor:clip:
5644 * The clip region for the actor, in actor-relative coordinates
5646 * Every part of the actor outside the clip region will not be
5649 obj_props[PROP_CLIP] =
5650 g_param_spec_boxed ("clip",
5652 P_("The clip region for the actor"),
5653 CLUTTER_TYPE_GEOMETRY,
5654 CLUTTER_PARAM_READWRITE);
5657 * ClutterActor:name:
5659 * The name of the actor
5663 obj_props[PROP_NAME] =
5664 g_param_spec_string ("name",
5666 P_("Name of the actor"),
5668 CLUTTER_PARAM_READWRITE);
5671 * ClutterActor:scale-x:
5673 * The horizontal scale of the actor.
5675 * The #ClutterActor:scale-x property is animatable.
5679 obj_props[PROP_SCALE_X] =
5680 g_param_spec_double ("scale-x",
5682 P_("Scale factor on the X axis"),
5686 G_PARAM_STATIC_STRINGS |
5687 CLUTTER_PARAM_ANIMATABLE);
5690 * ClutterActor:scale-y:
5692 * The vertical scale of the actor.
5694 * The #ClutterActor:scale-y property is animatable.
5698 obj_props[PROP_SCALE_Y] =
5699 g_param_spec_double ("scale-y",
5701 P_("Scale factor on the Y axis"),
5705 G_PARAM_STATIC_STRINGS |
5706 CLUTTER_PARAM_ANIMATABLE);
5709 * ClutterActor:scale-center-x:
5711 * The horizontal center point for scaling
5715 obj_props[PROP_SCALE_CENTER_X] =
5716 g_param_spec_float ("scale-center-x",
5717 P_("Scale Center X"),
5718 P_("Horizontal scale center"),
5719 -G_MAXFLOAT, G_MAXFLOAT,
5721 CLUTTER_PARAM_READWRITE);
5724 * ClutterActor:scale-center-y:
5726 * The vertical center point for scaling
5730 obj_props[PROP_SCALE_CENTER_Y] =
5731 g_param_spec_float ("scale-center-y",
5732 P_("Scale Center Y"),
5733 P_("Vertical scale center"),
5734 -G_MAXFLOAT, G_MAXFLOAT,
5736 CLUTTER_PARAM_READWRITE);
5739 * ClutterActor:scale-gravity:
5741 * The center point for scaling expressed as a #ClutterGravity
5745 obj_props[PROP_SCALE_GRAVITY] =
5746 g_param_spec_enum ("scale-gravity",
5747 P_("Scale Gravity"),
5748 P_("The center of scaling"),
5749 CLUTTER_TYPE_GRAVITY,
5750 CLUTTER_GRAVITY_NONE,
5751 CLUTTER_PARAM_READWRITE);
5754 * ClutterActor:rotation-angle-x:
5756 * The rotation angle on the X axis.
5758 * The #ClutterActor:rotation-angle-x property is animatable.
5762 obj_props[PROP_ROTATION_ANGLE_X] =
5763 g_param_spec_double ("rotation-angle-x",
5764 P_("Rotation Angle X"),
5765 P_("The rotation angle on the X axis"),
5766 -G_MAXDOUBLE, G_MAXDOUBLE,
5769 G_PARAM_STATIC_STRINGS |
5770 CLUTTER_PARAM_ANIMATABLE);
5773 * ClutterActor:rotation-angle-y:
5775 * The rotation angle on the Y axis
5777 * The #ClutterActor:rotation-angle-y property is animatable.
5781 obj_props[PROP_ROTATION_ANGLE_Y] =
5782 g_param_spec_double ("rotation-angle-y",
5783 P_("Rotation Angle Y"),
5784 P_("The rotation angle on the Y axis"),
5785 -G_MAXDOUBLE, G_MAXDOUBLE,
5788 G_PARAM_STATIC_STRINGS |
5789 CLUTTER_PARAM_ANIMATABLE);
5792 * ClutterActor:rotation-angle-z:
5794 * The rotation angle on the Z axis
5796 * The #ClutterActor:rotation-angle-z property is animatable.
5800 obj_props[PROP_ROTATION_ANGLE_Z] =
5801 g_param_spec_double ("rotation-angle-z",
5802 P_("Rotation Angle Z"),
5803 P_("The rotation angle on the Z axis"),
5804 -G_MAXDOUBLE, G_MAXDOUBLE,
5807 G_PARAM_STATIC_STRINGS |
5808 CLUTTER_PARAM_ANIMATABLE);
5811 * ClutterActor:rotation-center-x:
5813 * The rotation center on the X axis.
5817 obj_props[PROP_ROTATION_CENTER_X] =
5818 g_param_spec_boxed ("rotation-center-x",
5819 P_("Rotation Center X"),
5820 P_("The rotation center on the X axis"),
5821 CLUTTER_TYPE_VERTEX,
5822 CLUTTER_PARAM_READWRITE);
5825 * ClutterActor:rotation-center-y:
5827 * The rotation center on the Y axis.
5831 obj_props[PROP_ROTATION_CENTER_Y] =
5832 g_param_spec_boxed ("rotation-center-y",
5833 P_("Rotation Center Y"),
5834 P_("The rotation center on the Y axis"),
5835 CLUTTER_TYPE_VERTEX,
5836 CLUTTER_PARAM_READWRITE);
5839 * ClutterActor:rotation-center-z:
5841 * The rotation center on the Z axis.
5845 obj_props[PROP_ROTATION_CENTER_Z] =
5846 g_param_spec_boxed ("rotation-center-z",
5847 P_("Rotation Center Z"),
5848 P_("The rotation center on the Z axis"),
5849 CLUTTER_TYPE_VERTEX,
5850 CLUTTER_PARAM_READWRITE);
5853 * ClutterActor:rotation-center-z-gravity:
5855 * The rotation center on the Z axis expressed as a #ClutterGravity.
5859 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5860 g_param_spec_enum ("rotation-center-z-gravity",
5861 P_("Rotation Center Z Gravity"),
5862 P_("Center point for rotation around the Z axis"),
5863 CLUTTER_TYPE_GRAVITY,
5864 CLUTTER_GRAVITY_NONE,
5865 CLUTTER_PARAM_READWRITE);
5868 * ClutterActor:anchor-x:
5870 * The X coordinate of an actor's anchor point, relative to
5871 * the actor coordinate space, in pixels
5875 obj_props[PROP_ANCHOR_X] =
5876 g_param_spec_float ("anchor-x",
5878 P_("X coordinate of the anchor point"),
5879 -G_MAXFLOAT, G_MAXFLOAT,
5881 CLUTTER_PARAM_READWRITE);
5884 * ClutterActor:anchor-y:
5886 * The Y coordinate of an actor's anchor point, relative to
5887 * the actor coordinate space, in pixels
5891 obj_props[PROP_ANCHOR_Y] =
5892 g_param_spec_float ("anchor-y",
5894 P_("Y coordinate of the anchor point"),
5895 -G_MAXFLOAT, G_MAXFLOAT,
5897 CLUTTER_PARAM_READWRITE);
5900 * ClutterActor:anchor-gravity:
5902 * The anchor point expressed as a #ClutterGravity
5906 obj_props[PROP_ANCHOR_GRAVITY] =
5907 g_param_spec_enum ("anchor-gravity",
5908 P_("Anchor Gravity"),
5909 P_("The anchor point as a ClutterGravity"),
5910 CLUTTER_TYPE_GRAVITY,
5911 CLUTTER_GRAVITY_NONE,
5912 CLUTTER_PARAM_READWRITE);
5915 * ClutterActor:show-on-set-parent:
5917 * If %TRUE, the actor is automatically shown when parented.
5919 * Calling clutter_actor_hide() on an actor which has not been
5920 * parented will set this property to %FALSE as a side effect.
5924 obj_props[PROP_SHOW_ON_SET_PARENT] =
5925 g_param_spec_boolean ("show-on-set-parent",
5926 P_("Show on set parent"),
5927 P_("Whether the actor is shown when parented"),
5929 CLUTTER_PARAM_READWRITE);
5932 * ClutterActor:clip-to-allocation:
5934 * Whether the clip region should track the allocated area
5937 * This property is ignored if a clip area has been explicitly
5938 * set using clutter_actor_set_clip().
5942 obj_props[PROP_CLIP_TO_ALLOCATION] =
5943 g_param_spec_boolean ("clip-to-allocation",
5944 P_("Clip to Allocation"),
5945 P_("Sets the clip region to track the actor's allocation"),
5947 CLUTTER_PARAM_READWRITE);
5950 * ClutterActor:text-direction:
5952 * The direction of the text inside a #ClutterActor.
5956 obj_props[PROP_TEXT_DIRECTION] =
5957 g_param_spec_enum ("text-direction",
5958 P_("Text Direction"),
5959 P_("Direction of the text"),
5960 CLUTTER_TYPE_TEXT_DIRECTION,
5961 CLUTTER_TEXT_DIRECTION_LTR,
5962 CLUTTER_PARAM_READWRITE);
5965 * ClutterActor:has-pointer:
5967 * Whether the actor contains the pointer of a #ClutterInputDevice
5972 obj_props[PROP_HAS_POINTER] =
5973 g_param_spec_boolean ("has-pointer",
5975 P_("Whether the actor contains the pointer of an input device"),
5977 CLUTTER_PARAM_READABLE);
5980 * ClutterActor:actions:
5982 * Adds a #ClutterAction to the actor
5986 obj_props[PROP_ACTIONS] =
5987 g_param_spec_object ("actions",
5989 P_("Adds an action to the actor"),
5990 CLUTTER_TYPE_ACTION,
5991 CLUTTER_PARAM_WRITABLE);
5994 * ClutterActor:constraints:
5996 * Adds a #ClutterConstraint to the actor
6000 obj_props[PROP_CONSTRAINTS] =
6001 g_param_spec_object ("constraints",
6003 P_("Adds a constraint to the actor"),
6004 CLUTTER_TYPE_CONSTRAINT,
6005 CLUTTER_PARAM_WRITABLE);
6008 * ClutterActor:effect:
6010 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6014 obj_props[PROP_EFFECT] =
6015 g_param_spec_object ("effect",
6017 P_("Add an effect to be applied on the actor"),
6018 CLUTTER_TYPE_EFFECT,
6019 CLUTTER_PARAM_WRITABLE);
6022 * ClutterActor:layout-manager:
6024 * A delegate object for controlling the layout of the children of
6029 obj_props[PROP_LAYOUT_MANAGER] =
6030 g_param_spec_object ("layout-manager",
6031 P_("Layout Manager"),
6032 P_("The object controlling the layout of an actor's children"),
6033 CLUTTER_TYPE_LAYOUT_MANAGER,
6034 CLUTTER_PARAM_READWRITE);
6038 * ClutterActor:x-align:
6040 * The alignment of an actor on the X axis, if the actor has been given
6041 * extra space for its allocation.
6045 obj_props[PROP_X_ALIGN] =
6046 g_param_spec_enum ("x-align",
6048 P_("The alignment of the actor on the X axis within its allocation"),
6049 CLUTTER_TYPE_ACTOR_ALIGN,
6050 CLUTTER_ACTOR_ALIGN_FILL,
6051 CLUTTER_PARAM_READWRITE);
6054 * ClutterActor:y-align:
6056 * The alignment of an actor on the Y axis, if the actor has been given
6057 * extra space for its allocation.
6061 obj_props[PROP_Y_ALIGN] =
6062 g_param_spec_enum ("y-align",
6064 P_("The alignment of the actor on the Y axis within its allocation"),
6065 CLUTTER_TYPE_ACTOR_ALIGN,
6066 CLUTTER_ACTOR_ALIGN_FILL,
6067 CLUTTER_PARAM_READWRITE);
6070 * ClutterActor:margin-top:
6072 * The margin (in pixels) from the top of the actor.
6074 * This property adds a margin to the actor's preferred size; the margin
6075 * will be automatically taken into account when allocating the actor.
6079 obj_props[PROP_MARGIN_TOP] =
6080 g_param_spec_float ("margin-top",
6082 P_("Extra space at the top"),
6085 CLUTTER_PARAM_READWRITE);
6088 * ClutterActor:margin-bottom:
6090 * The margin (in pixels) from the bottom of the actor.
6092 * This property adds a margin to the actor's preferred size; the margin
6093 * will be automatically taken into account when allocating the actor.
6097 obj_props[PROP_MARGIN_BOTTOM] =
6098 g_param_spec_float ("margin-bottom",
6099 P_("Margin Bottom"),
6100 P_("Extra space at the bottom"),
6103 CLUTTER_PARAM_READWRITE);
6106 * ClutterActor:margin-left:
6108 * The margin (in pixels) from the left of the actor.
6110 * This property adds a margin to the actor's preferred size; the margin
6111 * will be automatically taken into account when allocating the actor.
6115 obj_props[PROP_MARGIN_LEFT] =
6116 g_param_spec_float ("margin-left",
6118 P_("Extra space at the left"),
6121 CLUTTER_PARAM_READWRITE);
6124 * ClutterActor:margin-right:
6126 * The margin (in pixels) from the right of the actor.
6128 * This property adds a margin to the actor's preferred size; the margin
6129 * will be automatically taken into account when allocating the actor.
6133 obj_props[PROP_MARGIN_RIGHT] =
6134 g_param_spec_float ("margin-right",
6136 P_("Extra space at the right"),
6139 CLUTTER_PARAM_READWRITE);
6142 * ClutterActor:background-color-set:
6144 * Whether the #ClutterActor:background-color property has been set.
6148 obj_props[PROP_BACKGROUND_COLOR_SET] =
6149 g_param_spec_boolean ("background-color-set",
6150 P_("Background Color Set"),
6151 P_("Whether the background color is set"),
6153 CLUTTER_PARAM_READABLE);
6156 * ClutterActor:background-color:
6158 * Paints a solid fill of the actor's allocation using the specified
6161 * The #ClutterActor:background-color property is animatable.
6165 obj_props[PROP_BACKGROUND_COLOR] =
6166 clutter_param_spec_color ("background-color",
6167 P_("Background color"),
6168 P_("The actor's background color"),
6169 CLUTTER_COLOR_Transparent,
6171 G_PARAM_STATIC_STRINGS |
6172 CLUTTER_PARAM_ANIMATABLE);
6175 * ClutterActor:first-child:
6177 * The actor's first child.
6181 obj_props[PROP_FIRST_CHILD] =
6182 g_param_spec_object ("first-child",
6184 P_("The actor's first child"),
6186 CLUTTER_PARAM_READABLE);
6189 * ClutterActor:last-child:
6191 * The actor's last child.
6195 obj_props[PROP_LAST_CHILD] =
6196 g_param_spec_object ("last-child",
6198 P_("The actor's last child"),
6200 CLUTTER_PARAM_READABLE);
6203 * ClutterActor:content:
6205 * The #ClutterContent implementation that controls the content
6210 obj_props[PROP_CONTENT] =
6211 g_param_spec_object ("content",
6213 P_("Delegate object for painting the actor's content"),
6214 CLUTTER_TYPE_CONTENT,
6215 CLUTTER_PARAM_READWRITE);
6218 * ClutterActor:content-gravity:
6220 * The alignment that should be honoured by the #ClutterContent
6221 * set with the #ClutterActor:content property.
6223 * Changing the value of this property will change the bounding box of
6224 * the content; you can use the #ClutterActor:content-box property to
6225 * get the position and size of the content within the actor's
6228 * This property is meaningful only for #ClutterContent implementations
6229 * that have a preferred size, and if the preferred size is smaller than
6230 * the actor's allocation.
6234 obj_props[PROP_CONTENT_GRAVITY] =
6235 g_param_spec_enum ("content-gravity",
6236 P_("Content Gravity"),
6237 P_("Alignment of the actor's content"),
6238 CLUTTER_TYPE_CONTENT_GRAVITY,
6239 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6240 CLUTTER_PARAM_READWRITE);
6243 * ClutterActor:content-box:
6245 * The bounding box for the #ClutterContent used by the actor.
6247 * The value of this property is controlled by the #ClutterActor:allocation
6248 * and #ClutterActor:content-gravity properties of #ClutterActor.
6250 * The bounding box for the content is guaranteed to never exceed the
6251 * allocation's of the actor.
6255 obj_props[PROP_CONTENT_BOX] =
6256 g_param_spec_boxed ("content-box",
6258 P_("The bounding box of the actor's content"),
6259 CLUTTER_TYPE_ACTOR_BOX,
6260 CLUTTER_PARAM_READABLE);
6262 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6265 * ClutterActor::destroy:
6266 * @actor: the #ClutterActor which emitted the signal
6268 * The ::destroy signal notifies that all references held on the
6269 * actor which emitted it should be released.
6271 * The ::destroy signal should be used by all holders of a reference
6274 * This signal might result in the finalization of the #ClutterActor
6275 * if all references are released.
6277 * Composite actors and actors implementing the #ClutterContainer
6278 * interface should override the default implementation of the
6279 * class handler of this signal and call clutter_actor_destroy() on
6280 * their children. When overriding the default class handler, it is
6281 * required to chain up to the parent's implementation.
6285 actor_signals[DESTROY] =
6286 g_signal_new (I_("destroy"),
6287 G_TYPE_FROM_CLASS (object_class),
6288 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6289 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6291 _clutter_marshal_VOID__VOID,
6294 * ClutterActor::show:
6295 * @actor: the object which received the signal
6297 * The ::show signal is emitted when an actor is visible and
6298 * rendered on the stage.
6302 actor_signals[SHOW] =
6303 g_signal_new (I_("show"),
6304 G_TYPE_FROM_CLASS (object_class),
6306 G_STRUCT_OFFSET (ClutterActorClass, show),
6308 _clutter_marshal_VOID__VOID,
6311 * ClutterActor::hide:
6312 * @actor: the object which received the signal
6314 * The ::hide signal is emitted when an actor is no longer rendered
6319 actor_signals[HIDE] =
6320 g_signal_new (I_("hide"),
6321 G_TYPE_FROM_CLASS (object_class),
6323 G_STRUCT_OFFSET (ClutterActorClass, hide),
6325 _clutter_marshal_VOID__VOID,
6328 * ClutterActor::parent-set:
6329 * @actor: the object which received the signal
6330 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6332 * This signal is emitted when the parent of the actor changes.
6336 actor_signals[PARENT_SET] =
6337 g_signal_new (I_("parent-set"),
6338 G_TYPE_FROM_CLASS (object_class),
6340 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6342 _clutter_marshal_VOID__OBJECT,
6344 CLUTTER_TYPE_ACTOR);
6347 * ClutterActor::queue-redraw:
6348 * @actor: the actor we're bubbling the redraw request through
6349 * @origin: the actor which initiated the redraw request
6351 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6352 * is called on @origin.
6354 * The default implementation for #ClutterActor chains up to the
6355 * parent actor and queues a redraw on the parent, thus "bubbling"
6356 * the redraw queue up through the actor graph. The default
6357 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6358 * in a main loop idle handler.
6360 * Note that the @origin actor may be the stage, or a container; it
6361 * does not have to be a leaf node in the actor graph.
6363 * Toolkits embedding a #ClutterStage which require a redraw and
6364 * relayout cycle can stop the emission of this signal using the
6365 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6370 * on_redraw_complete (gpointer data)
6372 * ClutterStage *stage = data;
6374 * /* execute the Clutter drawing pipeline */
6375 * clutter_stage_ensure_redraw (stage);
6379 * on_stage_queue_redraw (ClutterStage *stage)
6381 * /* this prevents the default handler to run */
6382 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6384 * /* queue a redraw with the host toolkit and call
6385 * * a function when the redraw has been completed
6387 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6391 * <note><para>This signal is emitted before the Clutter paint
6392 * pipeline is executed. If you want to know when the pipeline has
6393 * been completed you should connect to the ::paint signal on the
6394 * Stage with g_signal_connect_after().</para></note>
6398 actor_signals[QUEUE_REDRAW] =
6399 g_signal_new (I_("queue-redraw"),
6400 G_TYPE_FROM_CLASS (object_class),
6403 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6405 _clutter_marshal_VOID__OBJECT,
6407 CLUTTER_TYPE_ACTOR);
6410 * ClutterActor::queue-relayout
6411 * @actor: the actor being queued for relayout
6413 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6414 * is called on an actor.
6416 * The default implementation for #ClutterActor chains up to the
6417 * parent actor and queues a relayout on the parent, thus "bubbling"
6418 * the relayout queue up through the actor graph.
6420 * The main purpose of this signal is to allow relayout to be propagated
6421 * properly in the procense of #ClutterClone actors. Applications will
6422 * not normally need to connect to this signal.
6426 actor_signals[QUEUE_RELAYOUT] =
6427 g_signal_new (I_("queue-relayout"),
6428 G_TYPE_FROM_CLASS (object_class),
6431 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6433 _clutter_marshal_VOID__VOID,
6437 * ClutterActor::event:
6438 * @actor: the actor which received the event
6439 * @event: a #ClutterEvent
6441 * The ::event signal is emitted each time an event is received
6442 * by the @actor. This signal will be emitted on every actor,
6443 * following the hierarchy chain, until it reaches the top-level
6444 * container (the #ClutterStage).
6446 * Return value: %TRUE if the event has been handled by the actor,
6447 * or %FALSE to continue the emission.
6451 actor_signals[EVENT] =
6452 g_signal_new (I_("event"),
6453 G_TYPE_FROM_CLASS (object_class),
6455 G_STRUCT_OFFSET (ClutterActorClass, event),
6456 _clutter_boolean_handled_accumulator, NULL,
6457 _clutter_marshal_BOOLEAN__BOXED,
6459 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6461 * ClutterActor::button-press-event:
6462 * @actor: the actor which received the event
6463 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6465 * The ::button-press-event signal is emitted each time a mouse button
6466 * is pressed on @actor.
6468 * Return value: %TRUE if the event has been handled by the actor,
6469 * or %FALSE to continue the emission.
6473 actor_signals[BUTTON_PRESS_EVENT] =
6474 g_signal_new (I_("button-press-event"),
6475 G_TYPE_FROM_CLASS (object_class),
6477 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6478 _clutter_boolean_handled_accumulator, NULL,
6479 _clutter_marshal_BOOLEAN__BOXED,
6481 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6483 * ClutterActor::button-release-event:
6484 * @actor: the actor which received the event
6485 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6487 * The ::button-release-event signal is emitted each time a mouse button
6488 * is released on @actor.
6490 * Return value: %TRUE if the event has been handled by the actor,
6491 * or %FALSE to continue the emission.
6495 actor_signals[BUTTON_RELEASE_EVENT] =
6496 g_signal_new (I_("button-release-event"),
6497 G_TYPE_FROM_CLASS (object_class),
6499 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6500 _clutter_boolean_handled_accumulator, NULL,
6501 _clutter_marshal_BOOLEAN__BOXED,
6503 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6505 * ClutterActor::scroll-event:
6506 * @actor: the actor which received the event
6507 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6509 * The ::scroll-event signal is emitted each time the mouse is
6510 * scrolled on @actor
6512 * Return value: %TRUE if the event has been handled by the actor,
6513 * or %FALSE to continue the emission.
6517 actor_signals[SCROLL_EVENT] =
6518 g_signal_new (I_("scroll-event"),
6519 G_TYPE_FROM_CLASS (object_class),
6521 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6522 _clutter_boolean_handled_accumulator, NULL,
6523 _clutter_marshal_BOOLEAN__BOXED,
6525 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6527 * ClutterActor::key-press-event:
6528 * @actor: the actor which received the event
6529 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6531 * The ::key-press-event signal is emitted each time a keyboard button
6532 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6534 * Return value: %TRUE if the event has been handled by the actor,
6535 * or %FALSE to continue the emission.
6539 actor_signals[KEY_PRESS_EVENT] =
6540 g_signal_new (I_("key-press-event"),
6541 G_TYPE_FROM_CLASS (object_class),
6543 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6544 _clutter_boolean_handled_accumulator, NULL,
6545 _clutter_marshal_BOOLEAN__BOXED,
6547 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6549 * ClutterActor::key-release-event:
6550 * @actor: the actor which received the event
6551 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6553 * The ::key-release-event signal is emitted each time a keyboard button
6554 * is released while @actor has key focus (see
6555 * clutter_stage_set_key_focus()).
6557 * Return value: %TRUE if the event has been handled by the actor,
6558 * or %FALSE to continue the emission.
6562 actor_signals[KEY_RELEASE_EVENT] =
6563 g_signal_new (I_("key-release-event"),
6564 G_TYPE_FROM_CLASS (object_class),
6566 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6567 _clutter_boolean_handled_accumulator, NULL,
6568 _clutter_marshal_BOOLEAN__BOXED,
6570 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6572 * ClutterActor::motion-event:
6573 * @actor: the actor which received the event
6574 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6576 * The ::motion-event signal is emitted each time the mouse pointer is
6577 * moved over @actor.
6579 * Return value: %TRUE if the event has been handled by the actor,
6580 * or %FALSE to continue the emission.
6584 actor_signals[MOTION_EVENT] =
6585 g_signal_new (I_("motion-event"),
6586 G_TYPE_FROM_CLASS (object_class),
6588 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6589 _clutter_boolean_handled_accumulator, NULL,
6590 _clutter_marshal_BOOLEAN__BOXED,
6592 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6595 * ClutterActor::key-focus-in:
6596 * @actor: the actor which now has key focus
6598 * The ::key-focus-in signal is emitted when @actor receives key focus.
6602 actor_signals[KEY_FOCUS_IN] =
6603 g_signal_new (I_("key-focus-in"),
6604 G_TYPE_FROM_CLASS (object_class),
6606 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6608 _clutter_marshal_VOID__VOID,
6612 * ClutterActor::key-focus-out:
6613 * @actor: the actor which now has key focus
6615 * The ::key-focus-out signal is emitted when @actor loses key focus.
6619 actor_signals[KEY_FOCUS_OUT] =
6620 g_signal_new (I_("key-focus-out"),
6621 G_TYPE_FROM_CLASS (object_class),
6623 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6625 _clutter_marshal_VOID__VOID,
6629 * ClutterActor::enter-event:
6630 * @actor: the actor which the pointer has entered.
6631 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6633 * The ::enter-event signal is emitted when the pointer enters the @actor
6635 * Return value: %TRUE if the event has been handled by the actor,
6636 * or %FALSE to continue the emission.
6640 actor_signals[ENTER_EVENT] =
6641 g_signal_new (I_("enter-event"),
6642 G_TYPE_FROM_CLASS (object_class),
6644 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6645 _clutter_boolean_handled_accumulator, NULL,
6646 _clutter_marshal_BOOLEAN__BOXED,
6648 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6651 * ClutterActor::leave-event:
6652 * @actor: the actor which the pointer has left
6653 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6655 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6657 * Return value: %TRUE if the event has been handled by the actor,
6658 * or %FALSE to continue the emission.
6662 actor_signals[LEAVE_EVENT] =
6663 g_signal_new (I_("leave-event"),
6664 G_TYPE_FROM_CLASS (object_class),
6666 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6667 _clutter_boolean_handled_accumulator, NULL,
6668 _clutter_marshal_BOOLEAN__BOXED,
6670 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6673 * ClutterActor::captured-event:
6674 * @actor: the actor which received the signal
6675 * @event: a #ClutterEvent
6677 * The ::captured-event signal is emitted when an event is captured
6678 * by Clutter. This signal will be emitted starting from the top-level
6679 * container (the #ClutterStage) to the actor which received the event
6680 * going down the hierarchy. This signal can be used to intercept every
6681 * event before the specialized events (like
6682 * ClutterActor::button-press-event or ::key-released-event) are
6685 * Return value: %TRUE if the event has been handled by the actor,
6686 * or %FALSE to continue the emission.
6690 actor_signals[CAPTURED_EVENT] =
6691 g_signal_new (I_("captured-event"),
6692 G_TYPE_FROM_CLASS (object_class),
6694 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6695 _clutter_boolean_handled_accumulator, NULL,
6696 _clutter_marshal_BOOLEAN__BOXED,
6698 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6701 * ClutterActor::paint:
6702 * @actor: the #ClutterActor that received the signal
6704 * The ::paint signal is emitted each time an actor is being painted.
6706 * Subclasses of #ClutterActor should override the class signal handler
6707 * and paint themselves in that function.
6709 * It is possible to connect a handler to the ::paint signal in order
6710 * to set up some custom aspect of a paint.
6714 actor_signals[PAINT] =
6715 g_signal_new (I_("paint"),
6716 G_TYPE_FROM_CLASS (object_class),
6719 G_STRUCT_OFFSET (ClutterActorClass, paint),
6721 _clutter_marshal_VOID__VOID,
6724 * ClutterActor::realize:
6725 * @actor: the #ClutterActor that received the signal
6727 * The ::realize signal is emitted each time an actor is being
6732 actor_signals[REALIZE] =
6733 g_signal_new (I_("realize"),
6734 G_TYPE_FROM_CLASS (object_class),
6736 G_STRUCT_OFFSET (ClutterActorClass, realize),
6738 _clutter_marshal_VOID__VOID,
6741 * ClutterActor::unrealize:
6742 * @actor: the #ClutterActor that received the signal
6744 * The ::unrealize signal is emitted each time an actor is being
6749 actor_signals[UNREALIZE] =
6750 g_signal_new (I_("unrealize"),
6751 G_TYPE_FROM_CLASS (object_class),
6753 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6755 _clutter_marshal_VOID__VOID,
6759 * ClutterActor::pick:
6760 * @actor: the #ClutterActor that received the signal
6761 * @color: the #ClutterColor to be used when picking
6763 * The ::pick signal is emitted each time an actor is being painted
6764 * in "pick mode". The pick mode is used to identify the actor during
6765 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6766 * The actor should paint its shape using the passed @pick_color.
6768 * Subclasses of #ClutterActor should override the class signal handler
6769 * and paint themselves in that function.
6771 * It is possible to connect a handler to the ::pick signal in order
6772 * to set up some custom aspect of a paint in pick mode.
6776 actor_signals[PICK] =
6777 g_signal_new (I_("pick"),
6778 G_TYPE_FROM_CLASS (object_class),
6780 G_STRUCT_OFFSET (ClutterActorClass, pick),
6782 _clutter_marshal_VOID__BOXED,
6784 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6787 * ClutterActor::allocation-changed:
6788 * @actor: the #ClutterActor that emitted the signal
6789 * @box: a #ClutterActorBox with the new allocation
6790 * @flags: #ClutterAllocationFlags for the allocation
6792 * The ::allocation-changed signal is emitted when the
6793 * #ClutterActor:allocation property changes. Usually, application
6794 * code should just use the notifications for the :allocation property
6795 * but if you want to track the allocation flags as well, for instance
6796 * to know whether the absolute origin of @actor changed, then you might
6797 * want use this signal instead.
6801 actor_signals[ALLOCATION_CHANGED] =
6802 g_signal_new (I_("allocation-changed"),
6803 G_TYPE_FROM_CLASS (object_class),
6807 _clutter_marshal_VOID__BOXED_FLAGS,
6809 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6810 CLUTTER_TYPE_ALLOCATION_FLAGS);
6814 clutter_actor_init (ClutterActor *self)
6816 ClutterActorPrivate *priv;
6818 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6820 priv->id = _clutter_context_acquire_id (self);
6823 priv->opacity = 0xff;
6824 priv->show_on_set_parent = TRUE;
6826 priv->needs_width_request = TRUE;
6827 priv->needs_height_request = TRUE;
6828 priv->needs_allocation = TRUE;
6830 priv->cached_width_age = 1;
6831 priv->cached_height_age = 1;
6833 priv->opacity_override = -1;
6834 priv->enable_model_view_transform = TRUE;
6836 /* Initialize an empty paint volume to start with */
6837 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6838 priv->last_paint_volume_valid = TRUE;
6840 priv->transform_valid = FALSE;
6842 /* the default is to stretch the content, to match the
6843 * current behaviour of basically all actors. also, it's
6844 * the easiest thing to compute.
6846 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6850 * clutter_actor_new:
6852 * Creates a new #ClutterActor.
6854 * A newly created actor has a floating reference, which will be sunk
6855 * when it is added to another actor.
6857 * Return value: (transfer full): the newly created #ClutterActor
6862 clutter_actor_new (void)
6864 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6868 * clutter_actor_destroy:
6869 * @self: a #ClutterActor
6871 * Destroys an actor. When an actor is destroyed, it will break any
6872 * references it holds to other objects. If the actor is inside a
6873 * container, the actor will be removed.
6875 * When you destroy a container, its children will be destroyed as well.
6877 * Note: you cannot destroy the #ClutterStage returned by
6878 * clutter_stage_get_default().
6881 clutter_actor_destroy (ClutterActor *self)
6883 g_return_if_fail (CLUTTER_IS_ACTOR (self));
6885 g_object_ref (self);
6887 /* avoid recursion while destroying */
6888 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6890 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6892 g_object_run_dispose (G_OBJECT (self));
6894 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6897 g_object_unref (self);
6901 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6902 ClutterPaintVolume *clip)
6904 ClutterActorPrivate *priv = self->priv;
6905 ClutterPaintVolume *pv;
6908 /* Remove queue entry early in the process, otherwise a new
6909 queue_redraw() during signal handling could put back this
6910 object in the stage redraw list (but the entry is freed as
6911 soon as we return from this function, causing a segfault
6914 priv->queue_redraw_entry = NULL;
6916 /* If we've been explicitly passed a clip volume then there's
6917 * nothing more to calculate, but otherwise the only thing we know
6918 * is that the change is constrained to the given actor.
6920 * The idea is that if we know the paint volume for where the actor
6921 * was last drawn (in eye coordinates) and we also have the paint
6922 * volume for where it will be drawn next (in actor coordinates)
6923 * then if we queue a redraw for both these volumes that will cover
6924 * everything that needs to be redrawn to clear the old view and
6925 * show the latest view of the actor.
6927 * Don't clip this redraw if we don't know what position we had for
6928 * the previous redraw since we don't know where to set the clip so
6929 * it will clear the actor as it is currently.
6933 _clutter_actor_set_queue_redraw_clip (self, clip);
6936 else if (G_LIKELY (priv->last_paint_volume_valid))
6938 pv = _clutter_actor_get_paint_volume_mutable (self);
6941 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6943 /* make sure we redraw the actors old position... */
6944 _clutter_actor_set_queue_redraw_clip (stage,
6945 &priv->last_paint_volume);
6946 _clutter_actor_signal_queue_redraw (stage, stage);
6947 _clutter_actor_set_queue_redraw_clip (stage, NULL);
6949 /* XXX: Ideally the redraw signal would take a clip volume
6950 * argument, but that would be an ABI break. Until we can
6951 * break the ABI we pass the argument out-of-band
6954 /* setup the clip for the actors new position... */
6955 _clutter_actor_set_queue_redraw_clip (self, pv);
6964 _clutter_actor_signal_queue_redraw (self, self);
6966 /* Just in case anyone is manually firing redraw signals without
6967 * using the public queue_redraw() API we are careful to ensure that
6968 * our out-of-band clip member is cleared before returning...
6970 * Note: A NULL clip denotes a full-stage, un-clipped redraw
6972 if (G_LIKELY (clipped))
6973 _clutter_actor_set_queue_redraw_clip (self, NULL);
6977 _clutter_actor_get_allocation_clip (ClutterActor *self,
6978 ClutterActorBox *clip)
6980 ClutterActorBox allocation;
6982 /* XXX: we don't care if we get an out of date allocation here
6983 * because clutter_actor_queue_redraw_with_clip knows to ignore
6984 * the clip if the actor's allocation is invalid.
6986 * This is noted because clutter_actor_get_allocation_box does some
6987 * unnecessary work to support buggy code with a comment suggesting
6988 * that it could be changed later which would be good for this use
6991 clutter_actor_get_allocation_box (self, &allocation);
6993 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6994 * actor's own coordinate space but the allocation is in parent
6998 clip->x2 = allocation.x2 - allocation.x1;
6999 clip->y2 = allocation.y2 - allocation.y1;
7003 _clutter_actor_queue_redraw_full (ClutterActor *self,
7004 ClutterRedrawFlags flags,
7005 ClutterPaintVolume *volume,
7006 ClutterEffect *effect)
7008 ClutterActorPrivate *priv = self->priv;
7009 ClutterPaintVolume allocation_pv;
7010 ClutterPaintVolume *pv;
7011 gboolean should_free_pv;
7012 ClutterActor *stage;
7014 /* Here's an outline of the actor queue redraw mechanism:
7016 * The process starts in one of the following two functions which
7017 * are wrappers for this function:
7018 * clutter_actor_queue_redraw
7019 * _clutter_actor_queue_redraw_with_clip
7021 * additionally, an effect can queue a redraw by wrapping this
7022 * function in clutter_effect_queue_rerun
7024 * This functions queues an entry in a list associated with the
7025 * stage which is a list of actors that queued a redraw while
7026 * updating the timelines, performing layouting and processing other
7027 * mainloop sources before the next paint starts.
7029 * We aim to minimize the processing done at this point because
7030 * there is a good chance other events will happen while updating
7031 * the scenegraph that would invalidate any expensive work we might
7032 * otherwise try to do here. For example we don't try and resolve
7033 * the screen space bounding box of an actor at this stage so as to
7034 * minimize how much of the screen redraw because it's possible
7035 * something else will happen which will force a full redraw anyway.
7037 * When all updates are complete and we come to paint the stage then
7038 * we iterate this list and actually emit the "queue-redraw" signals
7039 * for each of the listed actors which will bubble up to the stage
7040 * for each actor and at that point we will transform the actors
7041 * paint volume into screen coordinates to determine the clip region
7042 * for what needs to be redrawn in the next paint.
7044 * Besides minimizing redundant work another reason for this
7045 * deferred design is that it's more likely we will be able to
7046 * determine the paint volume of an actor once we've finished
7047 * updating the scenegraph because its allocation should be up to
7048 * date. NB: If we can't determine an actors paint volume then we
7049 * can't automatically queue a clipped redraw which can make a big
7050 * difference to performance.
7052 * So the control flow goes like this:
7053 * One of clutter_actor_queue_redraw,
7054 * _clutter_actor_queue_redraw_with_clip
7055 * or clutter_effect_queue_rerun
7057 * then control moves to:
7058 * _clutter_stage_queue_actor_redraw
7060 * later during _clutter_stage_do_update, once relayouting is done
7061 * and the scenegraph has been updated we will call:
7062 * _clutter_stage_finish_queue_redraws
7064 * _clutter_stage_finish_queue_redraws will call
7065 * _clutter_actor_finish_queue_redraw for each listed actor.
7066 * Note: actors *are* allowed to queue further redraws during this
7067 * process (considering clone actors or texture_new_from_actor which
7068 * respond to their source queueing a redraw by queuing a redraw
7069 * themselves). We repeat the process until the list is empty.
7071 * This will result in the "queue-redraw" signal being fired for
7072 * each actor which will pass control to the default signal handler:
7073 * clutter_actor_real_queue_redraw
7075 * This will bubble up to the stages handler:
7076 * clutter_stage_real_queue_redraw
7078 * clutter_stage_real_queue_redraw will transform the actors paint
7079 * volume into screen space and add it as a clip region for the next
7083 /* ignore queueing a redraw for actors being destroyed */
7084 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7087 stage = _clutter_actor_get_stage_internal (self);
7089 /* Ignore queueing a redraw for actors not descended from a stage */
7093 /* ignore queueing a redraw on stages that are being destroyed */
7094 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7097 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7099 ClutterActorBox allocation_clip;
7100 ClutterVertex origin;
7102 /* If the actor doesn't have a valid allocation then we will
7103 * queue a full stage redraw. */
7104 if (priv->needs_allocation)
7106 /* NB: NULL denotes an undefined clip which will result in a
7108 _clutter_actor_set_queue_redraw_clip (self, NULL);
7109 _clutter_actor_signal_queue_redraw (self, self);
7113 _clutter_paint_volume_init_static (&allocation_pv, self);
7114 pv = &allocation_pv;
7116 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7118 origin.x = allocation_clip.x1;
7119 origin.y = allocation_clip.y1;
7121 clutter_paint_volume_set_origin (pv, &origin);
7122 clutter_paint_volume_set_width (pv,
7123 allocation_clip.x2 - allocation_clip.x1);
7124 clutter_paint_volume_set_height (pv,
7125 allocation_clip.y2 -
7126 allocation_clip.y1);
7127 should_free_pv = TRUE;
7132 should_free_pv = FALSE;
7135 self->priv->queue_redraw_entry =
7136 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7137 priv->queue_redraw_entry,
7142 clutter_paint_volume_free (pv);
7144 /* If this is the first redraw queued then we can directly use the
7146 if (!priv->is_dirty)
7147 priv->effect_to_redraw = effect;
7148 /* Otherwise we need to merge it with the existing effect parameter */
7149 else if (effect != NULL)
7151 /* If there's already an effect then we need to use whichever is
7152 later in the chain of actors. Otherwise a full redraw has
7153 already been queued on the actor so we need to ignore the
7155 if (priv->effect_to_redraw != NULL)
7157 if (priv->effects == NULL)
7158 g_warning ("Redraw queued with an effect that is "
7159 "not applied to the actor");
7164 for (l = _clutter_meta_group_peek_metas (priv->effects);
7168 if (l->data == priv->effect_to_redraw ||
7170 priv->effect_to_redraw = l->data;
7177 /* If no effect is specified then we need to redraw the whole
7179 priv->effect_to_redraw = NULL;
7182 priv->is_dirty = TRUE;
7186 * clutter_actor_queue_redraw:
7187 * @self: A #ClutterActor
7189 * Queues up a redraw of an actor and any children. The redraw occurs
7190 * once the main loop becomes idle (after the current batch of events
7191 * has been processed, roughly).
7193 * Applications rarely need to call this, as redraws are handled
7194 * automatically by modification functions.
7196 * This function will not do anything if @self is not visible, or
7197 * if the actor is inside an invisible part of the scenegraph.
7199 * Also be aware that painting is a NOP for actors with an opacity of
7202 * When you are implementing a custom actor you must queue a redraw
7203 * whenever some private state changes that will affect painting or
7204 * picking of your actor.
7207 clutter_actor_queue_redraw (ClutterActor *self)
7209 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7211 _clutter_actor_queue_redraw_full (self,
7213 NULL, /* clip volume */
7218 * _clutter_actor_queue_redraw_with_clip:
7219 * @self: A #ClutterActor
7220 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7221 * this queue redraw.
7222 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7223 * redrawn or %NULL if you are just using a @flag to state your
7226 * Queues up a clipped redraw of an actor and any children. The redraw
7227 * occurs once the main loop becomes idle (after the current batch of
7228 * events has been processed, roughly).
7230 * If no flags are given the clip volume is defined by @volume
7231 * specified in actor coordinates and tells Clutter that only content
7232 * within this volume has been changed so Clutter can optionally
7233 * optimize the redraw.
7235 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7236 * should be %NULL and this tells Clutter to use the actor's current
7237 * allocation as a clip box. This flag can only be used for 2D actors,
7238 * because any actor with depth may be projected outside its
7241 * Applications rarely need to call this, as redraws are handled
7242 * automatically by modification functions.
7244 * This function will not do anything if @self is not visible, or if
7245 * the actor is inside an invisible part of the scenegraph.
7247 * Also be aware that painting is a NOP for actors with an opacity of
7250 * When you are implementing a custom actor you must queue a redraw
7251 * whenever some private state changes that will affect painting or
7252 * picking of your actor.
7255 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7256 ClutterRedrawFlags flags,
7257 ClutterPaintVolume *volume)
7259 _clutter_actor_queue_redraw_full (self,
7261 volume, /* clip volume */
7266 _clutter_actor_queue_only_relayout (ClutterActor *self)
7268 ClutterActorPrivate *priv = self->priv;
7270 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7273 if (priv->needs_width_request &&
7274 priv->needs_height_request &&
7275 priv->needs_allocation)
7276 return; /* save some cpu cycles */
7278 #if CLUTTER_ENABLE_DEBUG
7279 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7281 g_warning ("The actor '%s' is currently inside an allocation "
7282 "cycle; calling clutter_actor_queue_relayout() is "
7284 _clutter_actor_get_debug_name (self));
7286 #endif /* CLUTTER_ENABLE_DEBUG */
7288 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7292 * clutter_actor_queue_redraw_with_clip:
7293 * @self: a #ClutterActor
7294 * @clip: (allow-none): a rectangular clip region, or %NULL
7296 * Queues a redraw on @self limited to a specific, actor-relative
7299 * If @clip is %NULL this function is equivalent to
7300 * clutter_actor_queue_redraw().
7305 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7306 const cairo_rectangle_int_t *clip)
7308 ClutterPaintVolume volume;
7309 ClutterVertex origin;
7311 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7315 clutter_actor_queue_redraw (self);
7319 _clutter_paint_volume_init_static (&volume, self);
7325 clutter_paint_volume_set_origin (&volume, &origin);
7326 clutter_paint_volume_set_width (&volume, clip->width);
7327 clutter_paint_volume_set_height (&volume, clip->height);
7329 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7331 clutter_paint_volume_free (&volume);
7335 * clutter_actor_queue_relayout:
7336 * @self: A #ClutterActor
7338 * Indicates that the actor's size request or other layout-affecting
7339 * properties may have changed. This function is used inside #ClutterActor
7340 * subclass implementations, not by applications directly.
7342 * Queueing a new layout automatically queues a redraw as well.
7347 clutter_actor_queue_relayout (ClutterActor *self)
7349 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7351 _clutter_actor_queue_only_relayout (self);
7352 clutter_actor_queue_redraw (self);
7356 * clutter_actor_get_preferred_size:
7357 * @self: a #ClutterActor
7358 * @min_width_p: (out) (allow-none): return location for the minimum
7360 * @min_height_p: (out) (allow-none): return location for the minimum
7362 * @natural_width_p: (out) (allow-none): return location for the natural
7364 * @natural_height_p: (out) (allow-none): return location for the natural
7367 * Computes the preferred minimum and natural size of an actor, taking into
7368 * account the actor's geometry management (either height-for-width
7369 * or width-for-height).
7371 * The width and height used to compute the preferred height and preferred
7372 * width are the actor's natural ones.
7374 * If you need to control the height for the preferred width, or the width for
7375 * the preferred height, you should use clutter_actor_get_preferred_width()
7376 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7377 * geometry management using the #ClutterActor:request-mode property.
7382 clutter_actor_get_preferred_size (ClutterActor *self,
7383 gfloat *min_width_p,
7384 gfloat *min_height_p,
7385 gfloat *natural_width_p,
7386 gfloat *natural_height_p)
7388 ClutterActorPrivate *priv;
7389 gfloat min_width, min_height;
7390 gfloat natural_width, natural_height;
7392 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7396 min_width = min_height = 0;
7397 natural_width = natural_height = 0;
7399 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7401 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7402 clutter_actor_get_preferred_width (self, -1,
7405 clutter_actor_get_preferred_height (self, natural_width,
7411 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7412 clutter_actor_get_preferred_height (self, -1,
7415 clutter_actor_get_preferred_width (self, natural_height,
7421 *min_width_p = min_width;
7424 *min_height_p = min_height;
7426 if (natural_width_p)
7427 *natural_width_p = natural_width;
7429 if (natural_height_p)
7430 *natural_height_p = natural_height;
7435 * @align: a #ClutterActorAlign
7436 * @direction: a #ClutterTextDirection
7438 * Retrieves the correct alignment depending on the text direction
7440 * Return value: the effective alignment
7442 static ClutterActorAlign
7443 effective_align (ClutterActorAlign align,
7444 ClutterTextDirection direction)
7446 ClutterActorAlign res;
7450 case CLUTTER_ACTOR_ALIGN_START:
7451 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7452 ? CLUTTER_ACTOR_ALIGN_END
7453 : CLUTTER_ACTOR_ALIGN_START;
7456 case CLUTTER_ACTOR_ALIGN_END:
7457 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7458 ? CLUTTER_ACTOR_ALIGN_START
7459 : CLUTTER_ACTOR_ALIGN_END;
7471 adjust_for_margin (float margin_start,
7473 float *minimum_size,
7474 float *natural_size,
7475 float *allocated_start,
7476 float *allocated_end)
7478 *minimum_size -= (margin_start + margin_end);
7479 *natural_size -= (margin_start + margin_end);
7480 *allocated_start += margin_start;
7481 *allocated_end -= margin_end;
7485 adjust_for_alignment (ClutterActorAlign alignment,
7487 float *allocated_start,
7488 float *allocated_end)
7490 float allocated_size = *allocated_end - *allocated_start;
7494 case CLUTTER_ACTOR_ALIGN_FILL:
7498 case CLUTTER_ACTOR_ALIGN_START:
7500 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7503 case CLUTTER_ACTOR_ALIGN_END:
7504 if (allocated_size > natural_size)
7506 *allocated_start += (allocated_size - natural_size);
7507 *allocated_end = *allocated_start + natural_size;
7511 case CLUTTER_ACTOR_ALIGN_CENTER:
7512 if (allocated_size > natural_size)
7514 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7515 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7522 * clutter_actor_adjust_width:
7523 * @self: a #ClutterActor
7524 * @minimum_width: (inout): the actor's preferred minimum width, which
7525 * will be adjusted depending on the margin
7526 * @natural_width: (inout): the actor's preferred natural width, which
7527 * will be adjusted depending on the margin
7528 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7529 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7531 * Adjusts the preferred and allocated position and size of an actor,
7532 * depending on the margin and alignment properties.
7535 clutter_actor_adjust_width (ClutterActor *self,
7536 gfloat *minimum_width,
7537 gfloat *natural_width,
7538 gfloat *adjusted_x1,
7539 gfloat *adjusted_x2)
7541 ClutterTextDirection text_dir;
7542 const ClutterLayoutInfo *info;
7544 info = _clutter_actor_get_layout_info_or_defaults (self);
7545 text_dir = clutter_actor_get_text_direction (self);
7547 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7549 /* this will tweak natural_width to remove the margin, so that
7550 * adjust_for_alignment() will use the correct size
7552 adjust_for_margin (info->margin.left, info->margin.right,
7553 minimum_width, natural_width,
7554 adjusted_x1, adjusted_x2);
7556 adjust_for_alignment (effective_align (info->x_align, text_dir),
7558 adjusted_x1, adjusted_x2);
7562 * clutter_actor_adjust_height:
7563 * @self: a #ClutterActor
7564 * @minimum_height: (inout): the actor's preferred minimum height, which
7565 * will be adjusted depending on the margin
7566 * @natural_height: (inout): the actor's preferred natural height, which
7567 * will be adjusted depending on the margin
7568 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7569 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7571 * Adjusts the preferred and allocated position and size of an actor,
7572 * depending on the margin and alignment properties.
7575 clutter_actor_adjust_height (ClutterActor *self,
7576 gfloat *minimum_height,
7577 gfloat *natural_height,
7578 gfloat *adjusted_y1,
7579 gfloat *adjusted_y2)
7581 const ClutterLayoutInfo *info;
7583 info = _clutter_actor_get_layout_info_or_defaults (self);
7585 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7587 /* this will tweak natural_height to remove the margin, so that
7588 * adjust_for_alignment() will use the correct size
7590 adjust_for_margin (info->margin.top, info->margin.bottom,
7591 minimum_height, natural_height,
7595 /* we don't use effective_align() here, because text direction
7596 * only affects the horizontal axis
7598 adjust_for_alignment (info->y_align,
7605 /* looks for a cached size request for this for_size. If not
7606 * found, returns the oldest entry so it can be overwritten */
7608 _clutter_actor_get_cached_size_request (gfloat for_size,
7609 SizeRequest *cached_size_requests,
7610 SizeRequest **result)
7614 *result = &cached_size_requests[0];
7616 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7620 sr = &cached_size_requests[i];
7623 sr->for_size == for_size)
7625 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7629 else if (sr->age < (*result)->age)
7635 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7641 * clutter_actor_get_preferred_width:
7642 * @self: A #ClutterActor
7643 * @for_height: available height when computing the preferred width,
7644 * or a negative value to indicate that no height is defined
7645 * @min_width_p: (out) (allow-none): return location for minimum width,
7647 * @natural_width_p: (out) (allow-none): return location for the natural
7650 * Computes the requested minimum and natural widths for an actor,
7651 * optionally depending on the specified height, or if they are
7652 * already computed, returns the cached values.
7654 * An actor may not get its request - depending on the layout
7655 * manager that's in effect.
7657 * A request should not incorporate the actor's scale or anchor point;
7658 * those transformations do not affect layout, only rendering.
7663 clutter_actor_get_preferred_width (ClutterActor *self,
7665 gfloat *min_width_p,
7666 gfloat *natural_width_p)
7668 float request_min_width, request_natural_width;
7669 SizeRequest *cached_size_request;
7670 const ClutterLayoutInfo *info;
7671 ClutterActorPrivate *priv;
7672 gboolean found_in_cache;
7674 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7678 info = _clutter_actor_get_layout_info_or_defaults (self);
7680 /* we shortcircuit the case of a fixed size set using set_width() */
7681 if (priv->min_width_set && priv->natural_width_set)
7683 if (min_width_p != NULL)
7684 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7686 if (natural_width_p != NULL)
7687 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7692 /* the remaining cases are:
7694 * - either min_width or natural_width have been set
7695 * - neither min_width or natural_width have been set
7697 * in both cases, we go through the cache (and through the actor in case
7698 * of cache misses) and determine the authoritative value depending on
7702 if (!priv->needs_width_request)
7705 _clutter_actor_get_cached_size_request (for_height,
7706 priv->width_requests,
7707 &cached_size_request);
7711 /* if the actor needs a width request we use the first slot */
7712 found_in_cache = FALSE;
7713 cached_size_request = &priv->width_requests[0];
7716 if (!found_in_cache)
7718 gfloat minimum_width, natural_width;
7719 ClutterActorClass *klass;
7721 minimum_width = natural_width = 0;
7723 /* adjust for the margin */
7724 if (for_height >= 0)
7726 for_height -= (info->margin.top + info->margin.bottom);
7731 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7733 klass = CLUTTER_ACTOR_GET_CLASS (self);
7734 klass->get_preferred_width (self, for_height,
7738 /* adjust for the margin */
7739 minimum_width += (info->margin.left + info->margin.right);
7740 natural_width += (info->margin.left + info->margin.right);
7742 /* Due to accumulated float errors, it's better not to warn
7743 * on this, but just fix it.
7745 if (natural_width < minimum_width)
7746 natural_width = minimum_width;
7748 cached_size_request->min_size = minimum_width;
7749 cached_size_request->natural_size = natural_width;
7750 cached_size_request->for_size = for_height;
7751 cached_size_request->age = priv->cached_width_age;
7753 priv->cached_width_age += 1;
7754 priv->needs_width_request = FALSE;
7757 if (!priv->min_width_set)
7758 request_min_width = cached_size_request->min_size;
7760 request_min_width = info->min_width;
7762 if (!priv->natural_width_set)
7763 request_natural_width = cached_size_request->natural_size;
7765 request_natural_width = info->natural_width;
7768 *min_width_p = request_min_width;
7770 if (natural_width_p)
7771 *natural_width_p = request_natural_width;
7775 * clutter_actor_get_preferred_height:
7776 * @self: A #ClutterActor
7777 * @for_width: available width to assume in computing desired height,
7778 * or a negative value to indicate that no width is defined
7779 * @min_height_p: (out) (allow-none): return location for minimum height,
7781 * @natural_height_p: (out) (allow-none): return location for natural
7784 * Computes the requested minimum and natural heights for an actor,
7785 * or if they are already computed, returns the cached values.
7787 * An actor may not get its request - depending on the layout
7788 * manager that's in effect.
7790 * A request should not incorporate the actor's scale or anchor point;
7791 * those transformations do not affect layout, only rendering.
7796 clutter_actor_get_preferred_height (ClutterActor *self,
7798 gfloat *min_height_p,
7799 gfloat *natural_height_p)
7801 float request_min_height, request_natural_height;
7802 SizeRequest *cached_size_request;
7803 const ClutterLayoutInfo *info;
7804 ClutterActorPrivate *priv;
7805 gboolean found_in_cache;
7807 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7811 info = _clutter_actor_get_layout_info_or_defaults (self);
7813 /* we shortcircuit the case of a fixed size set using set_height() */
7814 if (priv->min_height_set && priv->natural_height_set)
7816 if (min_height_p != NULL)
7817 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7819 if (natural_height_p != NULL)
7820 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7825 /* the remaining cases are:
7827 * - either min_height or natural_height have been set
7828 * - neither min_height or natural_height have been set
7830 * in both cases, we go through the cache (and through the actor in case
7831 * of cache misses) and determine the authoritative value depending on
7835 if (!priv->needs_height_request)
7838 _clutter_actor_get_cached_size_request (for_width,
7839 priv->height_requests,
7840 &cached_size_request);
7844 found_in_cache = FALSE;
7845 cached_size_request = &priv->height_requests[0];
7848 if (!found_in_cache)
7850 gfloat minimum_height, natural_height;
7851 ClutterActorClass *klass;
7853 minimum_height = natural_height = 0;
7855 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7857 /* adjust for margin */
7860 for_width -= (info->margin.left + info->margin.right);
7865 klass = CLUTTER_ACTOR_GET_CLASS (self);
7866 klass->get_preferred_height (self, for_width,
7870 /* adjust for margin */
7871 minimum_height += (info->margin.top + info->margin.bottom);
7872 natural_height += (info->margin.top + info->margin.bottom);
7874 /* Due to accumulated float errors, it's better not to warn
7875 * on this, but just fix it.
7877 if (natural_height < minimum_height)
7878 natural_height = minimum_height;
7880 cached_size_request->min_size = minimum_height;
7881 cached_size_request->natural_size = natural_height;
7882 cached_size_request->for_size = for_width;
7883 cached_size_request->age = priv->cached_height_age;
7885 priv->cached_height_age += 1;
7886 priv->needs_height_request = FALSE;
7889 if (!priv->min_height_set)
7890 request_min_height = cached_size_request->min_size;
7892 request_min_height = info->min_height;
7894 if (!priv->natural_height_set)
7895 request_natural_height = cached_size_request->natural_size;
7897 request_natural_height = info->natural_height;
7900 *min_height_p = request_min_height;
7902 if (natural_height_p)
7903 *natural_height_p = request_natural_height;
7907 * clutter_actor_get_allocation_box:
7908 * @self: A #ClutterActor
7909 * @box: (out): the function fills this in with the actor's allocation
7911 * Gets the layout box an actor has been assigned. The allocation can
7912 * only be assumed valid inside a paint() method; anywhere else, it
7913 * may be out-of-date.
7915 * An allocation does not incorporate the actor's scale or anchor point;
7916 * those transformations do not affect layout, only rendering.
7918 * <note>Do not call any of the clutter_actor_get_allocation_*() family
7919 * of functions inside the implementation of the get_preferred_width()
7920 * or get_preferred_height() virtual functions.</note>
7925 clutter_actor_get_allocation_box (ClutterActor *self,
7926 ClutterActorBox *box)
7928 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7930 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7931 * which limits calling get_allocation to inside paint() basically; or
7932 * we can 2) force a layout, which could be expensive if someone calls
7933 * get_allocation somewhere silly; or we can 3) just return the latest
7934 * value, allowing it to be out-of-date, and assume people know what
7937 * The least-surprises approach that keeps existing code working is
7938 * likely to be 2). People can end up doing some inefficient things,
7939 * though, and in general code that requires 2) is probably broken.
7942 /* this implements 2) */
7943 if (G_UNLIKELY (self->priv->needs_allocation))
7945 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7947 /* do not queue a relayout on an unparented actor */
7949 _clutter_stage_maybe_relayout (stage);
7952 /* commenting out the code above and just keeping this assigment
7955 *box = self->priv->allocation;
7959 * clutter_actor_get_allocation_geometry:
7960 * @self: A #ClutterActor
7961 * @geom: (out): allocation geometry in pixels
7963 * Gets the layout box an actor has been assigned. The allocation can
7964 * only be assumed valid inside a paint() method; anywhere else, it
7965 * may be out-of-date.
7967 * An allocation does not incorporate the actor's scale or anchor point;
7968 * those transformations do not affect layout, only rendering.
7970 * The returned rectangle is in pixels.
7975 clutter_actor_get_allocation_geometry (ClutterActor *self,
7976 ClutterGeometry *geom)
7978 ClutterActorBox box;
7980 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7981 g_return_if_fail (geom != NULL);
7983 clutter_actor_get_allocation_box (self, &box);
7985 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7986 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7987 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7988 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7992 clutter_actor_update_constraints (ClutterActor *self,
7993 ClutterActorBox *allocation)
7995 ClutterActorPrivate *priv = self->priv;
7996 const GList *constraints, *l;
7998 if (priv->constraints == NULL)
8001 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8002 for (l = constraints; l != NULL; l = l->next)
8004 ClutterConstraint *constraint = l->data;
8005 ClutterActorMeta *meta = l->data;
8007 if (clutter_actor_meta_get_enabled (meta))
8009 _clutter_constraint_update_allocation (constraint,
8017 * clutter_actor_adjust_allocation:
8018 * @self: a #ClutterActor
8019 * @allocation: (inout): the allocation to adjust
8021 * Adjusts the passed allocation box taking into account the actor's
8022 * layout information, like alignment, expansion, and margin.
8025 clutter_actor_adjust_allocation (ClutterActor *self,
8026 ClutterActorBox *allocation)
8028 ClutterActorBox adj_allocation;
8029 float alloc_width, alloc_height;
8030 float min_width, min_height;
8031 float nat_width, nat_height;
8032 ClutterRequestMode req_mode;
8034 adj_allocation = *allocation;
8036 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8038 /* we want to hit the cache, so we use the public API */
8039 req_mode = clutter_actor_get_request_mode (self);
8041 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8043 clutter_actor_get_preferred_width (self, -1,
8046 clutter_actor_get_preferred_height (self, alloc_width,
8050 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8052 clutter_actor_get_preferred_height (self, -1,
8055 clutter_actor_get_preferred_height (self, alloc_height,
8060 #ifdef CLUTTER_ENABLE_DEBUG
8061 /* warn about underallocations */
8062 if (_clutter_diagnostic_enabled () &&
8063 (floorf (min_width - alloc_width) > 0 ||
8064 floorf (min_height - alloc_height) > 0))
8066 ClutterActor *parent = clutter_actor_get_parent (self);
8068 /* the only actors that are allowed to be underallocated are the Stage,
8069 * as it doesn't have an implicit size, and Actors that specifically
8070 * told us that they want to opt-out from layout control mechanisms
8071 * through the NO_LAYOUT escape hatch.
8073 if (parent != NULL &&
8074 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8076 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8077 "of %.2f x %.2f from its parent actor '%s', but its "
8078 "requested minimum size is of %.2f x %.2f",
8079 _clutter_actor_get_debug_name (self),
8080 alloc_width, alloc_height,
8081 _clutter_actor_get_debug_name (parent),
8082 min_width, min_height);
8087 clutter_actor_adjust_width (self,
8091 &adj_allocation.x2);
8093 clutter_actor_adjust_height (self,
8097 &adj_allocation.y2);
8099 /* we maintain the invariant that an allocation cannot be adjusted
8100 * to be outside the parent-given box
8102 if (adj_allocation.x1 < allocation->x1 ||
8103 adj_allocation.y1 < allocation->y1 ||
8104 adj_allocation.x2 > allocation->x2 ||
8105 adj_allocation.y2 > allocation->y2)
8107 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8108 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8109 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8110 _clutter_actor_get_debug_name (self),
8111 adj_allocation.x1, adj_allocation.y1,
8112 adj_allocation.x2 - adj_allocation.x1,
8113 adj_allocation.y2 - adj_allocation.y1,
8114 allocation->x1, allocation->y1,
8115 allocation->x2 - allocation->x1,
8116 allocation->y2 - allocation->y1);
8120 *allocation = adj_allocation;
8124 * clutter_actor_allocate:
8125 * @self: A #ClutterActor
8126 * @box: new allocation of the actor, in parent-relative coordinates
8127 * @flags: flags that control the allocation
8129 * Called by the parent of an actor to assign the actor its size.
8130 * Should never be called by applications (except when implementing
8131 * a container or layout manager).
8133 * Actors can know from their allocation box whether they have moved
8134 * with respect to their parent actor. The @flags parameter describes
8135 * additional information about the allocation, for instance whether
8136 * the parent has moved with respect to the stage, for example because
8137 * a grandparent's origin has moved.
8142 clutter_actor_allocate (ClutterActor *self,
8143 const ClutterActorBox *box,
8144 ClutterAllocationFlags flags)
8146 ClutterActorPrivate *priv;
8147 ClutterActorClass *klass;
8148 ClutterActorBox old_allocation, real_allocation;
8149 gboolean origin_changed, child_moved, size_changed;
8150 gboolean stage_allocation_changed;
8152 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8153 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8155 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8156 "which isn't a descendent of the stage!\n",
8157 self, _clutter_actor_get_debug_name (self));
8163 old_allocation = priv->allocation;
8164 real_allocation = *box;
8166 /* constraints are allowed to modify the allocation only here; we do
8167 * this prior to all the other checks so that we can bail out if the
8168 * allocation did not change
8170 clutter_actor_update_constraints (self, &real_allocation);
8172 /* adjust the allocation depending on the align/margin properties */
8173 clutter_actor_adjust_allocation (self, &real_allocation);
8175 if (real_allocation.x2 < real_allocation.x1 ||
8176 real_allocation.y2 < real_allocation.y1)
8178 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8179 _clutter_actor_get_debug_name (self),
8180 real_allocation.x2 - real_allocation.x1,
8181 real_allocation.y2 - real_allocation.y1);
8184 /* we allow 0-sized actors, but not negative-sized ones */
8185 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8186 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8188 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8190 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8191 real_allocation.y1 != old_allocation.y1);
8193 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8194 real_allocation.y2 != old_allocation.y2);
8196 if (origin_changed || child_moved || size_changed)
8197 stage_allocation_changed = TRUE;
8199 stage_allocation_changed = FALSE;
8201 /* If we get an allocation "out of the blue"
8202 * (we did not queue relayout), then we want to
8203 * ignore it. But if we have needs_allocation set,
8204 * we want to guarantee that allocate() virtual
8205 * method is always called, i.e. that queue_relayout()
8206 * always results in an allocate() invocation on
8209 * The optimization here is to avoid re-allocating
8210 * actors that did not queue relayout and were
8213 if (!priv->needs_allocation && !stage_allocation_changed)
8215 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8219 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8220 * clutter_actor_allocate(), it indicates whether the parent has its
8221 * absolute origin moved; when passed in to ClutterActor::allocate()
8222 * virtual method though, it indicates whether the child has its
8223 * absolute origin moved. So we set it when child_moved is TRUE
8226 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8228 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8230 klass = CLUTTER_ACTOR_GET_CLASS (self);
8231 klass->allocate (self, &real_allocation, flags);
8233 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8235 if (stage_allocation_changed)
8236 clutter_actor_queue_redraw (self);
8240 * clutter_actor_set_allocation:
8241 * @self: a #ClutterActor
8242 * @box: a #ClutterActorBox
8243 * @flags: allocation flags
8245 * Stores the allocation of @self as defined by @box.
8247 * This function can only be called from within the implementation of
8248 * the #ClutterActorClass.allocate() virtual function.
8250 * The allocation should have been adjusted to take into account constraints,
8251 * alignment, and margin properties. If you are implementing a #ClutterActor
8252 * subclass that provides its own layout management policy for its children
8253 * instead of using a #ClutterLayoutManager delegate, you should not call
8254 * this function on the children of @self; instead, you should call
8255 * clutter_actor_allocate(), which will adjust the allocation box for
8258 * This function should only be used by subclasses of #ClutterActor
8259 * that wish to store their allocation but cannot chain up to the
8260 * parent's implementation; the default implementation of the
8261 * #ClutterActorClass.allocate() virtual function will call this
8264 * It is important to note that, while chaining up was the recommended
8265 * behaviour for #ClutterActor subclasses prior to the introduction of
8266 * this function, it is recommended to call clutter_actor_set_allocation()
8269 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8270 * to handle the allocation of its children, this function will call
8271 * the clutter_layout_manager_allocate() function only if the
8272 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8273 * expected that the subclass will call clutter_layout_manager_allocate()
8274 * by itself. For instance, the following code:
8278 * my_actor_allocate (ClutterActor *actor,
8279 * const ClutterActorBox *allocation,
8280 * ClutterAllocationFlags flags)
8282 * ClutterActorBox new_alloc;
8283 * ClutterAllocationFlags new_flags;
8285 * adjust_allocation (allocation, &new_alloc);
8287 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8289 * /* this will use the layout manager set on the actor */
8290 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8294 * is equivalent to this:
8298 * my_actor_allocate (ClutterActor *actor,
8299 * const ClutterActorBox *allocation,
8300 * ClutterAllocationFlags flags)
8302 * ClutterLayoutManager *layout;
8303 * ClutterActorBox new_alloc;
8305 * adjust_allocation (allocation, &new_alloc);
8307 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8309 * layout = clutter_actor_get_layout_manager (actor);
8310 * clutter_layout_manager_allocate (layout,
8311 * CLUTTER_CONTAINER (actor),
8320 clutter_actor_set_allocation (ClutterActor *self,
8321 const ClutterActorBox *box,
8322 ClutterAllocationFlags flags)
8324 ClutterActorPrivate *priv;
8327 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8328 g_return_if_fail (box != NULL);
8330 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8332 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8333 "can only be called from within the implementation of "
8334 "the ClutterActor::allocate() virtual function.");
8340 g_object_freeze_notify (G_OBJECT (self));
8342 changed = clutter_actor_set_allocation_internal (self, box, flags);
8344 /* we allocate our children before we notify changes in our geometry,
8345 * so that people connecting to properties will be able to get valid
8346 * data out of the sub-tree of the scene graph that has this actor at
8349 clutter_actor_maybe_layout_children (self, box, flags);
8353 ClutterActorBox signal_box = priv->allocation;
8354 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8356 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8361 g_object_thaw_notify (G_OBJECT (self));
8365 * clutter_actor_set_geometry:
8366 * @self: A #ClutterActor
8367 * @geometry: A #ClutterGeometry
8369 * Sets the actor's fixed position and forces its minimum and natural
8370 * size, in pixels. This means the untransformed actor will have the
8371 * given geometry. This is the same as calling clutter_actor_set_position()
8372 * and clutter_actor_set_size().
8374 * Deprecated: 1.10: Use clutter_actor_set_position() and
8375 * clutter_actor_set_size() instead.
8378 clutter_actor_set_geometry (ClutterActor *self,
8379 const ClutterGeometry *geometry)
8381 g_object_freeze_notify (G_OBJECT (self));
8383 clutter_actor_set_position (self, geometry->x, geometry->y);
8384 clutter_actor_set_size (self, geometry->width, geometry->height);
8386 g_object_thaw_notify (G_OBJECT (self));
8390 * clutter_actor_get_geometry:
8391 * @self: A #ClutterActor
8392 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8394 * Gets the size and position of an actor relative to its parent
8395 * actor. This is the same as calling clutter_actor_get_position() and
8396 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8397 * requested size and position if the actor's allocation is invalid.
8399 * Deprecated: 1.10: Use clutter_actor_get_position() and
8400 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8404 clutter_actor_get_geometry (ClutterActor *self,
8405 ClutterGeometry *geometry)
8407 gfloat x, y, width, height;
8409 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8410 g_return_if_fail (geometry != NULL);
8412 clutter_actor_get_position (self, &x, &y);
8413 clutter_actor_get_size (self, &width, &height);
8415 geometry->x = (int) x;
8416 geometry->y = (int) y;
8417 geometry->width = (int) width;
8418 geometry->height = (int) height;
8422 * clutter_actor_set_position:
8423 * @self: A #ClutterActor
8424 * @x: New left position of actor in pixels.
8425 * @y: New top position of actor in pixels.
8427 * Sets the actor's fixed position in pixels relative to any parent
8430 * If a layout manager is in use, this position will override the
8431 * layout manager and force a fixed position.
8434 clutter_actor_set_position (ClutterActor *self,
8438 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8440 g_object_freeze_notify (G_OBJECT (self));
8442 clutter_actor_set_x (self, x);
8443 clutter_actor_set_y (self, y);
8445 g_object_thaw_notify (G_OBJECT (self));
8449 * clutter_actor_get_fixed_position_set:
8450 * @self: A #ClutterActor
8452 * Checks whether an actor has a fixed position set (and will thus be
8453 * unaffected by any layout manager).
8455 * Return value: %TRUE if the fixed position is set on the actor
8460 clutter_actor_get_fixed_position_set (ClutterActor *self)
8462 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8464 return self->priv->position_set;
8468 * clutter_actor_set_fixed_position_set:
8469 * @self: A #ClutterActor
8470 * @is_set: whether to use fixed position
8472 * Sets whether an actor has a fixed position set (and will thus be
8473 * unaffected by any layout manager).
8478 clutter_actor_set_fixed_position_set (ClutterActor *self,
8481 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8483 if (self->priv->position_set == (is_set != FALSE))
8486 self->priv->position_set = is_set != FALSE;
8487 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8489 clutter_actor_queue_relayout (self);
8493 * clutter_actor_move_by:
8494 * @self: A #ClutterActor
8495 * @dx: Distance to move Actor on X axis.
8496 * @dy: Distance to move Actor on Y axis.
8498 * Moves an actor by the specified distance relative to its current
8499 * position in pixels.
8501 * This function modifies the fixed position of an actor and thus removes
8502 * it from any layout management. Another way to move an actor is with an
8503 * anchor point, see clutter_actor_set_anchor_point().
8508 clutter_actor_move_by (ClutterActor *self,
8512 const ClutterLayoutInfo *info;
8515 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8517 info = _clutter_actor_get_layout_info_or_defaults (self);
8521 clutter_actor_set_position (self, x + dx, y + dy);
8525 clutter_actor_set_min_width (ClutterActor *self,
8528 ClutterActorPrivate *priv = self->priv;
8529 ClutterActorBox old = { 0, };
8530 ClutterLayoutInfo *info;
8532 /* if we are setting the size on a top-level actor and the
8533 * backend only supports static top-levels (e.g. framebuffers)
8534 * then we ignore the passed value and we override it with
8535 * the stage implementation's preferred size.
8537 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8538 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8541 info = _clutter_actor_get_layout_info (self);
8543 if (priv->min_width_set && min_width == info->min_width)
8546 g_object_freeze_notify (G_OBJECT (self));
8548 clutter_actor_store_old_geometry (self, &old);
8550 info->min_width = min_width;
8551 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8552 clutter_actor_set_min_width_set (self, TRUE);
8554 clutter_actor_notify_if_geometry_changed (self, &old);
8556 g_object_thaw_notify (G_OBJECT (self));
8558 clutter_actor_queue_relayout (self);
8562 clutter_actor_set_min_height (ClutterActor *self,
8566 ClutterActorPrivate *priv = self->priv;
8567 ClutterActorBox old = { 0, };
8568 ClutterLayoutInfo *info;
8570 /* if we are setting the size on a top-level actor and the
8571 * backend only supports static top-levels (e.g. framebuffers)
8572 * then we ignore the passed value and we override it with
8573 * the stage implementation's preferred size.
8575 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8576 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8579 info = _clutter_actor_get_layout_info (self);
8581 if (priv->min_height_set && min_height == info->min_height)
8584 g_object_freeze_notify (G_OBJECT (self));
8586 clutter_actor_store_old_geometry (self, &old);
8588 info->min_height = min_height;
8589 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8590 clutter_actor_set_min_height_set (self, TRUE);
8592 clutter_actor_notify_if_geometry_changed (self, &old);
8594 g_object_thaw_notify (G_OBJECT (self));
8596 clutter_actor_queue_relayout (self);
8600 clutter_actor_set_natural_width (ClutterActor *self,
8601 gfloat natural_width)
8603 ClutterActorPrivate *priv = self->priv;
8604 ClutterActorBox old = { 0, };
8605 ClutterLayoutInfo *info;
8607 /* if we are setting the size on a top-level actor and the
8608 * backend only supports static top-levels (e.g. framebuffers)
8609 * then we ignore the passed value and we override it with
8610 * the stage implementation's preferred size.
8612 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8613 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8616 info = _clutter_actor_get_layout_info (self);
8618 if (priv->natural_width_set && natural_width == info->natural_width)
8621 g_object_freeze_notify (G_OBJECT (self));
8623 clutter_actor_store_old_geometry (self, &old);
8625 info->natural_width = natural_width;
8626 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8627 clutter_actor_set_natural_width_set (self, TRUE);
8629 clutter_actor_notify_if_geometry_changed (self, &old);
8631 g_object_thaw_notify (G_OBJECT (self));
8633 clutter_actor_queue_relayout (self);
8637 clutter_actor_set_natural_height (ClutterActor *self,
8638 gfloat natural_height)
8640 ClutterActorPrivate *priv = self->priv;
8641 ClutterActorBox old = { 0, };
8642 ClutterLayoutInfo *info;
8644 /* if we are setting the size on a top-level actor and the
8645 * backend only supports static top-levels (e.g. framebuffers)
8646 * then we ignore the passed value and we override it with
8647 * the stage implementation's preferred size.
8649 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8650 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8653 info = _clutter_actor_get_layout_info (self);
8655 if (priv->natural_height_set && natural_height == info->natural_height)
8658 g_object_freeze_notify (G_OBJECT (self));
8660 clutter_actor_store_old_geometry (self, &old);
8662 info->natural_height = natural_height;
8663 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8664 clutter_actor_set_natural_height_set (self, TRUE);
8666 clutter_actor_notify_if_geometry_changed (self, &old);
8668 g_object_thaw_notify (G_OBJECT (self));
8670 clutter_actor_queue_relayout (self);
8674 clutter_actor_set_min_width_set (ClutterActor *self,
8675 gboolean use_min_width)
8677 ClutterActorPrivate *priv = self->priv;
8678 ClutterActorBox old = { 0, };
8680 if (priv->min_width_set == (use_min_width != FALSE))
8683 clutter_actor_store_old_geometry (self, &old);
8685 priv->min_width_set = use_min_width != FALSE;
8686 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8688 clutter_actor_notify_if_geometry_changed (self, &old);
8690 clutter_actor_queue_relayout (self);
8694 clutter_actor_set_min_height_set (ClutterActor *self,
8695 gboolean use_min_height)
8697 ClutterActorPrivate *priv = self->priv;
8698 ClutterActorBox old = { 0, };
8700 if (priv->min_height_set == (use_min_height != FALSE))
8703 clutter_actor_store_old_geometry (self, &old);
8705 priv->min_height_set = use_min_height != FALSE;
8706 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8708 clutter_actor_notify_if_geometry_changed (self, &old);
8710 clutter_actor_queue_relayout (self);
8714 clutter_actor_set_natural_width_set (ClutterActor *self,
8715 gboolean use_natural_width)
8717 ClutterActorPrivate *priv = self->priv;
8718 ClutterActorBox old = { 0, };
8720 if (priv->natural_width_set == (use_natural_width != FALSE))
8723 clutter_actor_store_old_geometry (self, &old);
8725 priv->natural_width_set = use_natural_width != FALSE;
8726 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8728 clutter_actor_notify_if_geometry_changed (self, &old);
8730 clutter_actor_queue_relayout (self);
8734 clutter_actor_set_natural_height_set (ClutterActor *self,
8735 gboolean use_natural_height)
8737 ClutterActorPrivate *priv = self->priv;
8738 ClutterActorBox old = { 0, };
8740 if (priv->natural_height_set == (use_natural_height != FALSE))
8743 clutter_actor_store_old_geometry (self, &old);
8745 priv->natural_height_set = use_natural_height != FALSE;
8746 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8748 clutter_actor_notify_if_geometry_changed (self, &old);
8750 clutter_actor_queue_relayout (self);
8754 * clutter_actor_set_request_mode:
8755 * @self: a #ClutterActor
8756 * @mode: the request mode
8758 * Sets the geometry request mode of @self.
8760 * The @mode determines the order for invoking
8761 * clutter_actor_get_preferred_width() and
8762 * clutter_actor_get_preferred_height()
8767 clutter_actor_set_request_mode (ClutterActor *self,
8768 ClutterRequestMode mode)
8770 ClutterActorPrivate *priv;
8772 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8776 if (priv->request_mode == mode)
8779 priv->request_mode = mode;
8781 priv->needs_width_request = TRUE;
8782 priv->needs_height_request = TRUE;
8784 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8786 clutter_actor_queue_relayout (self);
8790 * clutter_actor_get_request_mode:
8791 * @self: a #ClutterActor
8793 * Retrieves the geometry request mode of @self
8795 * Return value: the request mode for the actor
8800 clutter_actor_get_request_mode (ClutterActor *self)
8802 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8803 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8805 return self->priv->request_mode;
8808 /* variant of set_width() without checks and without notification
8809 * freeze+thaw, for internal usage only
8812 clutter_actor_set_width_internal (ClutterActor *self,
8817 /* the Stage will use the :min-width to control the minimum
8818 * width to be resized to, so we should not be setting it
8819 * along with the :natural-width
8821 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8822 clutter_actor_set_min_width (self, width);
8824 clutter_actor_set_natural_width (self, width);
8828 /* we only unset the :natural-width for the Stage */
8829 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8830 clutter_actor_set_min_width_set (self, FALSE);
8832 clutter_actor_set_natural_width_set (self, FALSE);
8836 /* variant of set_height() without checks and without notification
8837 * freeze+thaw, for internal usage only
8840 clutter_actor_set_height_internal (ClutterActor *self,
8845 /* see the comment above in set_width_internal() */
8846 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8847 clutter_actor_set_min_height (self, height);
8849 clutter_actor_set_natural_height (self, height);
8853 /* see the comment above in set_width_internal() */
8854 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8855 clutter_actor_set_min_height_set (self, FALSE);
8857 clutter_actor_set_natural_height_set (self, FALSE);
8862 * clutter_actor_set_size:
8863 * @self: A #ClutterActor
8864 * @width: New width of actor in pixels, or -1
8865 * @height: New height of actor in pixels, or -1
8867 * Sets the actor's size request in pixels. This overrides any
8868 * "normal" size request the actor would have. For example
8869 * a text actor might normally request the size of the text;
8870 * this function would force a specific size instead.
8872 * If @width and/or @height are -1 the actor will use its
8873 * "normal" size request instead of overriding it, i.e.
8874 * you can "unset" the size with -1.
8876 * This function sets or unsets both the minimum and natural size.
8879 clutter_actor_set_size (ClutterActor *self,
8883 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8885 g_object_freeze_notify (G_OBJECT (self));
8887 clutter_actor_set_width (self, width);
8888 clutter_actor_set_height (self, height);
8890 g_object_thaw_notify (G_OBJECT (self));
8894 * clutter_actor_get_size:
8895 * @self: A #ClutterActor
8896 * @width: (out) (allow-none): return location for the width, or %NULL.
8897 * @height: (out) (allow-none): return location for the height, or %NULL.
8899 * This function tries to "do what you mean" and return
8900 * the size an actor will have. If the actor has a valid
8901 * allocation, the allocation will be returned; otherwise,
8902 * the actors natural size request will be returned.
8904 * If you care whether you get the request vs. the allocation, you
8905 * should probably call a different function like
8906 * clutter_actor_get_allocation_box() or
8907 * clutter_actor_get_preferred_width().
8912 clutter_actor_get_size (ClutterActor *self,
8916 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8919 *width = clutter_actor_get_width (self);
8922 *height = clutter_actor_get_height (self);
8926 * clutter_actor_get_position:
8927 * @self: a #ClutterActor
8928 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8929 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8931 * This function tries to "do what you mean" and tell you where the
8932 * actor is, prior to any transformations. Retrieves the fixed
8933 * position of an actor in pixels, if one has been set; otherwise, if
8934 * the allocation is valid, returns the actor's allocated position;
8935 * otherwise, returns 0,0.
8937 * The returned position is in pixels.
8942 clutter_actor_get_position (ClutterActor *self,
8946 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8949 *x = clutter_actor_get_x (self);
8952 *y = clutter_actor_get_y (self);
8956 * clutter_actor_get_transformed_position:
8957 * @self: A #ClutterActor
8958 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8959 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8961 * Gets the absolute position of an actor, in pixels relative to the stage.
8966 clutter_actor_get_transformed_position (ClutterActor *self,
8973 v1.x = v1.y = v1.z = 0;
8974 clutter_actor_apply_transform_to_point (self, &v1, &v2);
8984 * clutter_actor_get_transformed_size:
8985 * @self: A #ClutterActor
8986 * @width: (out) (allow-none): return location for the width, or %NULL
8987 * @height: (out) (allow-none): return location for the height, or %NULL
8989 * Gets the absolute size of an actor in pixels, taking into account the
8992 * If the actor has a valid allocation, the allocated size will be used.
8993 * If the actor has not a valid allocation then the preferred size will
8994 * be transformed and returned.
8996 * If you want the transformed allocation, see
8997 * clutter_actor_get_abs_allocation_vertices() instead.
8999 * <note>When the actor (or one of its ancestors) is rotated around the
9000 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9001 * as a generic quadrangle; in that case this function returns the size
9002 * of the smallest rectangle that encapsulates the entire quad. Please
9003 * note that in this case no assumptions can be made about the relative
9004 * position of this envelope to the absolute position of the actor, as
9005 * returned by clutter_actor_get_transformed_position(); if you need this
9006 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9007 * to get the coords of the actual quadrangle.</note>
9012 clutter_actor_get_transformed_size (ClutterActor *self,
9016 ClutterActorPrivate *priv;
9018 gfloat x_min, x_max, y_min, y_max;
9021 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9025 /* if the actor hasn't been allocated yet, get the preferred
9026 * size and transform that
9028 if (priv->needs_allocation)
9030 gfloat natural_width, natural_height;
9031 ClutterActorBox box;
9033 /* Make a fake allocation to transform.
9035 * NB: _clutter_actor_transform_and_project_box expects a box in
9036 * the actor's coordinate space... */
9041 natural_width = natural_height = 0;
9042 clutter_actor_get_preferred_size (self, NULL, NULL,
9046 box.x2 = natural_width;
9047 box.y2 = natural_height;
9049 _clutter_actor_transform_and_project_box (self, &box, v);
9052 clutter_actor_get_abs_allocation_vertices (self, v);
9054 x_min = x_max = v[0].x;
9055 y_min = y_max = v[0].y;
9057 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9073 *width = x_max - x_min;
9076 *height = y_max - y_min;
9080 * clutter_actor_get_width:
9081 * @self: A #ClutterActor
9083 * Retrieves the width of a #ClutterActor.
9085 * If the actor has a valid allocation, this function will return the
9086 * width of the allocated area given to the actor.
9088 * If the actor does not have a valid allocation, this function will
9089 * return the actor's natural width, that is the preferred width of
9092 * If you care whether you get the preferred width or the width that
9093 * has been assigned to the actor, you should probably call a different
9094 * function like clutter_actor_get_allocation_box() to retrieve the
9095 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9098 * If an actor has a fixed width, for instance a width that has been
9099 * assigned using clutter_actor_set_width(), the width returned will
9100 * be the same value.
9102 * Return value: the width of the actor, in pixels
9105 clutter_actor_get_width (ClutterActor *self)
9107 ClutterActorPrivate *priv;
9109 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9113 if (priv->needs_allocation)
9115 gfloat natural_width = 0;
9117 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9118 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9121 gfloat natural_height = 0;
9123 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9124 clutter_actor_get_preferred_width (self, natural_height,
9129 return natural_width;
9132 return priv->allocation.x2 - priv->allocation.x1;
9136 * clutter_actor_get_height:
9137 * @self: A #ClutterActor
9139 * Retrieves the height of a #ClutterActor.
9141 * If the actor has a valid allocation, this function will return the
9142 * height of the allocated area given to the actor.
9144 * If the actor does not have a valid allocation, this function will
9145 * return the actor's natural height, that is the preferred height of
9148 * If you care whether you get the preferred height or the height that
9149 * has been assigned to the actor, you should probably call a different
9150 * function like clutter_actor_get_allocation_box() to retrieve the
9151 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9154 * If an actor has a fixed height, for instance a height that has been
9155 * assigned using clutter_actor_set_height(), the height returned will
9156 * be the same value.
9158 * Return value: the height of the actor, in pixels
9161 clutter_actor_get_height (ClutterActor *self)
9163 ClutterActorPrivate *priv;
9165 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9169 if (priv->needs_allocation)
9171 gfloat natural_height = 0;
9173 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9175 gfloat natural_width = 0;
9177 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9178 clutter_actor_get_preferred_height (self, natural_width,
9179 NULL, &natural_height);
9182 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9184 return natural_height;
9187 return priv->allocation.y2 - priv->allocation.y1;
9191 * clutter_actor_set_width:
9192 * @self: A #ClutterActor
9193 * @width: Requested new width for the actor, in pixels, or -1
9195 * Forces a width on an actor, causing the actor's preferred width
9196 * and height (if any) to be ignored.
9198 * If @width is -1 the actor will use its preferred width request
9199 * instead of overriding it, i.e. you can "unset" the width with -1.
9201 * This function sets both the minimum and natural size of the actor.
9206 clutter_actor_set_width (ClutterActor *self,
9209 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9211 if (clutter_actor_get_easing_duration (self) != 0)
9213 ClutterTransition *transition;
9215 transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9216 if (transition == NULL)
9218 float old_width = clutter_actor_get_width (self);
9220 transition = _clutter_actor_create_transition (self,
9221 obj_props[PROP_WIDTH],
9224 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9227 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9229 clutter_actor_queue_relayout (self);
9233 g_object_freeze_notify (G_OBJECT (self));
9235 clutter_actor_set_width_internal (self, width);
9237 g_object_thaw_notify (G_OBJECT (self));
9242 * clutter_actor_set_height:
9243 * @self: A #ClutterActor
9244 * @height: Requested new height for the actor, in pixels, or -1
9246 * Forces a height on an actor, causing the actor's preferred width
9247 * and height (if any) to be ignored.
9249 * If @height is -1 the actor will use its preferred height instead of
9250 * overriding it, i.e. you can "unset" the height with -1.
9252 * This function sets both the minimum and natural size of the actor.
9257 clutter_actor_set_height (ClutterActor *self,
9260 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9262 if (clutter_actor_get_easing_duration (self) != 0)
9264 ClutterTransition *transition;
9266 transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9267 if (transition == NULL)
9269 float old_height = clutter_actor_get_height (self);
9271 transition = _clutter_actor_create_transition (self,
9272 obj_props[PROP_HEIGHT],
9275 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9278 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9280 clutter_actor_queue_relayout (self);
9284 g_object_freeze_notify (G_OBJECT (self));
9286 clutter_actor_set_height_internal (self, height);
9288 g_object_thaw_notify (G_OBJECT (self));
9293 clutter_actor_set_x_internal (ClutterActor *self,
9296 ClutterActorPrivate *priv = self->priv;
9297 ClutterLayoutInfo *linfo;
9298 ClutterActorBox old = { 0, };
9300 linfo = _clutter_actor_get_layout_info (self);
9302 if (priv->position_set && linfo->fixed_x == x)
9305 clutter_actor_store_old_geometry (self, &old);
9308 clutter_actor_set_fixed_position_set (self, TRUE);
9310 clutter_actor_notify_if_geometry_changed (self, &old);
9312 clutter_actor_queue_relayout (self);
9316 clutter_actor_set_y_internal (ClutterActor *self,
9319 ClutterActorPrivate *priv = self->priv;
9320 ClutterLayoutInfo *linfo;
9321 ClutterActorBox old = { 0, };
9323 linfo = _clutter_actor_get_layout_info (self);
9325 if (priv->position_set && linfo->fixed_y == y)
9328 clutter_actor_store_old_geometry (self, &old);
9331 clutter_actor_set_fixed_position_set (self, TRUE);
9333 clutter_actor_notify_if_geometry_changed (self, &old);
9337 * clutter_actor_set_x:
9338 * @self: a #ClutterActor
9339 * @x: the actor's position on the X axis
9341 * Sets the actor's X coordinate, relative to its parent, in pixels.
9343 * Overrides any layout manager and forces a fixed position for
9346 * The #ClutterActor:x property is animatable.
9351 clutter_actor_set_x (ClutterActor *self,
9354 const ClutterLayoutInfo *linfo;
9356 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9358 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9360 if (clutter_actor_get_easing_duration (self) != 0)
9362 ClutterTransition *transition;
9364 transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9365 if (transition == NULL)
9367 transition = _clutter_actor_create_transition (self,
9372 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9375 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9377 clutter_actor_queue_relayout (self);
9380 clutter_actor_set_x_internal (self, x);
9384 * clutter_actor_set_y:
9385 * @self: a #ClutterActor
9386 * @y: the actor's position on the Y axis
9388 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9390 * Overrides any layout manager and forces a fixed position for
9393 * The #ClutterActor:y property is animatable.
9398 clutter_actor_set_y (ClutterActor *self,
9401 const ClutterLayoutInfo *linfo;
9403 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9405 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9407 if (clutter_actor_get_easing_duration (self) != 0)
9409 ClutterTransition *transition;
9411 transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9412 if (transition == NULL)
9414 transition = _clutter_actor_create_transition (self,
9419 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9422 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9424 clutter_actor_queue_relayout (self);
9427 clutter_actor_set_y_internal (self, y);
9429 clutter_actor_queue_relayout (self);
9433 * clutter_actor_get_x:
9434 * @self: A #ClutterActor
9436 * Retrieves the X coordinate of a #ClutterActor.
9438 * This function tries to "do what you mean", by returning the
9439 * correct value depending on the actor's state.
9441 * If the actor has a valid allocation, this function will return
9442 * the X coordinate of the origin of the allocation box.
9444 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9445 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9446 * function will return that coordinate.
9448 * If both the allocation and a fixed position are missing, this function
9451 * Return value: the X coordinate, in pixels, ignoring any
9452 * transformation (i.e. scaling, rotation)
9455 clutter_actor_get_x (ClutterActor *self)
9457 ClutterActorPrivate *priv;
9459 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9463 if (priv->needs_allocation)
9465 if (priv->position_set)
9467 const ClutterLayoutInfo *info;
9469 info = _clutter_actor_get_layout_info_or_defaults (self);
9471 return info->fixed_x;
9477 return priv->allocation.x1;
9481 * clutter_actor_get_y:
9482 * @self: A #ClutterActor
9484 * Retrieves the Y coordinate of a #ClutterActor.
9486 * This function tries to "do what you mean", by returning the
9487 * correct value depending on the actor's state.
9489 * If the actor has a valid allocation, this function will return
9490 * the Y coordinate of the origin of the allocation box.
9492 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9493 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9494 * function will return that coordinate.
9496 * If both the allocation and a fixed position are missing, this function
9499 * Return value: the Y coordinate, in pixels, ignoring any
9500 * transformation (i.e. scaling, rotation)
9503 clutter_actor_get_y (ClutterActor *self)
9505 ClutterActorPrivate *priv;
9507 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9511 if (priv->needs_allocation)
9513 if (priv->position_set)
9515 const ClutterLayoutInfo *info;
9517 info = _clutter_actor_get_layout_info_or_defaults (self);
9519 return info->fixed_y;
9525 return priv->allocation.y1;
9529 * clutter_actor_set_scale:
9530 * @self: A #ClutterActor
9531 * @scale_x: double factor to scale actor by horizontally.
9532 * @scale_y: double factor to scale actor by vertically.
9534 * Scales an actor with the given factors. The scaling is relative to
9535 * the scale center and the anchor point. The scale center is
9536 * unchanged by this function and defaults to 0,0.
9538 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9544 clutter_actor_set_scale (ClutterActor *self,
9548 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9550 g_object_freeze_notify (G_OBJECT (self));
9552 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9553 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9555 g_object_thaw_notify (G_OBJECT (self));
9559 * clutter_actor_set_scale_full:
9560 * @self: A #ClutterActor
9561 * @scale_x: double factor to scale actor by horizontally.
9562 * @scale_y: double factor to scale actor by vertically.
9563 * @center_x: X coordinate of the center of the scale.
9564 * @center_y: Y coordinate of the center of the scale
9566 * Scales an actor with the given factors around the given center
9567 * point. The center point is specified in pixels relative to the
9568 * anchor point (usually the top left corner of the actor).
9570 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9576 clutter_actor_set_scale_full (ClutterActor *self,
9582 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9584 g_object_freeze_notify (G_OBJECT (self));
9586 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9587 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9588 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9589 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9591 g_object_thaw_notify (G_OBJECT (self));
9595 * clutter_actor_set_scale_with_gravity:
9596 * @self: A #ClutterActor
9597 * @scale_x: double factor to scale actor by horizontally.
9598 * @scale_y: double factor to scale actor by vertically.
9599 * @gravity: the location of the scale center expressed as a compass
9602 * Scales an actor with the given factors around the given
9603 * center point. The center point is specified as one of the compass
9604 * directions in #ClutterGravity. For example, setting it to north
9605 * will cause the top of the actor to remain unchanged and the rest of
9606 * the actor to expand left, right and downwards.
9608 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9614 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9617 ClutterGravity gravity)
9619 ClutterTransformInfo *info;
9622 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9624 obj = G_OBJECT (self);
9626 g_object_freeze_notify (obj);
9628 info = _clutter_actor_get_transform_info (self);
9629 info->scale_x = scale_x;
9630 info->scale_y = scale_y;
9632 if (gravity == CLUTTER_GRAVITY_NONE)
9633 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9635 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9637 self->priv->transform_valid = FALSE;
9639 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9640 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9641 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9642 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9643 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9645 clutter_actor_queue_redraw (self);
9647 g_object_thaw_notify (obj);
9651 * clutter_actor_get_scale:
9652 * @self: A #ClutterActor
9653 * @scale_x: (out) (allow-none): Location to store horizonal
9654 * scale factor, or %NULL.
9655 * @scale_y: (out) (allow-none): Location to store vertical
9656 * scale factor, or %NULL.
9658 * Retrieves an actors scale factors.
9663 clutter_actor_get_scale (ClutterActor *self,
9667 const ClutterTransformInfo *info;
9669 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9671 info = _clutter_actor_get_transform_info_or_defaults (self);
9674 *scale_x = info->scale_x;
9677 *scale_y = info->scale_y;
9681 * clutter_actor_get_scale_center:
9682 * @self: A #ClutterActor
9683 * @center_x: (out) (allow-none): Location to store the X position
9684 * of the scale center, or %NULL.
9685 * @center_y: (out) (allow-none): Location to store the Y position
9686 * of the scale center, or %NULL.
9688 * Retrieves the scale center coordinate in pixels relative to the top
9689 * left corner of the actor. If the scale center was specified using a
9690 * #ClutterGravity this will calculate the pixel offset using the
9691 * current size of the actor.
9696 clutter_actor_get_scale_center (ClutterActor *self,
9700 const ClutterTransformInfo *info;
9702 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9704 info = _clutter_actor_get_transform_info_or_defaults (self);
9706 clutter_anchor_coord_get_units (self, &info->scale_center,
9713 * clutter_actor_get_scale_gravity:
9714 * @self: A #ClutterActor
9716 * Retrieves the scale center as a compass direction. If the scale
9717 * center was specified in pixels or units this will return
9718 * %CLUTTER_GRAVITY_NONE.
9720 * Return value: the scale gravity
9725 clutter_actor_get_scale_gravity (ClutterActor *self)
9727 const ClutterTransformInfo *info;
9729 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9731 info = _clutter_actor_get_transform_info_or_defaults (self);
9733 return clutter_anchor_coord_get_gravity (&info->scale_center);
9737 clutter_actor_set_opacity_internal (ClutterActor *self,
9740 ClutterActorPrivate *priv = self->priv;
9742 if (priv->opacity != opacity)
9744 priv->opacity = opacity;
9746 /* Queue a redraw from the flatten effect so that it can use
9747 its cached image if available instead of having to redraw the
9748 actual actor. If it doesn't end up using the FBO then the
9749 effect is still able to continue the paint anyway. If there
9750 is no flatten effect yet then this is equivalent to queueing
9752 _clutter_actor_queue_redraw_full (self,
9755 priv->flatten_effect);
9757 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9762 * clutter_actor_set_opacity:
9763 * @self: A #ClutterActor
9764 * @opacity: New opacity value for the actor.
9766 * Sets the actor's opacity, with zero being completely transparent and
9767 * 255 (0xff) being fully opaque.
9769 * The #ClutterActor:opacity property is animatable.
9772 clutter_actor_set_opacity (ClutterActor *self,
9775 ClutterActorPrivate *priv;
9777 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9781 if (clutter_actor_get_easing_duration (self) != 0)
9783 ClutterTransition *transition;
9785 transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9786 if (transition == NULL)
9788 transition = _clutter_actor_create_transition (self,
9789 obj_props[PROP_OPACITY],
9792 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9795 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9797 clutter_actor_queue_redraw (self);
9800 clutter_actor_set_opacity_internal (self, opacity);
9804 * clutter_actor_get_paint_opacity_internal:
9805 * @self: a #ClutterActor
9807 * Retrieves the absolute opacity of the actor, as it appears on the stage
9809 * This function does not do type checks
9811 * Return value: the absolute opacity of the actor
9814 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9816 ClutterActorPrivate *priv = self->priv;
9817 ClutterActor *parent;
9819 /* override the top-level opacity to always be 255; even in
9820 * case of ClutterStage:use-alpha being TRUE we want the rest
9821 * of the scene to be painted
9823 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9826 if (priv->opacity_override >= 0)
9827 return priv->opacity_override;
9829 parent = priv->parent;
9831 /* Factor in the actual actors opacity with parents */
9834 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9836 if (opacity != 0xff)
9837 return (opacity * priv->opacity) / 0xff;
9840 return priv->opacity;
9845 * clutter_actor_get_paint_opacity:
9846 * @self: A #ClutterActor
9848 * Retrieves the absolute opacity of the actor, as it appears on the stage.
9850 * This function traverses the hierarchy chain and composites the opacity of
9851 * the actor with that of its parents.
9853 * This function is intended for subclasses to use in the paint virtual
9854 * function, to paint themselves with the correct opacity.
9856 * Return value: The actor opacity value.
9861 clutter_actor_get_paint_opacity (ClutterActor *self)
9863 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9865 return clutter_actor_get_paint_opacity_internal (self);
9869 * clutter_actor_get_opacity:
9870 * @self: a #ClutterActor
9872 * Retrieves the opacity value of an actor, as set by
9873 * clutter_actor_set_opacity().
9875 * For retrieving the absolute opacity of the actor inside a paint
9876 * virtual function, see clutter_actor_get_paint_opacity().
9878 * Return value: the opacity of the actor
9881 clutter_actor_get_opacity (ClutterActor *self)
9883 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9885 return self->priv->opacity;
9889 * clutter_actor_set_offscreen_redirect:
9890 * @self: A #ClutterActor
9891 * @redirect: New offscreen redirect flags for the actor.
9893 * Defines the circumstances where the actor should be redirected into
9894 * an offscreen image. The offscreen image is used to flatten the
9895 * actor into a single image while painting for two main reasons.
9896 * Firstly, when the actor is painted a second time without any of its
9897 * contents changing it can simply repaint the cached image without
9898 * descending further down the actor hierarchy. Secondly, it will make
9899 * the opacity look correct even if there are overlapping primitives
9902 * Caching the actor could in some cases be a performance win and in
9903 * some cases be a performance lose so it is important to determine
9904 * which value is right for an actor before modifying this value. For
9905 * example, there is never any reason to flatten an actor that is just
9906 * a single texture (such as a #ClutterTexture) because it is
9907 * effectively already cached in an image so the offscreen would be
9908 * redundant. Also if the actor contains primitives that are far apart
9909 * with a large transparent area in the middle (such as a large
9910 * CluterGroup with a small actor in the top left and a small actor in
9911 * the bottom right) then the cached image will contain the entire
9912 * image of the large area and the paint will waste time blending all
9913 * of the transparent pixels in the middle.
9915 * The default method of implementing opacity on a container simply
9916 * forwards on the opacity to all of the children. If the children are
9917 * overlapping then it will appear as if they are two separate glassy
9918 * objects and there will be a break in the color where they
9919 * overlap. By redirecting to an offscreen buffer it will be as if the
9920 * two opaque objects are combined into one and then made transparent
9921 * which is usually what is expected.
9923 * The image below demonstrates the difference between redirecting and
9924 * not. The image shows two Clutter groups, each containing a red and
9925 * a green rectangle which overlap. The opacity on the group is set to
9926 * 128 (which is 50%). When the offscreen redirect is not used, the
9927 * red rectangle can be seen through the blue rectangle as if the two
9928 * rectangles were separately transparent. When the redirect is used
9929 * the group as a whole is transparent instead so the red rectangle is
9930 * not visible where they overlap.
9932 * <figure id="offscreen-redirect">
9933 * <title>Sample of using an offscreen redirect for transparency</title>
9934 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
9937 * The default value for this property is 0, so we effectively will
9938 * never redirect an actor offscreen by default. This means that there
9939 * are times that transparent actors may look glassy as described
9940 * above. The reason this is the default is because there is a
9941 * performance trade off between quality and performance here. In many
9942 * cases the default form of glassy opacity looks good enough, but if
9943 * it's not you will need to set the
9944 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9945 * redirection for opacity.
9947 * Custom actors that don't contain any overlapping primitives are
9948 * recommended to override the has_overlaps() virtual to return %FALSE
9949 * for maximum efficiency.
9954 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9955 ClutterOffscreenRedirect redirect)
9957 ClutterActorPrivate *priv;
9959 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9963 if (priv->offscreen_redirect != redirect)
9965 priv->offscreen_redirect = redirect;
9967 /* Queue a redraw from the effect so that it can use its cached
9968 image if available instead of having to redraw the actual
9969 actor. If it doesn't end up using the FBO then the effect is
9970 still able to continue the paint anyway. If there is no
9971 effect then this is equivalent to queuing a full redraw */
9972 _clutter_actor_queue_redraw_full (self,
9975 priv->flatten_effect);
9977 g_object_notify_by_pspec (G_OBJECT (self),
9978 obj_props[PROP_OFFSCREEN_REDIRECT]);
9983 * clutter_actor_get_offscreen_redirect:
9984 * @self: a #ClutterActor
9986 * Retrieves whether to redirect the actor to an offscreen buffer, as
9987 * set by clutter_actor_set_offscreen_redirect().
9989 * Return value: the value of the offscreen-redirect property of the actor
9993 ClutterOffscreenRedirect
9994 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9996 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9998 return self->priv->offscreen_redirect;
10002 * clutter_actor_set_name:
10003 * @self: A #ClutterActor
10004 * @name: Textual tag to apply to actor
10006 * Sets the given name to @self. The name can be used to identify
10010 clutter_actor_set_name (ClutterActor *self,
10013 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10015 g_free (self->priv->name);
10016 self->priv->name = g_strdup (name);
10018 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10022 * clutter_actor_get_name:
10023 * @self: A #ClutterActor
10025 * Retrieves the name of @self.
10027 * Return value: the name of the actor, or %NULL. The returned string is
10028 * owned by the actor and should not be modified or freed.
10031 clutter_actor_get_name (ClutterActor *self)
10033 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10035 return self->priv->name;
10039 * clutter_actor_get_gid:
10040 * @self: A #ClutterActor
10042 * Retrieves the unique id for @self.
10044 * Return value: Globally unique value for this object instance.
10048 * Deprecated: 1.8: The id is not used any longer.
10051 clutter_actor_get_gid (ClutterActor *self)
10053 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10055 return self->priv->id;
10059 clutter_actor_set_depth_internal (ClutterActor *self,
10062 ClutterTransformInfo *info;
10064 info = _clutter_actor_get_transform_info (self);
10066 if (info->depth != depth)
10068 /* Sets Z value - XXX 2.0: should we invert? */
10069 info->depth = depth;
10071 self->priv->transform_valid = FALSE;
10073 /* FIXME - remove this crap; sadly, there are still containers
10074 * in Clutter that depend on this utter brain damage
10076 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10078 clutter_actor_queue_redraw (self);
10080 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10085 * clutter_actor_set_depth:
10086 * @self: a #ClutterActor
10089 * Sets the Z coordinate of @self to @depth.
10091 * The unit used by @depth is dependant on the perspective setup. See
10092 * also clutter_stage_set_perspective().
10095 clutter_actor_set_depth (ClutterActor *self,
10098 const ClutterTransformInfo *tinfo;
10100 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10102 tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10104 if (clutter_actor_get_easing_duration (self) != 0)
10106 ClutterTransition *transition;
10108 transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10109 if (transition == NULL)
10111 transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10114 clutter_timeline_start (CLUTTER_TIMELINE (transition));
10117 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10119 clutter_actor_queue_redraw (self);
10122 clutter_actor_set_depth_internal (self, depth);
10126 * clutter_actor_get_depth:
10127 * @self: a #ClutterActor
10129 * Retrieves the depth of @self.
10131 * Return value: the depth of the actor
10134 clutter_actor_get_depth (ClutterActor *self)
10136 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10138 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10142 * clutter_actor_set_rotation:
10143 * @self: a #ClutterActor
10144 * @axis: the axis of rotation
10145 * @angle: the angle of rotation
10146 * @x: X coordinate of the rotation center
10147 * @y: Y coordinate of the rotation center
10148 * @z: Z coordinate of the rotation center
10150 * Sets the rotation angle of @self around the given axis.
10152 * The rotation center coordinates used depend on the value of @axis:
10154 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10155 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10156 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10159 * The rotation coordinates are relative to the anchor point of the
10160 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10161 * point is set, the upper left corner is assumed as the origin.
10166 clutter_actor_set_rotation (ClutterActor *self,
10167 ClutterRotateAxis axis,
10175 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10181 g_object_freeze_notify (G_OBJECT (self));
10183 clutter_actor_set_rotation_angle (self, axis, angle);
10184 clutter_actor_set_rotation_center_internal (self, axis, &v);
10186 g_object_thaw_notify (G_OBJECT (self));
10190 * clutter_actor_set_z_rotation_from_gravity:
10191 * @self: a #ClutterActor
10192 * @angle: the angle of rotation
10193 * @gravity: the center point of the rotation
10195 * Sets the rotation angle of @self around the Z axis using the center
10196 * point specified as a compass point. For example to rotate such that
10197 * the center of the actor remains static you can use
10198 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10199 * will move accordingly.
10204 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10206 ClutterGravity gravity)
10208 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10210 if (gravity == CLUTTER_GRAVITY_NONE)
10211 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10214 GObject *obj = G_OBJECT (self);
10215 ClutterTransformInfo *info;
10217 info = _clutter_actor_get_transform_info (self);
10219 g_object_freeze_notify (obj);
10221 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10223 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10224 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10225 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10227 g_object_thaw_notify (obj);
10232 * clutter_actor_get_rotation:
10233 * @self: a #ClutterActor
10234 * @axis: the axis of rotation
10235 * @x: (out): return value for the X coordinate of the center of rotation
10236 * @y: (out): return value for the Y coordinate of the center of rotation
10237 * @z: (out): return value for the Z coordinate of the center of rotation
10239 * Retrieves the angle and center of rotation on the given axis,
10240 * set using clutter_actor_set_rotation().
10242 * Return value: the angle of rotation
10247 clutter_actor_get_rotation (ClutterActor *self,
10248 ClutterRotateAxis axis,
10253 const ClutterTransformInfo *info;
10254 const AnchorCoord *anchor_coord;
10255 gdouble retval = 0;
10257 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10259 info = _clutter_actor_get_transform_info_or_defaults (self);
10263 case CLUTTER_X_AXIS:
10264 anchor_coord = &info->rx_center;
10265 retval = info->rx_angle;
10268 case CLUTTER_Y_AXIS:
10269 anchor_coord = &info->ry_center;
10270 retval = info->ry_angle;
10273 case CLUTTER_Z_AXIS:
10274 anchor_coord = &info->rz_center;
10275 retval = info->rz_angle;
10279 anchor_coord = NULL;
10284 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10290 * clutter_actor_get_z_rotation_gravity:
10291 * @self: A #ClutterActor
10293 * Retrieves the center for the rotation around the Z axis as a
10294 * compass direction. If the center was specified in pixels or units
10295 * this will return %CLUTTER_GRAVITY_NONE.
10297 * Return value: the Z rotation center
10302 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10304 const ClutterTransformInfo *info;
10306 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10308 info = _clutter_actor_get_transform_info_or_defaults (self);
10310 return clutter_anchor_coord_get_gravity (&info->rz_center);
10314 * clutter_actor_set_clip:
10315 * @self: A #ClutterActor
10316 * @xoff: X offset of the clip rectangle
10317 * @yoff: Y offset of the clip rectangle
10318 * @width: Width of the clip rectangle
10319 * @height: Height of the clip rectangle
10321 * Sets clip area for @self. The clip area is always computed from the
10322 * upper left corner of the actor, even if the anchor point is set
10328 clutter_actor_set_clip (ClutterActor *self,
10334 ClutterActorPrivate *priv;
10336 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10340 if (priv->has_clip &&
10341 priv->clip.x == xoff &&
10342 priv->clip.y == yoff &&
10343 priv->clip.width == width &&
10344 priv->clip.height == height)
10347 priv->clip.x = xoff;
10348 priv->clip.y = yoff;
10349 priv->clip.width = width;
10350 priv->clip.height = height;
10352 priv->has_clip = TRUE;
10354 clutter_actor_queue_redraw (self);
10356 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10357 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10361 * clutter_actor_remove_clip:
10362 * @self: A #ClutterActor
10364 * Removes clip area from @self.
10367 clutter_actor_remove_clip (ClutterActor *self)
10369 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10371 if (!self->priv->has_clip)
10374 self->priv->has_clip = FALSE;
10376 clutter_actor_queue_redraw (self);
10378 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10382 * clutter_actor_has_clip:
10383 * @self: a #ClutterActor
10385 * Determines whether the actor has a clip area set or not.
10387 * Return value: %TRUE if the actor has a clip area set.
10392 clutter_actor_has_clip (ClutterActor *self)
10394 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10396 return self->priv->has_clip;
10400 * clutter_actor_get_clip:
10401 * @self: a #ClutterActor
10402 * @xoff: (out) (allow-none): return location for the X offset of
10403 * the clip rectangle, or %NULL
10404 * @yoff: (out) (allow-none): return location for the Y offset of
10405 * the clip rectangle, or %NULL
10406 * @width: (out) (allow-none): return location for the width of
10407 * the clip rectangle, or %NULL
10408 * @height: (out) (allow-none): return location for the height of
10409 * the clip rectangle, or %NULL
10411 * Gets the clip area for @self, if any is set
10416 clutter_actor_get_clip (ClutterActor *self,
10422 ClutterActorPrivate *priv;
10424 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10428 if (!priv->has_clip)
10432 *xoff = priv->clip.x;
10435 *yoff = priv->clip.y;
10438 *width = priv->clip.width;
10440 if (height != NULL)
10441 *height = priv->clip.height;
10445 * clutter_actor_get_children:
10446 * @self: a #ClutterActor
10448 * Retrieves the list of children of @self.
10450 * Return value: (transfer container) (element-type ClutterActor): A newly
10451 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10457 clutter_actor_get_children (ClutterActor *self)
10459 ClutterActor *iter;
10462 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10464 /* we walk the list backward so that we can use prepend(),
10467 for (iter = self->priv->last_child, res = NULL;
10469 iter = iter->priv->prev_sibling)
10471 res = g_list_prepend (res, iter);
10478 * insert_child_at_depth:
10479 * @self: a #ClutterActor
10480 * @child: a #ClutterActor
10482 * Inserts @child inside the list of children held by @self, using
10483 * the depth as the insertion criteria.
10485 * This sadly makes the insertion not O(1), but we can keep the
10486 * list sorted so that the painters algorithm we use for painting
10487 * the children will work correctly.
10490 insert_child_at_depth (ClutterActor *self,
10491 ClutterActor *child,
10492 gpointer dummy G_GNUC_UNUSED)
10494 ClutterActor *iter;
10497 child->priv->parent = self;
10500 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10502 /* special-case the first child */
10503 if (self->priv->n_children == 0)
10505 self->priv->first_child = child;
10506 self->priv->last_child = child;
10508 child->priv->next_sibling = NULL;
10509 child->priv->prev_sibling = NULL;
10514 /* Find the right place to insert the child so that it will still be
10515 sorted and the child will be after all of the actors at the same
10517 for (iter = self->priv->first_child;
10519 iter = iter->priv->next_sibling)
10524 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10526 if (iter_depth > child_depth)
10532 ClutterActor *tmp = iter->priv->prev_sibling;
10535 tmp->priv->next_sibling = child;
10537 /* Insert the node before the found one */
10538 child->priv->prev_sibling = iter->priv->prev_sibling;
10539 child->priv->next_sibling = iter;
10540 iter->priv->prev_sibling = child;
10544 ClutterActor *tmp = self->priv->last_child;
10547 tmp->priv->next_sibling = child;
10549 /* insert the node at the end of the list */
10550 child->priv->prev_sibling = self->priv->last_child;
10551 child->priv->next_sibling = NULL;
10554 if (child->priv->prev_sibling == NULL)
10555 self->priv->first_child = child;
10557 if (child->priv->next_sibling == NULL)
10558 self->priv->last_child = child;
10562 insert_child_at_index (ClutterActor *self,
10563 ClutterActor *child,
10566 gint index_ = GPOINTER_TO_INT (data_);
10568 child->priv->parent = self;
10572 ClutterActor *tmp = self->priv->first_child;
10575 tmp->priv->prev_sibling = child;
10577 child->priv->prev_sibling = NULL;
10578 child->priv->next_sibling = tmp;
10580 else if (index_ < 0 || index_ >= self->priv->n_children)
10582 ClutterActor *tmp = self->priv->last_child;
10585 tmp->priv->next_sibling = child;
10587 child->priv->prev_sibling = tmp;
10588 child->priv->next_sibling = NULL;
10592 ClutterActor *iter;
10595 for (iter = self->priv->first_child, i = 0;
10597 iter = iter->priv->next_sibling, i += 1)
10601 ClutterActor *tmp = iter->priv->prev_sibling;
10603 child->priv->prev_sibling = tmp;
10604 child->priv->next_sibling = iter;
10606 iter->priv->prev_sibling = child;
10609 tmp->priv->next_sibling = child;
10616 if (child->priv->prev_sibling == NULL)
10617 self->priv->first_child = child;
10619 if (child->priv->next_sibling == NULL)
10620 self->priv->last_child = child;
10624 insert_child_above (ClutterActor *self,
10625 ClutterActor *child,
10628 ClutterActor *sibling = data;
10630 child->priv->parent = self;
10632 if (sibling == NULL)
10633 sibling = self->priv->last_child;
10635 child->priv->prev_sibling = sibling;
10637 if (sibling != NULL)
10639 ClutterActor *tmp = sibling->priv->next_sibling;
10641 child->priv->next_sibling = tmp;
10644 tmp->priv->prev_sibling = child;
10646 sibling->priv->next_sibling = child;
10649 child->priv->next_sibling = NULL;
10651 if (child->priv->prev_sibling == NULL)
10652 self->priv->first_child = child;
10654 if (child->priv->next_sibling == NULL)
10655 self->priv->last_child = child;
10659 insert_child_below (ClutterActor *self,
10660 ClutterActor *child,
10663 ClutterActor *sibling = data;
10665 child->priv->parent = self;
10667 if (sibling == NULL)
10668 sibling = self->priv->first_child;
10670 child->priv->next_sibling = sibling;
10672 if (sibling != NULL)
10674 ClutterActor *tmp = sibling->priv->prev_sibling;
10676 child->priv->prev_sibling = tmp;
10679 tmp->priv->next_sibling = child;
10681 sibling->priv->prev_sibling = child;
10684 child->priv->prev_sibling = NULL;
10686 if (child->priv->prev_sibling == NULL)
10687 self->priv->first_child = child;
10689 if (child->priv->next_sibling == NULL)
10690 self->priv->last_child = child;
10693 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10694 ClutterActor *child,
10698 ADD_CHILD_CREATE_META = 1 << 0,
10699 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10700 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10701 ADD_CHILD_CHECK_STATE = 1 << 3,
10702 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10704 /* default flags for public API */
10705 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10706 ADD_CHILD_EMIT_PARENT_SET |
10707 ADD_CHILD_EMIT_ACTOR_ADDED |
10708 ADD_CHILD_CHECK_STATE |
10709 ADD_CHILD_NOTIFY_FIRST_LAST,
10711 /* flags for legacy/deprecated API */
10712 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10713 ADD_CHILD_CHECK_STATE |
10714 ADD_CHILD_NOTIFY_FIRST_LAST
10715 } ClutterActorAddChildFlags;
10718 * clutter_actor_add_child_internal:
10719 * @self: a #ClutterActor
10720 * @child: a #ClutterActor
10721 * @flags: control flags for actions
10722 * @add_func: delegate function
10723 * @data: (closure): data to pass to @add_func
10725 * Adds @child to the list of children of @self.
10727 * The actual insertion inside the list is delegated to @add_func: this
10728 * function will just set up the state, perform basic checks, and emit
10731 * The @flags argument is used to perform additional operations.
10734 clutter_actor_add_child_internal (ClutterActor *self,
10735 ClutterActor *child,
10736 ClutterActorAddChildFlags flags,
10737 ClutterActorAddChildFunc add_func,
10740 ClutterTextDirection text_dir;
10741 gboolean create_meta;
10742 gboolean emit_parent_set, emit_actor_added;
10743 gboolean check_state;
10744 gboolean notify_first_last;
10745 ClutterActor *old_first_child, *old_last_child;
10747 if (child->priv->parent != NULL)
10749 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10750 "use clutter_actor_remove_child() first.",
10751 _clutter_actor_get_debug_name (child),
10752 _clutter_actor_get_debug_name (child->priv->parent));
10756 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10758 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10759 "a child of another actor.",
10760 _clutter_actor_get_debug_name (child));
10765 /* XXX - this check disallows calling methods that change the stacking
10766 * order within the destruction sequence, by triggering a critical
10767 * warning first, and leaving the actor in an undefined state, which
10768 * then ends up being caught by an assertion.
10770 * the reproducible sequence is:
10772 * - actor gets destroyed;
10773 * - another actor, linked to the first, will try to change the
10774 * stacking order of the first actor;
10775 * - changing the stacking order is a composite operation composed
10776 * by the following steps:
10777 * 1. ref() the child;
10778 * 2. remove_child_internal(), which removes the reference;
10779 * 3. add_child_internal(), which adds a reference;
10780 * - the state of the actor is not changed between (2) and (3), as
10781 * it could be an expensive recomputation;
10782 * - if (3) bails out, then the actor is in an undefined state, but
10784 * - the destruction sequence terminates, but the actor is unparented
10785 * while its state indicates being parented instead.
10786 * - assertion failure.
10788 * the obvious fix would be to decompose each set_child_*_sibling()
10789 * method into proper remove_child()/add_child(), with state validation;
10790 * this may cause excessive work, though, and trigger a cascade of other
10791 * bugs in code that assumes that a change in the stacking order is an
10792 * atomic operation.
10794 * another potential fix is to just remove this check here, and let
10795 * code doing stacking order changes inside the destruction sequence
10796 * of an actor continue doing the work.
10798 * the third fix is to silently bail out early from every
10799 * set_child_*_sibling() and set_child_at_index() method, and avoid
10802 * I have a preference for the second solution, since it involves the
10803 * least amount of work, and the least amount of code duplication.
10805 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10807 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10809 g_warning ("The actor '%s' is currently being destroyed, and "
10810 "cannot be added as a child of another actor.",
10811 _clutter_actor_get_debug_name (child));
10816 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10817 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10818 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10819 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10820 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10822 old_first_child = self->priv->first_child;
10823 old_last_child = self->priv->last_child;
10825 g_object_freeze_notify (G_OBJECT (self));
10828 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10830 g_object_ref_sink (child);
10831 child->priv->parent = NULL;
10832 child->priv->next_sibling = NULL;
10833 child->priv->prev_sibling = NULL;
10835 /* delegate the actual insertion */
10836 add_func (self, child, data);
10838 g_assert (child->priv->parent == self);
10840 self->priv->n_children += 1;
10842 self->priv->age += 1;
10844 /* if push_internal() has been called then we automatically set
10845 * the flag on the actor
10847 if (self->priv->internal_child)
10848 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10850 /* clutter_actor_reparent() will emit ::parent-set for us */
10851 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10852 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10856 /* If parent is mapped or realized, we need to also be mapped or
10857 * realized once we're inside the parent.
10859 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10861 /* propagate the parent's text direction to the child */
10862 text_dir = clutter_actor_get_text_direction (self);
10863 clutter_actor_set_text_direction (child, text_dir);
10866 if (child->priv->show_on_set_parent)
10867 clutter_actor_show (child);
10869 if (CLUTTER_ACTOR_IS_MAPPED (child))
10870 clutter_actor_queue_redraw (child);
10872 /* maintain the invariant that if an actor needs layout,
10873 * its parents do as well
10875 if (child->priv->needs_width_request ||
10876 child->priv->needs_height_request ||
10877 child->priv->needs_allocation)
10879 /* we work around the short-circuiting we do
10880 * in clutter_actor_queue_relayout() since we
10881 * want to force a relayout
10883 child->priv->needs_width_request = TRUE;
10884 child->priv->needs_height_request = TRUE;
10885 child->priv->needs_allocation = TRUE;
10887 clutter_actor_queue_relayout (child->priv->parent);
10890 if (emit_actor_added)
10891 g_signal_emit_by_name (self, "actor-added", child);
10893 if (notify_first_last)
10895 if (old_first_child != self->priv->first_child)
10896 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10898 if (old_last_child != self->priv->last_child)
10899 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10902 g_object_thaw_notify (G_OBJECT (self));
10906 * clutter_actor_add_child:
10907 * @self: a #ClutterActor
10908 * @child: a #ClutterActor
10910 * Adds @child to the children of @self.
10912 * This function will acquire a reference on @child that will only
10913 * be released when calling clutter_actor_remove_child().
10915 * This function will take into consideration the #ClutterActor:depth
10916 * of @child, and will keep the list of children sorted.
10918 * This function will emit the #ClutterContainer::actor-added signal
10924 clutter_actor_add_child (ClutterActor *self,
10925 ClutterActor *child)
10927 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10928 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10929 g_return_if_fail (self != child);
10930 g_return_if_fail (child->priv->parent == NULL);
10932 clutter_actor_add_child_internal (self, child,
10933 ADD_CHILD_DEFAULT_FLAGS,
10934 insert_child_at_depth,
10939 * clutter_actor_insert_child_at_index:
10940 * @self: a #ClutterActor
10941 * @child: a #ClutterActor
10942 * @index_: the index
10944 * Inserts @child into the list of children of @self, using the
10945 * given @index_. If @index_ is greater than the number of children
10946 * in @self, or is less than 0, then the new child is added at the end.
10948 * This function will acquire a reference on @child that will only
10949 * be released when calling clutter_actor_remove_child().
10951 * This function will not take into consideration the #ClutterActor:depth
10954 * This function will emit the #ClutterContainer::actor-added signal
10960 clutter_actor_insert_child_at_index (ClutterActor *self,
10961 ClutterActor *child,
10964 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10965 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10966 g_return_if_fail (self != child);
10967 g_return_if_fail (child->priv->parent == NULL);
10969 clutter_actor_add_child_internal (self, child,
10970 ADD_CHILD_DEFAULT_FLAGS,
10971 insert_child_at_index,
10972 GINT_TO_POINTER (index_));
10976 * clutter_actor_insert_child_above:
10977 * @self: a #ClutterActor
10978 * @child: a #ClutterActor
10979 * @sibling: (allow-none): a child of @self, or %NULL
10981 * Inserts @child into the list of children of @self, above another
10982 * child of @self or, if @sibling is %NULL, above all the children
10985 * This function will acquire a reference on @child that will only
10986 * be released when calling clutter_actor_remove_child().
10988 * This function will not take into consideration the #ClutterActor:depth
10991 * This function will emit the #ClutterContainer::actor-added signal
10997 clutter_actor_insert_child_above (ClutterActor *self,
10998 ClutterActor *child,
10999 ClutterActor *sibling)
11001 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11002 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11003 g_return_if_fail (self != child);
11004 g_return_if_fail (child != sibling);
11005 g_return_if_fail (child->priv->parent == NULL);
11006 g_return_if_fail (sibling == NULL ||
11007 (CLUTTER_IS_ACTOR (sibling) &&
11008 sibling->priv->parent == self));
11010 clutter_actor_add_child_internal (self, child,
11011 ADD_CHILD_DEFAULT_FLAGS,
11012 insert_child_above,
11017 * clutter_actor_insert_child_below:
11018 * @self: a #ClutterActor
11019 * @child: a #ClutterActor
11020 * @sibling: (allow-none): a child of @self, or %NULL
11022 * Inserts @child into the list of children of @self, below another
11023 * child of @self or, if @sibling is %NULL, below all the children
11026 * This function will acquire a reference on @child that will only
11027 * be released when calling clutter_actor_remove_child().
11029 * This function will not take into consideration the #ClutterActor:depth
11032 * This function will emit the #ClutterContainer::actor-added signal
11038 clutter_actor_insert_child_below (ClutterActor *self,
11039 ClutterActor *child,
11040 ClutterActor *sibling)
11042 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11043 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11044 g_return_if_fail (self != child);
11045 g_return_if_fail (child != sibling);
11046 g_return_if_fail (child->priv->parent == NULL);
11047 g_return_if_fail (sibling == NULL ||
11048 (CLUTTER_IS_ACTOR (sibling) &&
11049 sibling->priv->parent == self));
11051 clutter_actor_add_child_internal (self, child,
11052 ADD_CHILD_DEFAULT_FLAGS,
11053 insert_child_below,
11058 * clutter_actor_set_parent:
11059 * @self: A #ClutterActor
11060 * @parent: A new #ClutterActor parent
11062 * Sets the parent of @self to @parent.
11064 * This function will result in @parent acquiring a reference on @self,
11065 * eventually by sinking its floating reference first. The reference
11066 * will be released by clutter_actor_unparent().
11068 * This function should only be called by legacy #ClutterActor<!-- -->s
11069 * implementing the #ClutterContainer interface.
11071 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11074 clutter_actor_set_parent (ClutterActor *self,
11075 ClutterActor *parent)
11077 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11078 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11079 g_return_if_fail (self != parent);
11080 g_return_if_fail (self->priv->parent == NULL);
11082 /* as this function will be called inside ClutterContainer::add
11083 * implementations or when building up a composite actor, we have
11084 * to preserve the old behaviour, and not create child meta or
11085 * emit the ::actor-added signal, to avoid recursion or double
11088 clutter_actor_add_child_internal (parent, self,
11089 ADD_CHILD_LEGACY_FLAGS,
11090 insert_child_at_depth,
11095 * clutter_actor_get_parent:
11096 * @self: A #ClutterActor
11098 * Retrieves the parent of @self.
11100 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11101 * if no parent is set
11104 clutter_actor_get_parent (ClutterActor *self)
11106 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11108 return self->priv->parent;
11112 * clutter_actor_get_paint_visibility:
11113 * @self: A #ClutterActor
11115 * Retrieves the 'paint' visibility of an actor recursively checking for non
11118 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11120 * Return Value: %TRUE if the actor is visibile and will be painted.
11125 clutter_actor_get_paint_visibility (ClutterActor *actor)
11127 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11129 return CLUTTER_ACTOR_IS_MAPPED (actor);
11133 * clutter_actor_remove_child:
11134 * @self: a #ClutterActor
11135 * @child: a #ClutterActor
11137 * Removes @child from the children of @self.
11139 * This function will release the reference added by
11140 * clutter_actor_add_child(), so if you want to keep using @child
11141 * you will have to acquire a referenced on it before calling this
11144 * This function will emit the #ClutterContainer::actor-removed
11150 clutter_actor_remove_child (ClutterActor *self,
11151 ClutterActor *child)
11153 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11154 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11155 g_return_if_fail (self != child);
11156 g_return_if_fail (child->priv->parent != NULL);
11157 g_return_if_fail (child->priv->parent == self);
11159 clutter_actor_remove_child_internal (self, child,
11160 REMOVE_CHILD_DEFAULT_FLAGS);
11164 * clutter_actor_remove_all_children:
11165 * @self: a #ClutterActor
11167 * Removes all children of @self.
11169 * This function releases the reference added by inserting a child actor
11170 * in the list of children of @self.
11172 * If the reference count of a child drops to zero, the child will be
11173 * destroyed. If you want to ensure the destruction of all the children
11174 * of @self, use clutter_actor_destroy_all_children().
11179 clutter_actor_remove_all_children (ClutterActor *self)
11181 ClutterActorIter iter;
11183 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11185 if (self->priv->n_children == 0)
11188 g_object_freeze_notify (G_OBJECT (self));
11190 clutter_actor_iter_init (&iter, self);
11191 while (clutter_actor_iter_next (&iter, NULL))
11192 clutter_actor_iter_remove (&iter);
11194 g_object_thaw_notify (G_OBJECT (self));
11197 g_assert (self->priv->first_child == NULL);
11198 g_assert (self->priv->last_child == NULL);
11199 g_assert (self->priv->n_children == 0);
11203 * clutter_actor_destroy_all_children:
11204 * @self: a #ClutterActor
11206 * Destroys all children of @self.
11208 * This function releases the reference added by inserting a child
11209 * actor in the list of children of @self, and ensures that the
11210 * #ClutterActor::destroy signal is emitted on each child of the
11213 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11214 * when its reference count drops to 0; the default handler of the
11215 * #ClutterActor::destroy signal will destroy all the children of an
11216 * actor. This function ensures that all children are destroyed, instead
11217 * of just removed from @self, unlike clutter_actor_remove_all_children()
11218 * which will merely release the reference and remove each child.
11220 * Unless you acquired an additional reference on each child of @self
11221 * prior to calling clutter_actor_remove_all_children() and want to reuse
11222 * the actors, you should use clutter_actor_destroy_all_children() in
11223 * order to make sure that children are destroyed and signal handlers
11224 * are disconnected even in cases where circular references prevent this
11225 * from automatically happening through reference counting alone.
11230 clutter_actor_destroy_all_children (ClutterActor *self)
11232 ClutterActorIter iter;
11234 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11236 if (self->priv->n_children == 0)
11239 g_object_freeze_notify (G_OBJECT (self));
11241 clutter_actor_iter_init (&iter, self);
11242 while (clutter_actor_iter_next (&iter, NULL))
11243 clutter_actor_iter_destroy (&iter);
11245 g_object_thaw_notify (G_OBJECT (self));
11248 g_assert (self->priv->first_child == NULL);
11249 g_assert (self->priv->last_child == NULL);
11250 g_assert (self->priv->n_children == 0);
11253 typedef struct _InsertBetweenData {
11254 ClutterActor *prev_sibling;
11255 ClutterActor *next_sibling;
11256 } InsertBetweenData;
11259 insert_child_between (ClutterActor *self,
11260 ClutterActor *child,
11263 InsertBetweenData *data = data_;
11264 ClutterActor *prev_sibling = data->prev_sibling;
11265 ClutterActor *next_sibling = data->next_sibling;
11267 child->priv->parent = self;
11268 child->priv->prev_sibling = prev_sibling;
11269 child->priv->next_sibling = next_sibling;
11271 if (prev_sibling != NULL)
11272 prev_sibling->priv->next_sibling = child;
11274 if (next_sibling != NULL)
11275 next_sibling->priv->prev_sibling = child;
11277 if (child->priv->prev_sibling == NULL)
11278 self->priv->first_child = child;
11280 if (child->priv->next_sibling == NULL)
11281 self->priv->last_child = child;
11285 * clutter_actor_replace_child:
11286 * @self: a #ClutterActor
11287 * @old_child: the child of @self to replace
11288 * @new_child: the #ClutterActor to replace @old_child
11290 * Replaces @old_child with @new_child in the list of children of @self.
11295 clutter_actor_replace_child (ClutterActor *self,
11296 ClutterActor *old_child,
11297 ClutterActor *new_child)
11299 ClutterActor *prev_sibling, *next_sibling;
11300 InsertBetweenData clos;
11302 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11303 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11304 g_return_if_fail (old_child->priv->parent == self);
11305 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11306 g_return_if_fail (old_child != new_child);
11307 g_return_if_fail (new_child != self);
11308 g_return_if_fail (new_child->priv->parent == NULL);
11310 prev_sibling = old_child->priv->prev_sibling;
11311 next_sibling = old_child->priv->next_sibling;
11312 clutter_actor_remove_child_internal (self, old_child,
11313 REMOVE_CHILD_DEFAULT_FLAGS);
11315 clos.prev_sibling = prev_sibling;
11316 clos.next_sibling = next_sibling;
11317 clutter_actor_add_child_internal (self, new_child,
11318 ADD_CHILD_DEFAULT_FLAGS,
11319 insert_child_between,
11324 * clutter_actor_unparent:
11325 * @self: a #ClutterActor
11327 * Removes the parent of @self.
11329 * This will cause the parent of @self to release the reference
11330 * acquired when calling clutter_actor_set_parent(), so if you
11331 * want to keep @self you will have to acquire a reference of
11332 * your own, through g_object_ref().
11334 * This function should only be called by legacy #ClutterActor<!-- -->s
11335 * implementing the #ClutterContainer interface.
11339 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11342 clutter_actor_unparent (ClutterActor *self)
11344 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11346 if (self->priv->parent == NULL)
11349 clutter_actor_remove_child_internal (self->priv->parent, self,
11350 REMOVE_CHILD_LEGACY_FLAGS);
11354 * clutter_actor_reparent:
11355 * @self: a #ClutterActor
11356 * @new_parent: the new #ClutterActor parent
11358 * Resets the parent actor of @self.
11360 * This function is logically equivalent to calling clutter_actor_unparent()
11361 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11362 * ensures the child is not finalized when unparented, and emits the
11363 * #ClutterActor::parent-set signal only once.
11365 * In reality, calling this function is less useful than it sounds, as some
11366 * application code may rely on changes in the intermediate state between
11367 * removal and addition of the actor from its old parent to the @new_parent.
11368 * Thus, it is strongly encouraged to avoid using this function in application
11373 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11374 * clutter_actor_add_child() instead; remember to take a reference on
11375 * the actor being removed before calling clutter_actor_remove_child()
11376 * to avoid the reference count dropping to zero and the actor being
11380 clutter_actor_reparent (ClutterActor *self,
11381 ClutterActor *new_parent)
11383 ClutterActorPrivate *priv;
11385 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11386 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11387 g_return_if_fail (self != new_parent);
11389 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11391 g_warning ("Cannot set a parent on a toplevel actor");
11395 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11397 g_warning ("Cannot set a parent currently being destroyed");
11403 if (priv->parent != new_parent)
11405 ClutterActor *old_parent;
11407 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11409 old_parent = priv->parent;
11411 g_object_ref (self);
11413 if (old_parent != NULL)
11415 /* go through the Container implementation if this is a regular
11416 * child and not an internal one
11418 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11420 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11422 /* this will have to call unparent() */
11423 clutter_container_remove_actor (parent, self);
11426 clutter_actor_remove_child_internal (old_parent, self,
11427 REMOVE_CHILD_LEGACY_FLAGS);
11430 /* Note, will call set_parent() */
11431 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11432 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11434 clutter_actor_add_child_internal (new_parent, self,
11435 ADD_CHILD_LEGACY_FLAGS,
11436 insert_child_at_depth,
11439 /* we emit the ::parent-set signal once */
11440 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11442 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11444 /* the IN_REPARENT flag suspends state updates */
11445 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11447 g_object_unref (self);
11452 * clutter_actor_contains:
11453 * @self: A #ClutterActor
11454 * @descendant: A #ClutterActor, possibly contained in @self
11456 * Determines if @descendant is contained inside @self (either as an
11457 * immediate child, or as a deeper descendant). If @self and
11458 * @descendant point to the same actor then it will also return %TRUE.
11460 * Return value: whether @descendent is contained within @self
11465 clutter_actor_contains (ClutterActor *self,
11466 ClutterActor *descendant)
11468 ClutterActor *actor;
11470 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11471 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11473 for (actor = descendant; actor; actor = actor->priv->parent)
11481 * clutter_actor_set_child_above_sibling:
11482 * @self: a #ClutterActor
11483 * @child: a #ClutterActor child of @self
11484 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11486 * Sets @child to be above @sibling in the list of children of @self.
11488 * If @sibling is %NULL, @child will be the new last child of @self.
11490 * This function is logically equivalent to removing @child and using
11491 * clutter_actor_insert_child_above(), but it will not emit signals
11492 * or change state on @child.
11497 clutter_actor_set_child_above_sibling (ClutterActor *self,
11498 ClutterActor *child,
11499 ClutterActor *sibling)
11501 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11502 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11503 g_return_if_fail (child->priv->parent == self);
11504 g_return_if_fail (child != sibling);
11505 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11507 if (sibling != NULL)
11508 g_return_if_fail (sibling->priv->parent == self);
11510 /* we don't want to change the state of child, or emit signals, or
11511 * regenerate ChildMeta instances here, but we still want to follow
11512 * the correct sequence of steps encoded in remove_child() and
11513 * add_child(), so that correctness is ensured, and we only go
11514 * through one known code path.
11516 g_object_ref (child);
11517 clutter_actor_remove_child_internal (self, child, 0);
11518 clutter_actor_add_child_internal (self, child,
11519 ADD_CHILD_NOTIFY_FIRST_LAST,
11520 insert_child_above,
11523 clutter_actor_queue_relayout (self);
11527 * clutter_actor_set_child_below_sibling:
11528 * @self: a #ClutterActor
11529 * @child: a #ClutterActor child of @self
11530 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11532 * Sets @child to be below @sibling in the list of children of @self.
11534 * If @sibling is %NULL, @child will be the new first child of @self.
11536 * This function is logically equivalent to removing @self and using
11537 * clutter_actor_insert_child_below(), but it will not emit signals
11538 * or change state on @child.
11543 clutter_actor_set_child_below_sibling (ClutterActor *self,
11544 ClutterActor *child,
11545 ClutterActor *sibling)
11547 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11548 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11549 g_return_if_fail (child->priv->parent == self);
11550 g_return_if_fail (child != sibling);
11551 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11553 if (sibling != NULL)
11554 g_return_if_fail (sibling->priv->parent == self);
11556 /* see the comment in set_child_above_sibling() */
11557 g_object_ref (child);
11558 clutter_actor_remove_child_internal (self, child, 0);
11559 clutter_actor_add_child_internal (self, child,
11560 ADD_CHILD_NOTIFY_FIRST_LAST,
11561 insert_child_below,
11564 clutter_actor_queue_relayout (self);
11568 * clutter_actor_set_child_at_index:
11569 * @self: a #ClutterActor
11570 * @child: a #ClutterActor child of @self
11571 * @index_: the new index for @child
11573 * Changes the index of @child in the list of children of @self.
11575 * This function is logically equivalent to removing @child and
11576 * calling clutter_actor_insert_child_at_index(), but it will not
11577 * emit signals or change state on @child.
11582 clutter_actor_set_child_at_index (ClutterActor *self,
11583 ClutterActor *child,
11586 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11587 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11588 g_return_if_fail (child->priv->parent == self);
11589 g_return_if_fail (index_ <= self->priv->n_children);
11591 g_object_ref (child);
11592 clutter_actor_remove_child_internal (self, child, 0);
11593 clutter_actor_add_child_internal (self, child,
11594 ADD_CHILD_NOTIFY_FIRST_LAST,
11595 insert_child_at_index,
11596 GINT_TO_POINTER (index_));
11598 clutter_actor_queue_relayout (self);
11602 * clutter_actor_raise:
11603 * @self: A #ClutterActor
11604 * @below: (allow-none): A #ClutterActor to raise above.
11606 * Puts @self above @below.
11608 * Both actors must have the same parent, and the parent must implement
11609 * the #ClutterContainer interface
11611 * This function calls clutter_container_raise_child() internally.
11613 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11616 clutter_actor_raise (ClutterActor *self,
11617 ClutterActor *below)
11619 ClutterActor *parent;
11621 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11623 parent = clutter_actor_get_parent (self);
11624 if (parent == NULL)
11626 g_warning ("%s: Actor '%s' is not inside a container",
11628 _clutter_actor_get_debug_name (self));
11634 if (parent != clutter_actor_get_parent (below))
11636 g_warning ("%s Actor '%s' is not in the same container as "
11639 _clutter_actor_get_debug_name (self),
11640 _clutter_actor_get_debug_name (below));
11645 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11649 * clutter_actor_lower:
11650 * @self: A #ClutterActor
11651 * @above: (allow-none): A #ClutterActor to lower below
11653 * Puts @self below @above.
11655 * Both actors must have the same parent, and the parent must implement
11656 * the #ClutterContainer interface.
11658 * This function calls clutter_container_lower_child() internally.
11660 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11663 clutter_actor_lower (ClutterActor *self,
11664 ClutterActor *above)
11666 ClutterActor *parent;
11668 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11670 parent = clutter_actor_get_parent (self);
11671 if (parent == NULL)
11673 g_warning ("%s: Actor of type %s is not inside a container",
11675 _clutter_actor_get_debug_name (self));
11681 if (parent != clutter_actor_get_parent (above))
11683 g_warning ("%s: Actor '%s' is not in the same container as "
11686 _clutter_actor_get_debug_name (self),
11687 _clutter_actor_get_debug_name (above));
11692 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11696 * clutter_actor_raise_top:
11697 * @self: A #ClutterActor
11699 * Raises @self to the top.
11701 * This function calls clutter_actor_raise() internally.
11703 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11704 * a %NULL sibling, instead.
11707 clutter_actor_raise_top (ClutterActor *self)
11709 clutter_actor_raise (self, NULL);
11713 * clutter_actor_lower_bottom:
11714 * @self: A #ClutterActor
11716 * Lowers @self to the bottom.
11718 * This function calls clutter_actor_lower() internally.
11720 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11721 * a %NULL sibling, instead.
11724 clutter_actor_lower_bottom (ClutterActor *self)
11726 clutter_actor_lower (self, NULL);
11734 * clutter_actor_event:
11735 * @actor: a #ClutterActor
11736 * @event: a #ClutterEvent
11737 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11739 * This function is used to emit an event on the main stage.
11740 * You should rarely need to use this function, except for
11741 * synthetising events.
11743 * Return value: the return value from the signal emission: %TRUE
11744 * if the actor handled the event, or %FALSE if the event was
11750 clutter_actor_event (ClutterActor *actor,
11751 ClutterEvent *event,
11754 gboolean retval = FALSE;
11755 gint signal_num = -1;
11757 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11758 g_return_val_if_fail (event != NULL, FALSE);
11760 g_object_ref (actor);
11764 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11770 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11774 switch (event->type)
11776 case CLUTTER_NOTHING:
11778 case CLUTTER_BUTTON_PRESS:
11779 signal_num = BUTTON_PRESS_EVENT;
11781 case CLUTTER_BUTTON_RELEASE:
11782 signal_num = BUTTON_RELEASE_EVENT;
11784 case CLUTTER_SCROLL:
11785 signal_num = SCROLL_EVENT;
11787 case CLUTTER_KEY_PRESS:
11788 signal_num = KEY_PRESS_EVENT;
11790 case CLUTTER_KEY_RELEASE:
11791 signal_num = KEY_RELEASE_EVENT;
11793 case CLUTTER_MOTION:
11794 signal_num = MOTION_EVENT;
11796 case CLUTTER_ENTER:
11797 signal_num = ENTER_EVENT;
11799 case CLUTTER_LEAVE:
11800 signal_num = LEAVE_EVENT;
11802 case CLUTTER_DELETE:
11803 case CLUTTER_DESTROY_NOTIFY:
11804 case CLUTTER_CLIENT_MESSAGE:
11810 if (signal_num != -1)
11811 g_signal_emit (actor, actor_signals[signal_num], 0,
11816 g_object_unref (actor);
11822 * clutter_actor_set_reactive:
11823 * @actor: a #ClutterActor
11824 * @reactive: whether the actor should be reactive to events
11826 * Sets @actor as reactive. Reactive actors will receive events.
11831 clutter_actor_set_reactive (ClutterActor *actor,
11834 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11836 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11840 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11842 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11844 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11848 * clutter_actor_get_reactive:
11849 * @actor: a #ClutterActor
11851 * Checks whether @actor is marked as reactive.
11853 * Return value: %TRUE if the actor is reactive
11858 clutter_actor_get_reactive (ClutterActor *actor)
11860 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11862 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11866 * clutter_actor_get_anchor_point:
11867 * @self: a #ClutterActor
11868 * @anchor_x: (out): return location for the X coordinate of the anchor point
11869 * @anchor_y: (out): return location for the Y coordinate of the anchor point
11871 * Gets the current anchor point of the @actor in pixels.
11876 clutter_actor_get_anchor_point (ClutterActor *self,
11880 const ClutterTransformInfo *info;
11882 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11884 info = _clutter_actor_get_transform_info_or_defaults (self);
11885 clutter_anchor_coord_get_units (self, &info->anchor,
11892 * clutter_actor_set_anchor_point:
11893 * @self: a #ClutterActor
11894 * @anchor_x: X coordinate of the anchor point
11895 * @anchor_y: Y coordinate of the anchor point
11897 * Sets an anchor point for @self. The anchor point is a point in the
11898 * coordinate space of an actor to which the actor position within its
11899 * parent is relative; the default is (0, 0), i.e. the top-left corner
11905 clutter_actor_set_anchor_point (ClutterActor *self,
11909 ClutterTransformInfo *info;
11910 ClutterActorPrivate *priv;
11911 gboolean changed = FALSE;
11912 gfloat old_anchor_x, old_anchor_y;
11915 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11917 obj = G_OBJECT (self);
11919 info = _clutter_actor_get_transform_info (self);
11921 g_object_freeze_notify (obj);
11923 clutter_anchor_coord_get_units (self, &info->anchor,
11928 if (info->anchor.is_fractional)
11929 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11931 if (old_anchor_x != anchor_x)
11933 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11937 if (old_anchor_y != anchor_y)
11939 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11943 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11947 priv->transform_valid = FALSE;
11948 clutter_actor_queue_redraw (self);
11951 g_object_thaw_notify (obj);
11955 * clutter_actor_get_anchor_point_gravity:
11956 * @self: a #ClutterActor
11958 * Retrieves the anchor position expressed as a #ClutterGravity. If
11959 * the anchor point was specified using pixels or units this will
11960 * return %CLUTTER_GRAVITY_NONE.
11962 * Return value: the #ClutterGravity used by the anchor point
11967 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11969 const ClutterTransformInfo *info;
11971 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11973 info = _clutter_actor_get_transform_info_or_defaults (self);
11975 return clutter_anchor_coord_get_gravity (&info->anchor);
11979 * clutter_actor_move_anchor_point:
11980 * @self: a #ClutterActor
11981 * @anchor_x: X coordinate of the anchor point
11982 * @anchor_y: Y coordinate of the anchor point
11984 * Sets an anchor point for the actor, and adjusts the actor postion so that
11985 * the relative position of the actor toward its parent remains the same.
11990 clutter_actor_move_anchor_point (ClutterActor *self,
11994 gfloat old_anchor_x, old_anchor_y;
11995 const ClutterTransformInfo *info;
11997 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11999 info = _clutter_actor_get_transform_info (self);
12000 clutter_anchor_coord_get_units (self, &info->anchor,
12005 g_object_freeze_notify (G_OBJECT (self));
12007 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12009 if (self->priv->position_set)
12010 clutter_actor_move_by (self,
12011 anchor_x - old_anchor_x,
12012 anchor_y - old_anchor_y);
12014 g_object_thaw_notify (G_OBJECT (self));
12018 * clutter_actor_move_anchor_point_from_gravity:
12019 * @self: a #ClutterActor
12020 * @gravity: #ClutterGravity.
12022 * Sets an anchor point on the actor based on the given gravity, adjusting the
12023 * actor postion so that its relative position within its parent remains
12026 * Since version 1.0 the anchor point will be stored as a gravity so
12027 * that if the actor changes size then the anchor point will move. For
12028 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12029 * and later double the size of the actor, the anchor point will move
12030 * to the bottom right.
12035 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12036 ClutterGravity gravity)
12038 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12039 const ClutterTransformInfo *info;
12040 ClutterActorPrivate *priv;
12042 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12045 info = _clutter_actor_get_transform_info (self);
12047 g_object_freeze_notify (G_OBJECT (self));
12049 clutter_anchor_coord_get_units (self, &info->anchor,
12053 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12054 clutter_anchor_coord_get_units (self, &info->anchor,
12059 if (priv->position_set)
12060 clutter_actor_move_by (self,
12061 new_anchor_x - old_anchor_x,
12062 new_anchor_y - old_anchor_y);
12064 g_object_thaw_notify (G_OBJECT (self));
12068 * clutter_actor_set_anchor_point_from_gravity:
12069 * @self: a #ClutterActor
12070 * @gravity: #ClutterGravity.
12072 * Sets an anchor point on the actor, based on the given gravity (this is a
12073 * convenience function wrapping clutter_actor_set_anchor_point()).
12075 * Since version 1.0 the anchor point will be stored as a gravity so
12076 * that if the actor changes size then the anchor point will move. For
12077 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12078 * and later double the size of the actor, the anchor point will move
12079 * to the bottom right.
12084 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12085 ClutterGravity gravity)
12087 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12089 if (gravity == CLUTTER_GRAVITY_NONE)
12090 clutter_actor_set_anchor_point (self, 0, 0);
12093 GObject *obj = G_OBJECT (self);
12094 ClutterTransformInfo *info;
12096 g_object_freeze_notify (obj);
12098 info = _clutter_actor_get_transform_info (self);
12099 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12101 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12102 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12103 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12105 self->priv->transform_valid = FALSE;
12107 clutter_actor_queue_redraw (self);
12109 g_object_thaw_notify (obj);
12114 clutter_container_iface_init (ClutterContainerIface *iface)
12116 /* we don't override anything, as ClutterContainer already has a default
12117 * implementation that we can use, and which calls into our own API.
12132 parse_units (ClutterActor *self,
12133 ParseDimension dimension,
12136 GValue value = { 0, };
12139 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12142 json_node_get_value (node, &value);
12144 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12146 retval = (gfloat) g_value_get_int64 (&value);
12148 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12150 retval = g_value_get_double (&value);
12152 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12154 ClutterUnits units;
12157 res = clutter_units_from_string (&units, g_value_get_string (&value));
12159 retval = clutter_units_to_pixels (&units);
12162 g_warning ("Invalid value '%s': integers, strings or floating point "
12163 "values can be used for the x, y, width and height "
12164 "properties. Valid modifiers for strings are 'px', 'mm', "
12166 g_value_get_string (&value));
12172 g_warning ("Invalid value of type '%s': integers, strings of floating "
12173 "point values can be used for the x, y, width, height "
12174 "anchor-x and anchor-y properties.",
12175 g_type_name (G_VALUE_TYPE (&value)));
12178 g_value_unset (&value);
12184 ClutterRotateAxis axis;
12193 static inline gboolean
12194 parse_rotation_array (ClutterActor *actor,
12196 RotationInfo *info)
12200 if (json_array_get_length (array) != 2)
12204 element = json_array_get_element (array, 0);
12205 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12206 info->angle = json_node_get_double (element);
12211 element = json_array_get_element (array, 1);
12212 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12214 JsonArray *center = json_node_get_array (element);
12216 if (json_array_get_length (center) != 2)
12219 switch (info->axis)
12221 case CLUTTER_X_AXIS:
12222 info->center_y = parse_units (actor, PARSE_Y,
12223 json_array_get_element (center, 0));
12224 info->center_z = parse_units (actor, PARSE_Y,
12225 json_array_get_element (center, 1));
12228 case CLUTTER_Y_AXIS:
12229 info->center_x = parse_units (actor, PARSE_X,
12230 json_array_get_element (center, 0));
12231 info->center_z = parse_units (actor, PARSE_X,
12232 json_array_get_element (center, 1));
12235 case CLUTTER_Z_AXIS:
12236 info->center_x = parse_units (actor, PARSE_X,
12237 json_array_get_element (center, 0));
12238 info->center_y = parse_units (actor, PARSE_Y,
12239 json_array_get_element (center, 1));
12248 parse_rotation (ClutterActor *actor,
12250 RotationInfo *info)
12254 gboolean retval = FALSE;
12256 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12258 g_warning ("Invalid node of type '%s' found, expecting an array",
12259 json_node_type_name (node));
12263 array = json_node_get_array (node);
12264 len = json_array_get_length (array);
12266 for (i = 0; i < len; i++)
12268 JsonNode *element = json_array_get_element (array, i);
12269 JsonObject *object;
12272 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12274 g_warning ("Invalid node of type '%s' found, expecting an object",
12275 json_node_type_name (element));
12279 object = json_node_get_object (element);
12281 if (json_object_has_member (object, "x-axis"))
12283 member = json_object_get_member (object, "x-axis");
12285 info->axis = CLUTTER_X_AXIS;
12287 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12289 info->angle = json_node_get_double (member);
12292 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12293 retval = parse_rotation_array (actor,
12294 json_node_get_array (member),
12299 else if (json_object_has_member (object, "y-axis"))
12301 member = json_object_get_member (object, "y-axis");
12303 info->axis = CLUTTER_Y_AXIS;
12305 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12307 info->angle = json_node_get_double (member);
12310 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12311 retval = parse_rotation_array (actor,
12312 json_node_get_array (member),
12317 else if (json_object_has_member (object, "z-axis"))
12319 member = json_object_get_member (object, "z-axis");
12321 info->axis = CLUTTER_Z_AXIS;
12323 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12325 info->angle = json_node_get_double (member);
12328 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12329 retval = parse_rotation_array (actor,
12330 json_node_get_array (member),
12341 parse_actor_metas (ClutterScript *script,
12342 ClutterActor *actor,
12345 GList *elements, *l;
12346 GSList *retval = NULL;
12348 if (!JSON_NODE_HOLDS_ARRAY (node))
12351 elements = json_array_get_elements (json_node_get_array (node));
12353 for (l = elements; l != NULL; l = l->next)
12355 JsonNode *element = l->data;
12356 const gchar *id_ = _clutter_script_get_id_from_node (element);
12359 if (id_ == NULL || *id_ == '\0')
12362 meta = clutter_script_get_object (script, id_);
12366 retval = g_slist_prepend (retval, meta);
12369 g_list_free (elements);
12371 return g_slist_reverse (retval);
12375 parse_behaviours (ClutterScript *script,
12376 ClutterActor *actor,
12379 GList *elements, *l;
12380 GSList *retval = NULL;
12382 if (!JSON_NODE_HOLDS_ARRAY (node))
12385 elements = json_array_get_elements (json_node_get_array (node));
12387 for (l = elements; l != NULL; l = l->next)
12389 JsonNode *element = l->data;
12390 const gchar *id_ = _clutter_script_get_id_from_node (element);
12391 GObject *behaviour;
12393 if (id_ == NULL || *id_ == '\0')
12396 behaviour = clutter_script_get_object (script, id_);
12397 if (behaviour == NULL)
12400 retval = g_slist_prepend (retval, behaviour);
12403 g_list_free (elements);
12405 return g_slist_reverse (retval);
12409 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12410 ClutterScript *script,
12415 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12416 gboolean retval = FALSE;
12418 if ((name[0] == 'x' && name[1] == '\0') ||
12419 (name[0] == 'y' && name[1] == '\0') ||
12420 (strcmp (name, "width") == 0) ||
12421 (strcmp (name, "height") == 0) ||
12422 (strcmp (name, "anchor_x") == 0) ||
12423 (strcmp (name, "anchor_y") == 0))
12425 ParseDimension dimension;
12428 if (name[0] == 'x')
12429 dimension = PARSE_X;
12430 else if (name[0] == 'y')
12431 dimension = PARSE_Y;
12432 else if (name[0] == 'w')
12433 dimension = PARSE_WIDTH;
12434 else if (name[0] == 'h')
12435 dimension = PARSE_HEIGHT;
12436 else if (name[0] == 'a' && name[7] == 'x')
12437 dimension = PARSE_ANCHOR_X;
12438 else if (name[0] == 'a' && name[7] == 'y')
12439 dimension = PARSE_ANCHOR_Y;
12443 units = parse_units (actor, dimension, node);
12445 /* convert back to pixels: all properties are pixel-based */
12446 g_value_init (value, G_TYPE_FLOAT);
12447 g_value_set_float (value, units);
12451 else if (strcmp (name, "rotation") == 0)
12453 RotationInfo *info;
12455 info = g_slice_new0 (RotationInfo);
12456 retval = parse_rotation (actor, node, info);
12460 g_value_init (value, G_TYPE_POINTER);
12461 g_value_set_pointer (value, info);
12464 g_slice_free (RotationInfo, info);
12466 else if (strcmp (name, "behaviours") == 0)
12470 #ifdef CLUTTER_ENABLE_DEBUG
12471 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12472 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12473 "and it should not be used in newly "
12474 "written ClutterScript definitions.");
12477 l = parse_behaviours (script, actor, node);
12479 g_value_init (value, G_TYPE_POINTER);
12480 g_value_set_pointer (value, l);
12484 else if (strcmp (name, "actions") == 0 ||
12485 strcmp (name, "constraints") == 0 ||
12486 strcmp (name, "effects") == 0)
12490 l = parse_actor_metas (script, actor, node);
12492 g_value_init (value, G_TYPE_POINTER);
12493 g_value_set_pointer (value, l);
12502 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12503 ClutterScript *script,
12505 const GValue *value)
12507 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12509 #ifdef CLUTTER_ENABLE_DEBUG
12510 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12512 gchar *tmp = g_strdup_value_contents (value);
12514 CLUTTER_NOTE (SCRIPT,
12515 "in ClutterActor::set_custom_property('%s') = %s",
12521 #endif /* CLUTTER_ENABLE_DEBUG */
12523 if (strcmp (name, "rotation") == 0)
12525 RotationInfo *info;
12527 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12530 info = g_value_get_pointer (value);
12532 clutter_actor_set_rotation (actor,
12533 info->axis, info->angle,
12538 g_slice_free (RotationInfo, info);
12543 if (strcmp (name, "behaviours") == 0)
12545 GSList *behaviours, *l;
12547 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12550 behaviours = g_value_get_pointer (value);
12551 for (l = behaviours; l != NULL; l = l->next)
12553 ClutterBehaviour *behaviour = l->data;
12555 clutter_behaviour_apply (behaviour, actor);
12558 g_slist_free (behaviours);
12563 if (strcmp (name, "actions") == 0 ||
12564 strcmp (name, "constraints") == 0 ||
12565 strcmp (name, "effects") == 0)
12569 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12572 metas = g_value_get_pointer (value);
12573 for (l = metas; l != NULL; l = l->next)
12575 if (name[0] == 'a')
12576 clutter_actor_add_action (actor, l->data);
12578 if (name[0] == 'c')
12579 clutter_actor_add_constraint (actor, l->data);
12581 if (name[0] == 'e')
12582 clutter_actor_add_effect (actor, l->data);
12585 g_slist_free (metas);
12590 g_object_set_property (G_OBJECT (scriptable), name, value);
12594 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12596 iface->parse_custom_node = clutter_actor_parse_custom_node;
12597 iface->set_custom_property = clutter_actor_set_custom_property;
12600 static ClutterActorMeta *
12601 get_meta_from_animation_property (ClutterActor *actor,
12605 ClutterActorPrivate *priv = actor->priv;
12606 ClutterActorMeta *meta = NULL;
12609 /* if this is not a special property, fall through */
12610 if (name[0] != '@')
12613 /* detect the properties named using the following spec:
12615 * @<section>.<meta-name>.<property-name>
12617 * where <section> can be one of the following:
12623 * and <meta-name> is the name set on a specific ActorMeta
12626 tokens = g_strsplit (name + 1, ".", -1);
12627 if (tokens == NULL || g_strv_length (tokens) != 3)
12629 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12631 g_strfreev (tokens);
12635 if (strcmp (tokens[0], "actions") == 0)
12636 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12638 if (strcmp (tokens[0], "constraints") == 0)
12639 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12641 if (strcmp (tokens[0], "effects") == 0)
12642 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12644 if (name_p != NULL)
12645 *name_p = g_strdup (tokens[2]);
12647 CLUTTER_NOTE (ANIMATION,
12648 "Looking for property '%s' of object '%s' in section '%s'",
12653 g_strfreev (tokens);
12658 static GParamSpec *
12659 clutter_actor_find_property (ClutterAnimatable *animatable,
12660 const gchar *property_name)
12662 ClutterActorMeta *meta = NULL;
12663 GObjectClass *klass = NULL;
12664 GParamSpec *pspec = NULL;
12665 gchar *p_name = NULL;
12667 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12673 klass = G_OBJECT_GET_CLASS (meta);
12675 pspec = g_object_class_find_property (klass, p_name);
12679 klass = G_OBJECT_GET_CLASS (animatable);
12681 pspec = g_object_class_find_property (klass, property_name);
12690 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12691 const gchar *property_name,
12694 ClutterActorMeta *meta = NULL;
12695 gchar *p_name = NULL;
12697 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12702 g_object_get_property (G_OBJECT (meta), p_name, initial);
12704 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12710 * clutter_actor_set_animatable_property:
12711 * @actor: a #ClutterActor
12712 * @prop_id: the paramspec id
12713 * @value: the value to set
12714 * @pspec: the paramspec
12716 * Sets values of animatable properties.
12718 * This is a variant of clutter_actor_set_property() that gets called
12719 * by the #ClutterAnimatable implementation of #ClutterActor for the
12720 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12723 * Unlike the implementation of #GObjectClass.set_property(), this
12724 * function will not update the interval if a transition involving an
12725 * animatable property is in progress - this avoids cycles with the
12726 * transition API calling the public API.
12729 clutter_actor_set_animatable_property (ClutterActor *actor,
12731 const GValue *value,
12737 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12741 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12745 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12749 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12753 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12757 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12760 case PROP_BACKGROUND_COLOR:
12761 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12765 clutter_actor_set_scale_factor_internal (actor,
12766 g_value_get_double (value),
12771 clutter_actor_set_scale_factor_internal (actor,
12772 g_value_get_double (value),
12776 case PROP_ROTATION_ANGLE_X:
12777 clutter_actor_set_rotation_angle_internal (actor,
12779 g_value_get_double (value));
12782 case PROP_ROTATION_ANGLE_Y:
12783 clutter_actor_set_rotation_angle_internal (actor,
12785 g_value_get_double (value));
12788 case PROP_ROTATION_ANGLE_Z:
12789 clutter_actor_set_rotation_angle_internal (actor,
12791 g_value_get_double (value));
12795 g_object_set_property (G_OBJECT (actor), pspec->name, value);
12801 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12802 const gchar *property_name,
12803 const GValue *final)
12805 ClutterActor *actor = CLUTTER_ACTOR (animatable);
12806 ClutterActorMeta *meta = NULL;
12807 gchar *p_name = NULL;
12809 meta = get_meta_from_animation_property (actor,
12813 g_object_set_property (G_OBJECT (meta), p_name, final);
12816 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12819 pspec = g_object_class_find_property (obj_class, property_name);
12821 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12823 /* XXX - I'm going to the special hell for this */
12824 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12827 g_object_set_property (G_OBJECT (animatable), property_name, final);
12834 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12836 iface->find_property = clutter_actor_find_property;
12837 iface->get_initial_state = clutter_actor_get_initial_state;
12838 iface->set_final_state = clutter_actor_set_final_state;
12842 * clutter_actor_transform_stage_point:
12843 * @self: A #ClutterActor
12844 * @x: (in): x screen coordinate of the point to unproject
12845 * @y: (in): y screen coordinate of the point to unproject
12846 * @x_out: (out): return location for the unprojected x coordinance
12847 * @y_out: (out): return location for the unprojected y coordinance
12849 * This function translates screen coordinates (@x, @y) to
12850 * coordinates relative to the actor. For example, it can be used to translate
12851 * screen events from global screen coordinates into actor-local coordinates.
12853 * The conversion can fail, notably if the transform stack results in the
12854 * actor being projected on the screen as a mere line.
12856 * The conversion should not be expected to be pixel-perfect due to the
12857 * nature of the operation. In general the error grows when the skewing
12858 * of the actor rectangle on screen increases.
12860 * <note><para>This function can be computationally intensive.</para></note>
12862 * <note><para>This function only works when the allocation is up-to-date,
12863 * i.e. inside of paint().</para></note>
12865 * Return value: %TRUE if conversion was successful.
12870 clutter_actor_transform_stage_point (ClutterActor *self,
12876 ClutterVertex v[4];
12879 int du, dv, xi, yi;
12881 float xf, yf, wf, det;
12882 ClutterActorPrivate *priv;
12884 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12888 /* This implementation is based on the quad -> quad projection algorithm
12889 * described by Paul Heckbert in:
12891 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12893 * and the sample implementation at:
12895 * http://www.cs.cmu.edu/~ph/src/texfund/
12897 * Our texture is a rectangle with origin [0, 0], so we are mapping from
12898 * quad to rectangle only, which significantly simplifies things; the
12899 * function calls have been unrolled, and most of the math is done in fixed
12903 clutter_actor_get_abs_allocation_vertices (self, v);
12905 /* Keeping these as ints simplifies the multiplication (no significant
12906 * loss of precision here).
12908 du = (int) (priv->allocation.x2 - priv->allocation.x1);
12909 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12914 #define UX2FP(x) (x)
12915 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12917 /* First, find mapping from unit uv square to xy quadrilateral; this
12918 * equivalent to the pmap_square_quad() functions in the sample
12919 * implementation, which we can simplify, since our target is always
12922 px = v[0].x - v[1].x + v[3].x - v[2].x;
12923 py = v[0].y - v[1].y + v[3].y - v[2].y;
12927 /* affine transform */
12928 RQ[0][0] = UX2FP (v[1].x - v[0].x);
12929 RQ[1][0] = UX2FP (v[3].x - v[1].x);
12930 RQ[2][0] = UX2FP (v[0].x);
12931 RQ[0][1] = UX2FP (v[1].y - v[0].y);
12932 RQ[1][1] = UX2FP (v[3].y - v[1].y);
12933 RQ[2][1] = UX2FP (v[0].y);
12940 /* projective transform */
12941 double dx1, dx2, dy1, dy2, del;
12943 dx1 = UX2FP (v[1].x - v[3].x);
12944 dx2 = UX2FP (v[2].x - v[3].x);
12945 dy1 = UX2FP (v[1].y - v[3].y);
12946 dy2 = UX2FP (v[2].y - v[3].y);
12948 del = DET2FP (dx1, dx2, dy1, dy2);
12953 * The division here needs to be done in floating point for
12954 * precisions reasons.
12956 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12957 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12958 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12960 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12961 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12962 RQ[2][0] = UX2FP (v[0].x);
12963 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12964 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12965 RQ[2][1] = UX2FP (v[0].y);
12969 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12970 * square. Since our rectangle is based at 0,0 we only need to scale.
12980 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12983 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12984 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12985 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12986 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12987 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12988 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12989 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12990 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12991 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12994 * Check the resulting matrix is OK.
12996 det = (RQ[0][0] * ST[0][0])
12997 + (RQ[0][1] * ST[0][1])
12998 + (RQ[0][2] * ST[0][2]);
13003 * Now transform our point with the ST matrix; the notional w
13004 * coordinate is 1, hence the last part is simply added.
13009 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13010 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13011 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13029 static ClutterGeometry*
13030 clutter_geometry_copy (const ClutterGeometry *geometry)
13032 return g_slice_dup (ClutterGeometry, geometry);
13036 clutter_geometry_free (ClutterGeometry *geometry)
13038 if (G_LIKELY (geometry != NULL))
13039 g_slice_free (ClutterGeometry, geometry);
13043 * clutter_geometry_union:
13044 * @geometry_a: a #ClutterGeometry
13045 * @geometry_b: another #ClutterGeometry
13046 * @result: (out): location to store the result
13048 * Find the union of two rectangles represented as #ClutterGeometry.
13053 clutter_geometry_union (const ClutterGeometry *geometry_a,
13054 const ClutterGeometry *geometry_b,
13055 ClutterGeometry *result)
13057 /* We don't try to handle rectangles that can't be represented
13058 * as a signed integer box */
13059 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13060 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13061 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13062 geometry_b->x + (gint)geometry_b->width);
13063 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13064 geometry_b->y + (gint)geometry_b->height);
13067 result->width = x_2 - x_1;
13068 result->height = y_2 - y_1;
13072 * clutter_geometry_intersects:
13073 * @geometry0: The first geometry to test
13074 * @geometry1: The second geometry to test
13076 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13077 * they do else %FALSE.
13079 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13085 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13086 const ClutterGeometry *geometry1)
13088 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13089 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13090 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13091 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13098 clutter_geometry_progress (const GValue *a,
13103 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13104 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13105 ClutterGeometry res = { 0, };
13106 gint a_width = a_geom->width;
13107 gint b_width = b_geom->width;
13108 gint a_height = a_geom->height;
13109 gint b_height = b_geom->height;
13111 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13112 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13114 res.width = a_width + (b_width - a_width) * progress;
13115 res.height = a_height + (b_height - a_height) * progress;
13117 g_value_set_boxed (retval, &res);
13122 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13123 clutter_geometry_copy,
13124 clutter_geometry_free,
13125 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13132 * clutter_vertex_new:
13137 * Creates a new #ClutterVertex for the point in 3D space
13138 * identified by the 3 coordinates @x, @y, @z
13140 * Return value: the newly allocate #ClutterVertex. Use
13141 * clutter_vertex_free() to free the resources
13146 clutter_vertex_new (gfloat x,
13150 ClutterVertex *vertex;
13152 vertex = g_slice_new (ClutterVertex);
13161 * clutter_vertex_copy:
13162 * @vertex: a #ClutterVertex
13166 * Return value: a newly allocated copy of #ClutterVertex. Use
13167 * clutter_vertex_free() to free the allocated resources
13172 clutter_vertex_copy (const ClutterVertex *vertex)
13174 if (G_LIKELY (vertex != NULL))
13175 return g_slice_dup (ClutterVertex, vertex);
13181 * clutter_vertex_free:
13182 * @vertex: a #ClutterVertex
13184 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13189 clutter_vertex_free (ClutterVertex *vertex)
13191 if (G_UNLIKELY (vertex != NULL))
13192 g_slice_free (ClutterVertex, vertex);
13196 * clutter_vertex_equal:
13197 * @vertex_a: a #ClutterVertex
13198 * @vertex_b: a #ClutterVertex
13200 * Compares @vertex_a and @vertex_b for equality
13202 * Return value: %TRUE if the passed #ClutterVertex are equal
13207 clutter_vertex_equal (const ClutterVertex *vertex_a,
13208 const ClutterVertex *vertex_b)
13210 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13212 if (vertex_a == vertex_b)
13215 return vertex_a->x == vertex_b->x &&
13216 vertex_a->y == vertex_b->y &&
13217 vertex_a->z == vertex_b->z;
13221 clutter_vertex_progress (const GValue *a,
13226 const ClutterVertex *av = g_value_get_boxed (a);
13227 const ClutterVertex *bv = g_value_get_boxed (b);
13228 ClutterVertex res = { 0, };
13230 res.x = av->x + (bv->x - av->x) * progress;
13231 res.y = av->y + (bv->y - av->y) * progress;
13232 res.z = av->z + (bv->z - av->z) * progress;
13234 g_value_set_boxed (retval, &res);
13239 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13240 clutter_vertex_copy,
13241 clutter_vertex_free,
13242 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13245 * clutter_actor_is_rotated:
13246 * @self: a #ClutterActor
13248 * Checks whether any rotation is applied to the actor.
13250 * Return value: %TRUE if the actor is rotated.
13255 clutter_actor_is_rotated (ClutterActor *self)
13257 const ClutterTransformInfo *info;
13259 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13261 info = _clutter_actor_get_transform_info_or_defaults (self);
13263 if (info->rx_angle || info->ry_angle || info->rz_angle)
13270 * clutter_actor_is_scaled:
13271 * @self: a #ClutterActor
13273 * Checks whether the actor is scaled in either dimension.
13275 * Return value: %TRUE if the actor is scaled.
13280 clutter_actor_is_scaled (ClutterActor *self)
13282 const ClutterTransformInfo *info;
13284 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13286 info = _clutter_actor_get_transform_info_or_defaults (self);
13288 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13295 _clutter_actor_get_stage_internal (ClutterActor *actor)
13297 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13298 actor = actor->priv->parent;
13304 * clutter_actor_get_stage:
13305 * @actor: a #ClutterActor
13307 * Retrieves the #ClutterStage where @actor is contained.
13309 * Return value: (transfer none) (type Clutter.Stage): the stage
13310 * containing the actor, or %NULL
13315 clutter_actor_get_stage (ClutterActor *actor)
13317 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13319 return _clutter_actor_get_stage_internal (actor);
13323 * clutter_actor_allocate_available_size:
13324 * @self: a #ClutterActor
13325 * @x: the actor's X coordinate
13326 * @y: the actor's Y coordinate
13327 * @available_width: the maximum available width, or -1 to use the
13328 * actor's natural width
13329 * @available_height: the maximum available height, or -1 to use the
13330 * actor's natural height
13331 * @flags: flags controlling the allocation
13333 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13334 * preferred size, but limiting it to the maximum available width
13335 * and height provided.
13337 * This function will do the right thing when dealing with the
13338 * actor's request mode.
13340 * The implementation of this function is equivalent to:
13343 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13345 * clutter_actor_get_preferred_width (self, available_height,
13347 * &natural_width);
13348 * width = CLAMP (natural_width, min_width, available_width);
13350 * clutter_actor_get_preferred_height (self, width,
13352 * &natural_height);
13353 * height = CLAMP (natural_height, min_height, available_height);
13357 * clutter_actor_get_preferred_height (self, available_width,
13359 * &natural_height);
13360 * height = CLAMP (natural_height, min_height, available_height);
13362 * clutter_actor_get_preferred_width (self, height,
13364 * &natural_width);
13365 * width = CLAMP (natural_width, min_width, available_width);
13368 * box.x1 = x; box.y1 = y;
13369 * box.x2 = box.x1 + available_width;
13370 * box.y2 = box.y1 + available_height;
13371 * clutter_actor_allocate (self, &box, flags);
13374 * This function can be used by fluid layout managers to allocate
13375 * an actor's preferred size without making it bigger than the area
13376 * available for the container.
13381 clutter_actor_allocate_available_size (ClutterActor *self,
13384 gfloat available_width,
13385 gfloat available_height,
13386 ClutterAllocationFlags flags)
13388 ClutterActorPrivate *priv;
13389 gfloat width, height;
13390 gfloat min_width, min_height;
13391 gfloat natural_width, natural_height;
13392 ClutterActorBox box;
13394 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13398 width = height = 0.0;
13400 switch (priv->request_mode)
13402 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13403 clutter_actor_get_preferred_width (self, available_height,
13406 width = CLAMP (natural_width, min_width, available_width);
13408 clutter_actor_get_preferred_height (self, width,
13411 height = CLAMP (natural_height, min_height, available_height);
13414 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13415 clutter_actor_get_preferred_height (self, available_width,
13418 height = CLAMP (natural_height, min_height, available_height);
13420 clutter_actor_get_preferred_width (self, height,
13423 width = CLAMP (natural_width, min_width, available_width);
13430 box.x2 = box.x1 + width;
13431 box.y2 = box.y1 + height;
13432 clutter_actor_allocate (self, &box, flags);
13436 * clutter_actor_allocate_preferred_size:
13437 * @self: a #ClutterActor
13438 * @flags: flags controlling the allocation
13440 * Allocates the natural size of @self.
13442 * This function is a utility call for #ClutterActor implementations
13443 * that allocates the actor's preferred natural size. It can be used
13444 * by fixed layout managers (like #ClutterGroup or so called
13445 * 'composite actors') inside the ClutterActor::allocate
13446 * implementation to give each child exactly how much space it
13449 * This function is not meant to be used by applications. It is also
13450 * not meant to be used outside the implementation of the
13451 * ClutterActor::allocate virtual function.
13456 clutter_actor_allocate_preferred_size (ClutterActor *self,
13457 ClutterAllocationFlags flags)
13459 gfloat actor_x, actor_y;
13460 gfloat natural_width, natural_height;
13461 ClutterActorBox actor_box;
13463 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13465 actor_x = clutter_actor_get_x (self);
13466 actor_y = clutter_actor_get_y (self);
13468 clutter_actor_get_preferred_size (self,
13473 actor_box.x1 = actor_x;
13474 actor_box.y1 = actor_y;
13475 actor_box.x2 = actor_box.x1 + natural_width;
13476 actor_box.y2 = actor_box.y1 + natural_height;
13478 clutter_actor_allocate (self, &actor_box, flags);
13482 * clutter_actor_allocate_align_fill:
13483 * @self: a #ClutterActor
13484 * @box: a #ClutterActorBox, containing the available width and height
13485 * @x_align: the horizontal alignment, between 0 and 1
13486 * @y_align: the vertical alignment, between 0 and 1
13487 * @x_fill: whether the actor should fill horizontally
13488 * @y_fill: whether the actor should fill vertically
13489 * @flags: allocation flags to be passed to clutter_actor_allocate()
13491 * Allocates @self by taking into consideration the available allocation
13492 * area; an alignment factor on either axis; and whether the actor should
13493 * fill the allocation on either axis.
13495 * The @box should contain the available allocation width and height;
13496 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13497 * allocation will be offset by their value.
13499 * This function takes into consideration the geometry request specified by
13500 * the #ClutterActor:request-mode property, and the text direction.
13502 * This function is useful for fluid layout managers, like #ClutterBinLayout
13503 * or #ClutterTableLayout
13508 clutter_actor_allocate_align_fill (ClutterActor *self,
13509 const ClutterActorBox *box,
13514 ClutterAllocationFlags flags)
13516 ClutterActorPrivate *priv;
13517 ClutterActorBox allocation = { 0, };
13518 gfloat x_offset, y_offset;
13519 gfloat available_width, available_height;
13520 gfloat child_width, child_height;
13522 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13523 g_return_if_fail (box != NULL);
13524 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13525 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13529 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13530 clutter_actor_box_get_size (box, &available_width, &available_height);
13532 if (available_width < 0)
13533 available_width = 0;
13535 if (available_height < 0)
13536 available_height = 0;
13540 allocation.x1 = x_offset;
13541 allocation.x2 = allocation.x1 + available_width;
13546 allocation.y1 = y_offset;
13547 allocation.y2 = allocation.y1 + available_height;
13550 /* if we are filling horizontally and vertically then we're done */
13551 if (x_fill && y_fill)
13554 child_width = child_height = 0.0f;
13556 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13558 gfloat min_width, natural_width;
13559 gfloat min_height, natural_height;
13561 clutter_actor_get_preferred_width (self, available_height,
13565 child_width = CLAMP (natural_width, min_width, available_width);
13569 clutter_actor_get_preferred_height (self, child_width,
13573 child_height = CLAMP (natural_height, min_height, available_height);
13578 gfloat min_width, natural_width;
13579 gfloat min_height, natural_height;
13581 clutter_actor_get_preferred_height (self, available_width,
13585 child_height = CLAMP (natural_height, min_height, available_height);
13589 clutter_actor_get_preferred_width (self, child_height,
13593 child_width = CLAMP (natural_width, min_width, available_width);
13597 /* invert the horizontal alignment for RTL languages */
13598 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13599 x_align = 1.0 - x_align;
13603 allocation.x1 = x_offset
13604 + ((available_width - child_width) * x_align);
13605 allocation.x2 = allocation.x1 + child_width;
13610 allocation.y1 = y_offset
13611 + ((available_height - child_height) * y_align);
13612 allocation.y2 = allocation.y1 + child_height;
13616 clutter_actor_box_clamp_to_pixel (&allocation);
13617 clutter_actor_allocate (self, &allocation, flags);
13621 * clutter_actor_grab_key_focus:
13622 * @self: a #ClutterActor
13624 * Sets the key focus of the #ClutterStage including @self
13625 * to this #ClutterActor.
13630 clutter_actor_grab_key_focus (ClutterActor *self)
13632 ClutterActor *stage;
13634 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13636 stage = _clutter_actor_get_stage_internal (self);
13638 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13642 * clutter_actor_get_pango_context:
13643 * @self: a #ClutterActor
13645 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13646 * is already configured using the appropriate font map, resolution
13647 * and font options.
13649 * Unlike clutter_actor_create_pango_context(), this context is owend
13650 * by the #ClutterActor and it will be updated each time the options
13651 * stored by the #ClutterBackend change.
13653 * You can use the returned #PangoContext to create a #PangoLayout
13654 * and render text using cogl_pango_render_layout() to reuse the
13655 * glyphs cache also used by Clutter.
13657 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13658 * The returned #PangoContext is owned by the actor and should not be
13659 * unreferenced by the application code
13664 clutter_actor_get_pango_context (ClutterActor *self)
13666 ClutterActorPrivate *priv;
13668 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13672 if (priv->pango_context != NULL)
13673 return priv->pango_context;
13675 priv->pango_context = _clutter_context_get_pango_context ();
13676 g_object_ref (priv->pango_context);
13678 return priv->pango_context;
13682 * clutter_actor_create_pango_context:
13683 * @self: a #ClutterActor
13685 * Creates a #PangoContext for the given actor. The #PangoContext
13686 * is already configured using the appropriate font map, resolution
13687 * and font options.
13689 * See also clutter_actor_get_pango_context().
13691 * Return value: (transfer full): the newly created #PangoContext.
13692 * Use g_object_unref() on the returned value to deallocate its
13698 clutter_actor_create_pango_context (ClutterActor *self)
13700 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13702 return _clutter_context_create_pango_context ();
13706 * clutter_actor_create_pango_layout:
13707 * @self: a #ClutterActor
13708 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13710 * Creates a new #PangoLayout from the same #PangoContext used
13711 * by the #ClutterActor. The #PangoLayout is already configured
13712 * with the font map, resolution and font options, and the
13715 * If you want to keep around a #PangoLayout created by this
13716 * function you will have to connect to the #ClutterBackend::font-changed
13717 * and #ClutterBackend::resolution-changed signals, and call
13718 * pango_layout_context_changed() in response to them.
13720 * Return value: (transfer full): the newly created #PangoLayout.
13721 * Use g_object_unref() when done
13726 clutter_actor_create_pango_layout (ClutterActor *self,
13729 PangoContext *context;
13730 PangoLayout *layout;
13732 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13734 context = clutter_actor_get_pango_context (self);
13735 layout = pango_layout_new (context);
13738 pango_layout_set_text (layout, text, -1);
13743 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13744 * ClutterOffscreenEffect.
13747 _clutter_actor_set_opacity_override (ClutterActor *self,
13750 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13752 self->priv->opacity_override = opacity;
13756 _clutter_actor_get_opacity_override (ClutterActor *self)
13758 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13760 return self->priv->opacity_override;
13763 /* Allows you to disable applying the actors model view transform during
13764 * a paint. Used by ClutterClone. */
13766 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13769 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13771 self->priv->enable_model_view_transform = enable;
13775 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13778 ClutterActorPrivate *priv;
13780 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13784 priv->enable_paint_unmapped = enable;
13786 if (priv->enable_paint_unmapped)
13788 /* Make sure that the parents of the widget are realized first;
13789 * otherwise checks in clutter_actor_update_map_state() will
13792 clutter_actor_realize (self);
13794 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13798 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13803 clutter_anchor_coord_get_units (ClutterActor *self,
13804 const AnchorCoord *coord,
13809 if (coord->is_fractional)
13811 gfloat actor_width, actor_height;
13813 clutter_actor_get_size (self, &actor_width, &actor_height);
13816 *x = actor_width * coord->v.fraction.x;
13819 *y = actor_height * coord->v.fraction.y;
13827 *x = coord->v.units.x;
13830 *y = coord->v.units.y;
13833 *z = coord->v.units.z;
13838 clutter_anchor_coord_set_units (AnchorCoord *coord,
13843 coord->is_fractional = FALSE;
13844 coord->v.units.x = x;
13845 coord->v.units.y = y;
13846 coord->v.units.z = z;
13849 static ClutterGravity
13850 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13852 if (coord->is_fractional)
13854 if (coord->v.fraction.x == 0.0)
13856 if (coord->v.fraction.y == 0.0)
13857 return CLUTTER_GRAVITY_NORTH_WEST;
13858 else if (coord->v.fraction.y == 0.5)
13859 return CLUTTER_GRAVITY_WEST;
13860 else if (coord->v.fraction.y == 1.0)
13861 return CLUTTER_GRAVITY_SOUTH_WEST;
13863 return CLUTTER_GRAVITY_NONE;
13865 else if (coord->v.fraction.x == 0.5)
13867 if (coord->v.fraction.y == 0.0)
13868 return CLUTTER_GRAVITY_NORTH;
13869 else if (coord->v.fraction.y == 0.5)
13870 return CLUTTER_GRAVITY_CENTER;
13871 else if (coord->v.fraction.y == 1.0)
13872 return CLUTTER_GRAVITY_SOUTH;
13874 return CLUTTER_GRAVITY_NONE;
13876 else if (coord->v.fraction.x == 1.0)
13878 if (coord->v.fraction.y == 0.0)
13879 return CLUTTER_GRAVITY_NORTH_EAST;
13880 else if (coord->v.fraction.y == 0.5)
13881 return CLUTTER_GRAVITY_EAST;
13882 else if (coord->v.fraction.y == 1.0)
13883 return CLUTTER_GRAVITY_SOUTH_EAST;
13885 return CLUTTER_GRAVITY_NONE;
13888 return CLUTTER_GRAVITY_NONE;
13891 return CLUTTER_GRAVITY_NONE;
13895 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
13896 ClutterGravity gravity)
13900 case CLUTTER_GRAVITY_NORTH:
13901 coord->v.fraction.x = 0.5;
13902 coord->v.fraction.y = 0.0;
13905 case CLUTTER_GRAVITY_NORTH_EAST:
13906 coord->v.fraction.x = 1.0;
13907 coord->v.fraction.y = 0.0;
13910 case CLUTTER_GRAVITY_EAST:
13911 coord->v.fraction.x = 1.0;
13912 coord->v.fraction.y = 0.5;
13915 case CLUTTER_GRAVITY_SOUTH_EAST:
13916 coord->v.fraction.x = 1.0;
13917 coord->v.fraction.y = 1.0;
13920 case CLUTTER_GRAVITY_SOUTH:
13921 coord->v.fraction.x = 0.5;
13922 coord->v.fraction.y = 1.0;
13925 case CLUTTER_GRAVITY_SOUTH_WEST:
13926 coord->v.fraction.x = 0.0;
13927 coord->v.fraction.y = 1.0;
13930 case CLUTTER_GRAVITY_WEST:
13931 coord->v.fraction.x = 0.0;
13932 coord->v.fraction.y = 0.5;
13935 case CLUTTER_GRAVITY_NORTH_WEST:
13936 coord->v.fraction.x = 0.0;
13937 coord->v.fraction.y = 0.0;
13940 case CLUTTER_GRAVITY_CENTER:
13941 coord->v.fraction.x = 0.5;
13942 coord->v.fraction.y = 0.5;
13946 coord->v.fraction.x = 0.0;
13947 coord->v.fraction.y = 0.0;
13951 coord->is_fractional = TRUE;
13955 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13957 if (coord->is_fractional)
13958 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13960 return (coord->v.units.x == 0.0
13961 && coord->v.units.y == 0.0
13962 && coord->v.units.z == 0.0);
13966 * clutter_actor_get_flags:
13967 * @self: a #ClutterActor
13969 * Retrieves the flags set on @self
13971 * Return value: a bitwise or of #ClutterActorFlags or 0
13976 clutter_actor_get_flags (ClutterActor *self)
13978 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13980 return self->flags;
13984 * clutter_actor_set_flags:
13985 * @self: a #ClutterActor
13986 * @flags: the flags to set
13988 * Sets @flags on @self
13990 * This function will emit notifications for the changed properties
13995 clutter_actor_set_flags (ClutterActor *self,
13996 ClutterActorFlags flags)
13998 ClutterActorFlags old_flags;
14000 gboolean was_reactive_set, reactive_set;
14001 gboolean was_realized_set, realized_set;
14002 gboolean was_mapped_set, mapped_set;
14003 gboolean was_visible_set, visible_set;
14005 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14007 if (self->flags == flags)
14010 obj = G_OBJECT (self);
14011 g_object_ref (obj);
14012 g_object_freeze_notify (obj);
14014 old_flags = self->flags;
14016 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14017 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14018 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14019 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14021 self->flags |= flags;
14023 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14024 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14025 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14026 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14028 if (reactive_set != was_reactive_set)
14029 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14031 if (realized_set != was_realized_set)
14032 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14034 if (mapped_set != was_mapped_set)
14035 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14037 if (visible_set != was_visible_set)
14038 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14040 g_object_thaw_notify (obj);
14041 g_object_unref (obj);
14045 * clutter_actor_unset_flags:
14046 * @self: a #ClutterActor
14047 * @flags: the flags to unset
14049 * Unsets @flags on @self
14051 * This function will emit notifications for the changed properties
14056 clutter_actor_unset_flags (ClutterActor *self,
14057 ClutterActorFlags flags)
14059 ClutterActorFlags old_flags;
14061 gboolean was_reactive_set, reactive_set;
14062 gboolean was_realized_set, realized_set;
14063 gboolean was_mapped_set, mapped_set;
14064 gboolean was_visible_set, visible_set;
14066 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14068 obj = G_OBJECT (self);
14069 g_object_freeze_notify (obj);
14071 old_flags = self->flags;
14073 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14074 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14075 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14076 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14078 self->flags &= ~flags;
14080 if (self->flags == old_flags)
14083 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14084 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14085 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14086 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14088 if (reactive_set != was_reactive_set)
14089 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14091 if (realized_set != was_realized_set)
14092 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14094 if (mapped_set != was_mapped_set)
14095 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14097 if (visible_set != was_visible_set)
14098 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14100 g_object_thaw_notify (obj);
14104 * clutter_actor_get_transformation_matrix:
14105 * @self: a #ClutterActor
14106 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14108 * Retrieves the transformations applied to @self relative to its
14114 clutter_actor_get_transformation_matrix (ClutterActor *self,
14115 CoglMatrix *matrix)
14117 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14119 cogl_matrix_init_identity (matrix);
14121 _clutter_actor_apply_modelview_transform (self, matrix);
14125 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14126 gboolean is_in_clone_paint)
14128 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14129 self->priv->in_clone_paint = is_in_clone_paint;
14133 * clutter_actor_is_in_clone_paint:
14134 * @self: a #ClutterActor
14136 * Checks whether @self is being currently painted by a #ClutterClone
14138 * This function is useful only inside the ::paint virtual function
14139 * implementations or within handlers for the #ClutterActor::paint
14142 * This function should not be used by applications
14144 * Return value: %TRUE if the #ClutterActor is currently being painted
14145 * by a #ClutterClone, and %FALSE otherwise
14150 clutter_actor_is_in_clone_paint (ClutterActor *self)
14152 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14154 return self->priv->in_clone_paint;
14158 set_direction_recursive (ClutterActor *actor,
14159 gpointer user_data)
14161 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14163 clutter_actor_set_text_direction (actor, text_dir);
14169 * clutter_actor_set_text_direction:
14170 * @self: a #ClutterActor
14171 * @text_dir: the text direction for @self
14173 * Sets the #ClutterTextDirection for an actor
14175 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14177 * If @self implements #ClutterContainer then this function will recurse
14178 * inside all the children of @self (including the internal ones).
14180 * Composite actors not implementing #ClutterContainer, or actors requiring
14181 * special handling when the text direction changes, should connect to
14182 * the #GObject::notify signal for the #ClutterActor:text-direction property
14187 clutter_actor_set_text_direction (ClutterActor *self,
14188 ClutterTextDirection text_dir)
14190 ClutterActorPrivate *priv;
14192 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14193 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14197 if (priv->text_direction != text_dir)
14199 priv->text_direction = text_dir;
14201 /* we need to emit the notify::text-direction first, so that
14202 * the sub-classes can catch that and do specific handling of
14203 * the text direction; see clutter_text_direction_changed_cb()
14204 * inside clutter-text.c
14206 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14208 _clutter_actor_foreach_child (self, set_direction_recursive,
14209 GINT_TO_POINTER (text_dir));
14211 clutter_actor_queue_relayout (self);
14216 _clutter_actor_set_has_pointer (ClutterActor *self,
14217 gboolean has_pointer)
14219 ClutterActorPrivate *priv = self->priv;
14221 if (priv->has_pointer != has_pointer)
14223 priv->has_pointer = has_pointer;
14225 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14230 * clutter_actor_get_text_direction:
14231 * @self: a #ClutterActor
14233 * Retrieves the value set using clutter_actor_set_text_direction()
14235 * If no text direction has been previously set, the default text
14236 * direction, as returned by clutter_get_default_text_direction(), will
14237 * be returned instead
14239 * Return value: the #ClutterTextDirection for the actor
14243 ClutterTextDirection
14244 clutter_actor_get_text_direction (ClutterActor *self)
14246 ClutterActorPrivate *priv;
14248 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14249 CLUTTER_TEXT_DIRECTION_LTR);
14253 /* if no direction has been set yet use the default */
14254 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14255 priv->text_direction = clutter_get_default_text_direction ();
14257 return priv->text_direction;
14261 * clutter_actor_push_internal:
14262 * @self: a #ClutterActor
14264 * Should be used by actors implementing the #ClutterContainer and with
14265 * internal children added through clutter_actor_set_parent(), for instance:
14269 * my_actor_init (MyActor *self)
14271 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14273 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14275 * /* calling clutter_actor_set_parent() now will result in
14276 * * the internal flag being set on a child of MyActor
14279 * /* internal child - a background texture */
14280 * self->priv->background_tex = clutter_texture_new ();
14281 * clutter_actor_set_parent (self->priv->background_tex,
14282 * CLUTTER_ACTOR (self));
14284 * /* internal child - a label */
14285 * self->priv->label = clutter_text_new ();
14286 * clutter_actor_set_parent (self->priv->label,
14287 * CLUTTER_ACTOR (self));
14289 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14291 * /* calling clutter_actor_set_parent() now will not result in
14292 * * the internal flag being set on a child of MyActor
14297 * This function will be used by Clutter to toggle an "internal child"
14298 * flag whenever clutter_actor_set_parent() is called; internal children
14299 * are handled differently by Clutter, specifically when destroying their
14302 * Call clutter_actor_pop_internal() when you finished adding internal
14305 * Nested calls to clutter_actor_push_internal() are allowed, but each
14306 * one must by followed by a clutter_actor_pop_internal() call.
14310 * Deprecated: 1.10: All children of an actor are accessible through
14311 * the #ClutterActor API, and #ClutterActor implements the
14312 * #ClutterContainer interface, so this function is only useful
14313 * for legacy containers overriding the default implementation.
14316 clutter_actor_push_internal (ClutterActor *self)
14318 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14320 self->priv->internal_child += 1;
14324 * clutter_actor_pop_internal:
14325 * @self: a #ClutterActor
14327 * Disables the effects of clutter_actor_push_internal().
14331 * Deprecated: 1.10: All children of an actor are accessible through
14332 * the #ClutterActor API. This function is only useful for legacy
14333 * containers overriding the default implementation of the
14334 * #ClutterContainer interface.
14337 clutter_actor_pop_internal (ClutterActor *self)
14339 ClutterActorPrivate *priv;
14341 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14345 if (priv->internal_child == 0)
14347 g_warning ("Mismatched %s: you need to call "
14348 "clutter_actor_push_composite() at least once before "
14349 "calling this function", G_STRFUNC);
14353 priv->internal_child -= 1;
14357 * clutter_actor_has_pointer:
14358 * @self: a #ClutterActor
14360 * Checks whether an actor contains the pointer of a
14361 * #ClutterInputDevice
14363 * Return value: %TRUE if the actor contains the pointer, and
14369 clutter_actor_has_pointer (ClutterActor *self)
14371 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14373 return self->priv->has_pointer;
14376 /* XXX: This is a workaround for not being able to break the ABI of
14377 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14378 * clutter_actor_queue_clipped_redraw() for details.
14380 ClutterPaintVolume *
14381 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14383 return g_object_get_data (G_OBJECT (self),
14384 "-clutter-actor-queue-redraw-clip");
14388 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14389 ClutterPaintVolume *clip)
14391 g_object_set_data (G_OBJECT (self),
14392 "-clutter-actor-queue-redraw-clip",
14397 * clutter_actor_has_allocation:
14398 * @self: a #ClutterActor
14400 * Checks if the actor has an up-to-date allocation assigned to
14401 * it. This means that the actor should have an allocation: it's
14402 * visible and has a parent. It also means that there is no
14403 * outstanding relayout request in progress for the actor or its
14404 * children (There might be other outstanding layout requests in
14405 * progress that will cause the actor to get a new allocation
14406 * when the stage is laid out, however).
14408 * If this function returns %FALSE, then the actor will normally
14409 * be allocated before it is next drawn on the screen.
14411 * Return value: %TRUE if the actor has an up-to-date allocation
14416 clutter_actor_has_allocation (ClutterActor *self)
14418 ClutterActorPrivate *priv;
14420 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14424 return priv->parent != NULL &&
14425 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14426 !priv->needs_allocation;
14430 * clutter_actor_add_action:
14431 * @self: a #ClutterActor
14432 * @action: a #ClutterAction
14434 * Adds @action to the list of actions applied to @self
14436 * A #ClutterAction can only belong to one actor at a time
14438 * The #ClutterActor will hold a reference on @action until either
14439 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14445 clutter_actor_add_action (ClutterActor *self,
14446 ClutterAction *action)
14448 ClutterActorPrivate *priv;
14450 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14451 g_return_if_fail (CLUTTER_IS_ACTION (action));
14455 if (priv->actions == NULL)
14457 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14458 priv->actions->actor = self;
14461 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14463 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14467 * clutter_actor_add_action_with_name:
14468 * @self: a #ClutterActor
14469 * @name: the name to set on the action
14470 * @action: a #ClutterAction
14472 * A convenience function for setting the name of a #ClutterAction
14473 * while adding it to the list of actions applied to @self
14475 * This function is the logical equivalent of:
14478 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14479 * clutter_actor_add_action (self, action);
14485 clutter_actor_add_action_with_name (ClutterActor *self,
14487 ClutterAction *action)
14489 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14490 g_return_if_fail (name != NULL);
14491 g_return_if_fail (CLUTTER_IS_ACTION (action));
14493 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14494 clutter_actor_add_action (self, action);
14498 * clutter_actor_remove_action:
14499 * @self: a #ClutterActor
14500 * @action: a #ClutterAction
14502 * Removes @action from the list of actions applied to @self
14504 * The reference held by @self on the #ClutterAction will be released
14509 clutter_actor_remove_action (ClutterActor *self,
14510 ClutterAction *action)
14512 ClutterActorPrivate *priv;
14514 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14515 g_return_if_fail (CLUTTER_IS_ACTION (action));
14519 if (priv->actions == NULL)
14522 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14524 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14528 * clutter_actor_remove_action_by_name:
14529 * @self: a #ClutterActor
14530 * @name: the name of the action to remove
14532 * Removes the #ClutterAction with the given name from the list
14533 * of actions applied to @self
14538 clutter_actor_remove_action_by_name (ClutterActor *self,
14541 ClutterActorPrivate *priv;
14542 ClutterActorMeta *meta;
14544 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14545 g_return_if_fail (name != NULL);
14549 if (priv->actions == NULL)
14552 meta = _clutter_meta_group_get_meta (priv->actions, name);
14556 _clutter_meta_group_remove_meta (priv->actions, meta);
14558 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14562 * clutter_actor_get_actions:
14563 * @self: a #ClutterActor
14565 * Retrieves the list of actions applied to @self
14567 * Return value: (transfer container) (element-type Clutter.Action): a copy
14568 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14569 * owned by the #ClutterActor. Use g_list_free() to free the resources
14570 * allocated by the returned #GList
14575 clutter_actor_get_actions (ClutterActor *self)
14577 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14579 if (self->priv->actions == NULL)
14582 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14586 * clutter_actor_get_action:
14587 * @self: a #ClutterActor
14588 * @name: the name of the action to retrieve
14590 * Retrieves the #ClutterAction with the given name in the list
14591 * of actions applied to @self
14593 * Return value: (transfer none): a #ClutterAction for the given
14594 * name, or %NULL. The returned #ClutterAction is owned by the
14595 * actor and it should not be unreferenced directly
14600 clutter_actor_get_action (ClutterActor *self,
14603 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14604 g_return_val_if_fail (name != NULL, NULL);
14606 if (self->priv->actions == NULL)
14609 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14613 * clutter_actor_clear_actions:
14614 * @self: a #ClutterActor
14616 * Clears the list of actions applied to @self
14621 clutter_actor_clear_actions (ClutterActor *self)
14623 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14625 if (self->priv->actions == NULL)
14628 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14632 * clutter_actor_add_constraint:
14633 * @self: a #ClutterActor
14634 * @constraint: a #ClutterConstraint
14636 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14639 * The #ClutterActor will hold a reference on the @constraint until
14640 * either clutter_actor_remove_constraint() or
14641 * clutter_actor_clear_constraints() is called.
14646 clutter_actor_add_constraint (ClutterActor *self,
14647 ClutterConstraint *constraint)
14649 ClutterActorPrivate *priv;
14651 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14652 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14656 if (priv->constraints == NULL)
14658 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14659 priv->constraints->actor = self;
14662 _clutter_meta_group_add_meta (priv->constraints,
14663 CLUTTER_ACTOR_META (constraint));
14664 clutter_actor_queue_relayout (self);
14666 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14670 * clutter_actor_add_constraint_with_name:
14671 * @self: a #ClutterActor
14672 * @name: the name to set on the constraint
14673 * @constraint: a #ClutterConstraint
14675 * A convenience function for setting the name of a #ClutterConstraint
14676 * while adding it to the list of constraints applied to @self
14678 * This function is the logical equivalent of:
14681 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14682 * clutter_actor_add_constraint (self, constraint);
14688 clutter_actor_add_constraint_with_name (ClutterActor *self,
14690 ClutterConstraint *constraint)
14692 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14693 g_return_if_fail (name != NULL);
14694 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14696 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14697 clutter_actor_add_constraint (self, constraint);
14701 * clutter_actor_remove_constraint:
14702 * @self: a #ClutterActor
14703 * @constraint: a #ClutterConstraint
14705 * Removes @constraint from the list of constraints applied to @self
14707 * The reference held by @self on the #ClutterConstraint will be released
14712 clutter_actor_remove_constraint (ClutterActor *self,
14713 ClutterConstraint *constraint)
14715 ClutterActorPrivate *priv;
14717 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14718 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14722 if (priv->constraints == NULL)
14725 _clutter_meta_group_remove_meta (priv->constraints,
14726 CLUTTER_ACTOR_META (constraint));
14727 clutter_actor_queue_relayout (self);
14729 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14733 * clutter_actor_remove_constraint_by_name:
14734 * @self: a #ClutterActor
14735 * @name: the name of the constraint to remove
14737 * Removes the #ClutterConstraint with the given name from the list
14738 * of constraints applied to @self
14743 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14746 ClutterActorPrivate *priv;
14747 ClutterActorMeta *meta;
14749 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14750 g_return_if_fail (name != NULL);
14754 if (priv->constraints == NULL)
14757 meta = _clutter_meta_group_get_meta (priv->constraints, name);
14761 _clutter_meta_group_remove_meta (priv->constraints, meta);
14762 clutter_actor_queue_relayout (self);
14766 * clutter_actor_get_constraints:
14767 * @self: a #ClutterActor
14769 * Retrieves the list of constraints applied to @self
14771 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14772 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14773 * owned by the #ClutterActor. Use g_list_free() to free the resources
14774 * allocated by the returned #GList
14779 clutter_actor_get_constraints (ClutterActor *self)
14781 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14783 if (self->priv->constraints == NULL)
14786 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14790 * clutter_actor_get_constraint:
14791 * @self: a #ClutterActor
14792 * @name: the name of the constraint to retrieve
14794 * Retrieves the #ClutterConstraint with the given name in the list
14795 * of constraints applied to @self
14797 * Return value: (transfer none): a #ClutterConstraint for the given
14798 * name, or %NULL. The returned #ClutterConstraint is owned by the
14799 * actor and it should not be unreferenced directly
14803 ClutterConstraint *
14804 clutter_actor_get_constraint (ClutterActor *self,
14807 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14808 g_return_val_if_fail (name != NULL, NULL);
14810 if (self->priv->constraints == NULL)
14813 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14817 * clutter_actor_clear_constraints:
14818 * @self: a #ClutterActor
14820 * Clears the list of constraints applied to @self
14825 clutter_actor_clear_constraints (ClutterActor *self)
14827 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14829 if (self->priv->constraints == NULL)
14832 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14834 clutter_actor_queue_relayout (self);
14838 * clutter_actor_set_clip_to_allocation:
14839 * @self: a #ClutterActor
14840 * @clip_set: %TRUE to apply a clip tracking the allocation
14842 * Sets whether @self should be clipped to the same size as its
14848 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14851 ClutterActorPrivate *priv;
14853 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14855 clip_set = !!clip_set;
14859 if (priv->clip_to_allocation != clip_set)
14861 priv->clip_to_allocation = clip_set;
14863 clutter_actor_queue_redraw (self);
14865 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14870 * clutter_actor_get_clip_to_allocation:
14871 * @self: a #ClutterActor
14873 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14875 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14880 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14882 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14884 return self->priv->clip_to_allocation;
14888 * clutter_actor_add_effect:
14889 * @self: a #ClutterActor
14890 * @effect: a #ClutterEffect
14892 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14894 * The #ClutterActor will hold a reference on the @effect until either
14895 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14901 clutter_actor_add_effect (ClutterActor *self,
14902 ClutterEffect *effect)
14904 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14905 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14907 _clutter_actor_add_effect_internal (self, effect);
14909 clutter_actor_queue_redraw (self);
14911 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14915 * clutter_actor_add_effect_with_name:
14916 * @self: a #ClutterActor
14917 * @name: the name to set on the effect
14918 * @effect: a #ClutterEffect
14920 * A convenience function for setting the name of a #ClutterEffect
14921 * while adding it to the list of effectss applied to @self
14923 * This function is the logical equivalent of:
14926 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14927 * clutter_actor_add_effect (self, effect);
14933 clutter_actor_add_effect_with_name (ClutterActor *self,
14935 ClutterEffect *effect)
14937 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14938 g_return_if_fail (name != NULL);
14939 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14941 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14942 clutter_actor_add_effect (self, effect);
14946 * clutter_actor_remove_effect:
14947 * @self: a #ClutterActor
14948 * @effect: a #ClutterEffect
14950 * Removes @effect from the list of effects applied to @self
14952 * The reference held by @self on the #ClutterEffect will be released
14957 clutter_actor_remove_effect (ClutterActor *self,
14958 ClutterEffect *effect)
14960 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14961 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14963 _clutter_actor_remove_effect_internal (self, effect);
14965 clutter_actor_queue_redraw (self);
14967 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14971 * clutter_actor_remove_effect_by_name:
14972 * @self: a #ClutterActor
14973 * @name: the name of the effect to remove
14975 * Removes the #ClutterEffect with the given name from the list
14976 * of effects applied to @self
14981 clutter_actor_remove_effect_by_name (ClutterActor *self,
14984 ClutterActorPrivate *priv;
14985 ClutterActorMeta *meta;
14987 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14988 g_return_if_fail (name != NULL);
14992 if (priv->effects == NULL)
14995 meta = _clutter_meta_group_get_meta (priv->effects, name);
14999 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15003 * clutter_actor_get_effects:
15004 * @self: a #ClutterActor
15006 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15008 * Return value: (transfer container) (element-type Clutter.Effect): a list
15009 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15010 * list are owned by Clutter and they should not be freed. You should
15011 * free the returned list using g_list_free() when done
15016 clutter_actor_get_effects (ClutterActor *self)
15018 ClutterActorPrivate *priv;
15020 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15024 if (priv->effects == NULL)
15027 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15031 * clutter_actor_get_effect:
15032 * @self: a #ClutterActor
15033 * @name: the name of the effect to retrieve
15035 * Retrieves the #ClutterEffect with the given name in the list
15036 * of effects applied to @self
15038 * Return value: (transfer none): a #ClutterEffect for the given
15039 * name, or %NULL. The returned #ClutterEffect is owned by the
15040 * actor and it should not be unreferenced directly
15045 clutter_actor_get_effect (ClutterActor *self,
15048 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15049 g_return_val_if_fail (name != NULL, NULL);
15051 if (self->priv->effects == NULL)
15054 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15058 * clutter_actor_clear_effects:
15059 * @self: a #ClutterActor
15061 * Clears the list of effects applied to @self
15066 clutter_actor_clear_effects (ClutterActor *self)
15068 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15070 if (self->priv->effects == NULL)
15073 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15075 clutter_actor_queue_redraw (self);
15079 * clutter_actor_has_key_focus:
15080 * @self: a #ClutterActor
15082 * Checks whether @self is the #ClutterActor that has key focus
15084 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15089 clutter_actor_has_key_focus (ClutterActor *self)
15091 ClutterActor *stage;
15093 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15095 stage = _clutter_actor_get_stage_internal (self);
15099 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15103 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15104 ClutterPaintVolume *pv)
15106 ClutterActorPrivate *priv = self->priv;
15108 /* Actors are only expected to report a valid paint volume
15109 * while they have a valid allocation. */
15110 if (G_UNLIKELY (priv->needs_allocation))
15112 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15113 "Actor needs allocation",
15114 _clutter_actor_get_debug_name (self));
15118 /* Check if there are any handlers connected to the paint
15119 * signal. If there are then all bets are off for what the paint
15120 * volume for this actor might possibly be!
15122 * XXX: It's expected that this is going to end up being quite a
15123 * costly check to have to do here, but we haven't come up with
15124 * another solution that can reliably catch paint signal handlers at
15125 * the right time to either avoid artefacts due to invalid stage
15126 * clipping or due to incorrect culling.
15128 * Previously we checked in clutter_actor_paint(), but at that time
15129 * we may already be using a stage clip that could be derived from
15130 * an invalid paint-volume. We used to try and handle that by
15131 * queuing a follow up, unclipped, redraw but still the previous
15132 * checking wasn't enough to catch invalid volumes involved in
15133 * culling (considering that containers may derive their volume from
15134 * children that haven't yet been painted)
15136 * Longer term, improved solutions could be:
15137 * - Disallow painting in the paint signal, only allow using it
15138 * for tracking when paints happen. We can add another API that
15139 * allows monkey patching the paint of arbitrary actors but in a
15140 * more controlled way and that also supports modifying the
15142 * - If we could be notified somehow when signal handlers are
15143 * connected we wouldn't have to poll for handlers like this.
15145 if (g_signal_has_handler_pending (self,
15146 actor_signals[PAINT],
15150 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15151 "Actor has \"paint\" signal handlers",
15152 _clutter_actor_get_debug_name (self));
15156 _clutter_paint_volume_init_static (pv, self);
15158 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15160 clutter_paint_volume_free (pv);
15161 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15162 "Actor failed to report a volume",
15163 _clutter_actor_get_debug_name (self));
15167 /* since effects can modify the paint volume, we allow them to actually
15168 * do this by making get_paint_volume() "context sensitive"
15170 if (priv->effects != NULL)
15172 if (priv->current_effect != NULL)
15174 const GList *effects, *l;
15176 /* if we are being called from within the paint sequence of
15177 * an actor, get the paint volume up to the current effect
15179 effects = _clutter_meta_group_peek_metas (priv->effects);
15181 l != NULL || (l != NULL && l->data != priv->current_effect);
15184 if (!_clutter_effect_get_paint_volume (l->data, pv))
15186 clutter_paint_volume_free (pv);
15187 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15188 "Effect (%s) failed to report a volume",
15189 _clutter_actor_get_debug_name (self),
15190 _clutter_actor_meta_get_debug_name (l->data));
15197 const GList *effects, *l;
15199 /* otherwise, get the cumulative volume */
15200 effects = _clutter_meta_group_peek_metas (priv->effects);
15201 for (l = effects; l != NULL; l = l->next)
15202 if (!_clutter_effect_get_paint_volume (l->data, pv))
15204 clutter_paint_volume_free (pv);
15205 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15206 "Effect (%s) failed to report a volume",
15207 _clutter_actor_get_debug_name (self),
15208 _clutter_actor_meta_get_debug_name (l->data));
15217 /* The public clutter_actor_get_paint_volume API returns a const
15218 * pointer since we return a pointer directly to the cached
15219 * PaintVolume associated with the actor and don't want the user to
15220 * inadvertently modify it, but for internal uses we sometimes need
15221 * access to the same PaintVolume but need to apply some book-keeping
15222 * modifications to it so we don't want a const pointer.
15224 static ClutterPaintVolume *
15225 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15227 ClutterActorPrivate *priv;
15231 if (priv->paint_volume_valid)
15232 clutter_paint_volume_free (&priv->paint_volume);
15234 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15236 priv->paint_volume_valid = TRUE;
15237 return &priv->paint_volume;
15241 priv->paint_volume_valid = FALSE;
15247 * clutter_actor_get_paint_volume:
15248 * @self: a #ClutterActor
15250 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15251 * when a paint volume can't be determined.
15253 * The paint volume is defined as the 3D space occupied by an actor
15254 * when being painted.
15256 * This function will call the <function>get_paint_volume()</function>
15257 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15258 * should not usually care about overriding the default implementation,
15259 * unless they are, for instance: painting outside their allocation, or
15260 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15263 * <note>2D actors overriding <function>get_paint_volume()</function>
15264 * ensure their volume has a depth of 0. (This will be true so long as
15265 * you don't call clutter_paint_volume_set_depth().)</note>
15267 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15268 * or %NULL if no volume could be determined. The returned pointer
15269 * is not guaranteed to be valid across multiple frames; if you want
15270 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15274 const ClutterPaintVolume *
15275 clutter_actor_get_paint_volume (ClutterActor *self)
15277 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15279 return _clutter_actor_get_paint_volume_mutable (self);
15283 * clutter_actor_get_transformed_paint_volume:
15284 * @self: a #ClutterActor
15285 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15286 * (or %NULL for the stage)
15288 * Retrieves the 3D paint volume of an actor like
15289 * clutter_actor_get_paint_volume() does (Please refer to the
15290 * documentation of clutter_actor_get_paint_volume() for more
15291 * details.) and it additionally transforms the paint volume into the
15292 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15293 * is passed for @relative_to_ancestor)
15295 * This can be used by containers that base their paint volume on
15296 * the volume of their children. Such containers can query the
15297 * transformed paint volume of all of its children and union them
15298 * together using clutter_paint_volume_union().
15300 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15301 * or %NULL if no volume could be determined. The returned pointer is
15302 * not guaranteed to be valid across multiple frames; if you wish to
15303 * keep it, you will have to copy it using clutter_paint_volume_copy().
15307 const ClutterPaintVolume *
15308 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15309 ClutterActor *relative_to_ancestor)
15311 const ClutterPaintVolume *volume;
15312 ClutterActor *stage;
15313 ClutterPaintVolume *transformed_volume;
15315 stage = _clutter_actor_get_stage_internal (self);
15316 if (G_UNLIKELY (stage == NULL))
15319 if (relative_to_ancestor == NULL)
15320 relative_to_ancestor = stage;
15322 volume = clutter_actor_get_paint_volume (self);
15323 if (volume == NULL)
15326 transformed_volume =
15327 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15329 _clutter_paint_volume_copy_static (volume, transformed_volume);
15331 _clutter_paint_volume_transform_relative (transformed_volume,
15332 relative_to_ancestor);
15334 return transformed_volume;
15338 * clutter_actor_get_paint_box:
15339 * @self: a #ClutterActor
15340 * @box: (out): return location for a #ClutterActorBox
15342 * Retrieves the paint volume of the passed #ClutterActor, and
15343 * transforms it into a 2D bounding box in stage coordinates.
15345 * This function is useful to determine the on screen area occupied by
15346 * the actor. The box is only an approximation and may often be
15347 * considerably larger due to the optimizations used to calculate the
15348 * box. The box is never smaller though, so it can reliably be used
15351 * There are times when a 2D paint box can't be determined, e.g.
15352 * because the actor isn't yet parented under a stage or because
15353 * the actor is unable to determine a paint volume.
15355 * Return value: %TRUE if a 2D paint box could be determined, else
15361 clutter_actor_get_paint_box (ClutterActor *self,
15362 ClutterActorBox *box)
15364 ClutterActor *stage;
15365 ClutterPaintVolume *pv;
15367 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15368 g_return_val_if_fail (box != NULL, FALSE);
15370 stage = _clutter_actor_get_stage_internal (self);
15371 if (G_UNLIKELY (!stage))
15374 pv = _clutter_actor_get_paint_volume_mutable (self);
15375 if (G_UNLIKELY (!pv))
15378 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15384 * clutter_actor_has_overlaps:
15385 * @self: A #ClutterActor
15387 * Asks the actor's implementation whether it may contain overlapping
15390 * For example; Clutter may use this to determine whether the painting
15391 * should be redirected to an offscreen buffer to correctly implement
15392 * the opacity property.
15394 * Custom actors can override the default response by implementing the
15395 * #ClutterActor <function>has_overlaps</function> virtual function. See
15396 * clutter_actor_set_offscreen_redirect() for more information.
15398 * Return value: %TRUE if the actor may have overlapping primitives, and
15404 clutter_actor_has_overlaps (ClutterActor *self)
15406 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15408 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15412 * clutter_actor_has_effects:
15413 * @self: A #ClutterActor
15415 * Returns whether the actor has any effects applied.
15417 * Return value: %TRUE if the actor has any effects,
15423 clutter_actor_has_effects (ClutterActor *self)
15425 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15427 if (self->priv->effects == NULL)
15430 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15434 * clutter_actor_has_constraints:
15435 * @self: A #ClutterActor
15437 * Returns whether the actor has any constraints applied.
15439 * Return value: %TRUE if the actor has any constraints,
15445 clutter_actor_has_constraints (ClutterActor *self)
15447 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15449 return self->priv->constraints != NULL;
15453 * clutter_actor_has_actions:
15454 * @self: A #ClutterActor
15456 * Returns whether the actor has any actions applied.
15458 * Return value: %TRUE if the actor has any actions,
15464 clutter_actor_has_actions (ClutterActor *self)
15466 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15468 return self->priv->actions != NULL;
15472 * clutter_actor_get_n_children:
15473 * @self: a #ClutterActor
15475 * Retrieves the number of children of @self.
15477 * Return value: the number of children of an actor
15482 clutter_actor_get_n_children (ClutterActor *self)
15484 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15486 return self->priv->n_children;
15490 * clutter_actor_get_child_at_index:
15491 * @self: a #ClutterActor
15492 * @index_: the position in the list of children
15494 * Retrieves the actor at the given @index_ inside the list of
15495 * children of @self.
15497 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15502 clutter_actor_get_child_at_index (ClutterActor *self,
15505 ClutterActor *iter;
15508 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15509 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15511 for (iter = self->priv->first_child, i = 0;
15512 iter != NULL && i < index_;
15513 iter = iter->priv->next_sibling, i += 1)
15520 * _clutter_actor_foreach_child:
15521 * @actor: The actor whos children you want to iterate
15522 * @callback: The function to call for each child
15523 * @user_data: Private data to pass to @callback
15525 * Calls a given @callback once for each child of the specified @actor and
15526 * passing the @user_data pointer each time.
15528 * Return value: returns %TRUE if all children were iterated, else
15529 * %FALSE if a callback broke out of iteration early.
15532 _clutter_actor_foreach_child (ClutterActor *self,
15533 ClutterForeachCallback callback,
15534 gpointer user_data)
15536 ClutterActorPrivate *priv = self->priv;
15537 ClutterActor *iter;
15540 for (cont = TRUE, iter = priv->first_child;
15541 cont && iter != NULL;
15542 iter = iter->priv->next_sibling)
15544 cont = callback (iter, user_data);
15551 /* For debugging purposes this gives us a simple way to print out
15552 * the scenegraph e.g in gdb using:
15554 * _clutter_actor_traverse (stage,
15556 * clutter_debug_print_actor_cb,
15561 static ClutterActorTraverseVisitFlags
15562 clutter_debug_print_actor_cb (ClutterActor *actor,
15566 g_print ("%*s%s:%p\n",
15568 _clutter_actor_get_debug_name (actor),
15571 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15576 _clutter_actor_traverse_breadth (ClutterActor *actor,
15577 ClutterTraverseCallback callback,
15578 gpointer user_data)
15580 GQueue *queue = g_queue_new ();
15581 ClutterActor dummy;
15582 int current_depth = 0;
15584 g_queue_push_tail (queue, actor);
15585 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15587 while ((actor = g_queue_pop_head (queue)))
15589 ClutterActorTraverseVisitFlags flags;
15591 if (actor == &dummy)
15594 g_queue_push_tail (queue, &dummy);
15598 flags = callback (actor, current_depth, user_data);
15599 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15601 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15603 ClutterActor *iter;
15605 for (iter = actor->priv->first_child;
15607 iter = iter->priv->next_sibling)
15609 g_queue_push_tail (queue, iter);
15614 g_queue_free (queue);
15617 static ClutterActorTraverseVisitFlags
15618 _clutter_actor_traverse_depth (ClutterActor *actor,
15619 ClutterTraverseCallback before_children_callback,
15620 ClutterTraverseCallback after_children_callback,
15622 gpointer user_data)
15624 ClutterActorTraverseVisitFlags flags;
15626 flags = before_children_callback (actor, current_depth, user_data);
15627 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15628 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15630 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15632 ClutterActor *iter;
15634 for (iter = actor->priv->first_child;
15636 iter = iter->priv->next_sibling)
15638 flags = _clutter_actor_traverse_depth (iter,
15639 before_children_callback,
15640 after_children_callback,
15644 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15645 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15649 if (after_children_callback)
15650 return after_children_callback (actor, current_depth, user_data);
15652 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15655 /* _clutter_actor_traverse:
15656 * @actor: The actor to start traversing the graph from
15657 * @flags: These flags may affect how the traversal is done
15658 * @before_children_callback: A function to call before visiting the
15659 * children of the current actor.
15660 * @after_children_callback: A function to call after visiting the
15661 * children of the current actor. (Ignored if
15662 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15663 * @user_data: The private data to pass to the callbacks
15665 * Traverses the scenegraph starting at the specified @actor and
15666 * descending through all its children and its children's children.
15667 * For each actor traversed @before_children_callback and
15668 * @after_children_callback are called with the specified
15669 * @user_data, before and after visiting that actor's children.
15671 * The callbacks can return flags that affect the ongoing traversal
15672 * such as by skipping over an actors children or bailing out of
15673 * any further traversing.
15676 _clutter_actor_traverse (ClutterActor *actor,
15677 ClutterActorTraverseFlags flags,
15678 ClutterTraverseCallback before_children_callback,
15679 ClutterTraverseCallback after_children_callback,
15680 gpointer user_data)
15682 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15683 _clutter_actor_traverse_breadth (actor,
15684 before_children_callback,
15686 else /* DEPTH_FIRST */
15687 _clutter_actor_traverse_depth (actor,
15688 before_children_callback,
15689 after_children_callback,
15690 0, /* start depth */
15695 on_layout_manager_changed (ClutterLayoutManager *manager,
15696 ClutterActor *self)
15698 clutter_actor_queue_relayout (self);
15702 * clutter_actor_set_layout_manager:
15703 * @self: a #ClutterActor
15704 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15706 * Sets the #ClutterLayoutManager delegate object that will be used to
15707 * lay out the children of @self.
15709 * The #ClutterActor will take a reference on the passed @manager which
15710 * will be released either when the layout manager is removed, or when
15711 * the actor is destroyed.
15716 clutter_actor_set_layout_manager (ClutterActor *self,
15717 ClutterLayoutManager *manager)
15719 ClutterActorPrivate *priv;
15721 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15722 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15726 if (priv->layout_manager != NULL)
15728 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15729 G_CALLBACK (on_layout_manager_changed),
15731 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15732 g_object_unref (priv->layout_manager);
15735 priv->layout_manager = manager;
15737 if (priv->layout_manager != NULL)
15739 g_object_ref_sink (priv->layout_manager);
15740 clutter_layout_manager_set_container (priv->layout_manager,
15741 CLUTTER_CONTAINER (self));
15742 g_signal_connect (priv->layout_manager, "layout-changed",
15743 G_CALLBACK (on_layout_manager_changed),
15747 clutter_actor_queue_relayout (self);
15749 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15753 * clutter_actor_get_layout_manager:
15754 * @self: a #ClutterActor
15756 * Retrieves the #ClutterLayoutManager used by @self.
15758 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15763 ClutterLayoutManager *
15764 clutter_actor_get_layout_manager (ClutterActor *self)
15766 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15768 return self->priv->layout_manager;
15771 static const ClutterLayoutInfo default_layout_info = {
15774 { 0, 0, 0, 0 }, /* margin */
15775 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
15776 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
15777 0.f, 0.f, /* min_width, natural_width */
15778 0.f, 0.f, /* natual_width, natural_height */
15782 layout_info_free (gpointer data)
15784 if (G_LIKELY (data != NULL))
15785 g_slice_free (ClutterLayoutInfo, data);
15789 * _clutter_actor_get_layout_info:
15790 * @self: a #ClutterActor
15792 * Retrieves a pointer to the ClutterLayoutInfo structure.
15794 * If the actor does not have a ClutterLayoutInfo associated to it, one
15795 * will be created and initialized to the default values.
15797 * This function should be used for setters.
15799 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15802 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15804 ClutterLayoutInfo *
15805 _clutter_actor_get_layout_info (ClutterActor *self)
15807 ClutterLayoutInfo *retval;
15809 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15810 if (retval == NULL)
15812 retval = g_slice_new (ClutterLayoutInfo);
15814 *retval = default_layout_info;
15816 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15825 * _clutter_actor_get_layout_info_or_defaults:
15826 * @self: a #ClutterActor
15828 * Retrieves the ClutterLayoutInfo structure associated to an actor.
15830 * If the actor does not have a ClutterLayoutInfo structure associated to it,
15831 * then the default structure will be returned.
15833 * This function should only be used for getters.
15835 * Return value: a const pointer to the ClutterLayoutInfo structure
15837 const ClutterLayoutInfo *
15838 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15840 const ClutterLayoutInfo *info;
15842 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15844 return &default_layout_info;
15850 * clutter_actor_set_x_align:
15851 * @self: a #ClutterActor
15852 * @x_align: the horizontal alignment policy
15854 * Sets the horizontal alignment policy of a #ClutterActor, in case the
15855 * actor received extra horizontal space.
15857 * See also the #ClutterActor:x-align property.
15862 clutter_actor_set_x_align (ClutterActor *self,
15863 ClutterActorAlign x_align)
15865 ClutterLayoutInfo *info;
15867 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15869 info = _clutter_actor_get_layout_info (self);
15871 if (info->x_align != x_align)
15873 info->x_align = x_align;
15875 clutter_actor_queue_relayout (self);
15877 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15882 * clutter_actor_get_x_align:
15883 * @self: a #ClutterActor
15885 * Retrieves the horizontal alignment policy set using
15886 * clutter_actor_set_x_align().
15888 * Return value: the horizontal alignment policy.
15893 clutter_actor_get_x_align (ClutterActor *self)
15895 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15897 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15901 * clutter_actor_set_y_align:
15902 * @self: a #ClutterActor
15903 * @y_align: the vertical alignment policy
15905 * Sets the vertical alignment policy of a #ClutterActor, in case the
15906 * actor received extra vertical space.
15908 * See also the #ClutterActor:y-align property.
15913 clutter_actor_set_y_align (ClutterActor *self,
15914 ClutterActorAlign y_align)
15916 ClutterLayoutInfo *info;
15918 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15920 info = _clutter_actor_get_layout_info (self);
15922 if (info->y_align != y_align)
15924 info->y_align = y_align;
15926 clutter_actor_queue_relayout (self);
15928 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15933 * clutter_actor_get_y_align:
15934 * @self: a #ClutterActor
15936 * Retrieves the vertical alignment policy set using
15937 * clutter_actor_set_y_align().
15939 * Return value: the vertical alignment policy.
15944 clutter_actor_get_y_align (ClutterActor *self)
15946 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15948 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15953 * clutter_margin_new:
15955 * Creates a new #ClutterMargin.
15957 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15958 * clutter_margin_free() to free the resources associated with it when
15964 clutter_margin_new (void)
15966 return g_slice_new0 (ClutterMargin);
15970 * clutter_margin_copy:
15971 * @margin_: a #ClutterMargin
15973 * Creates a new #ClutterMargin and copies the contents of @margin_ into
15974 * the newly created structure.
15976 * Return value: (transfer full): a copy of the #ClutterMargin.
15981 clutter_margin_copy (const ClutterMargin *margin_)
15983 if (G_LIKELY (margin_ != NULL))
15984 return g_slice_dup (ClutterMargin, margin_);
15990 * clutter_margin_free:
15991 * @margin_: a #ClutterMargin
15993 * Frees the resources allocated by clutter_margin_new() and
15994 * clutter_margin_copy().
15999 clutter_margin_free (ClutterMargin *margin_)
16001 if (G_LIKELY (margin_ != NULL))
16002 g_slice_free (ClutterMargin, margin_);
16005 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16006 clutter_margin_copy,
16007 clutter_margin_free)
16010 * clutter_actor_set_margin:
16011 * @self: a #ClutterActor
16012 * @margin: a #ClutterMargin
16014 * Sets all the components of the margin of a #ClutterActor.
16019 clutter_actor_set_margin (ClutterActor *self,
16020 const ClutterMargin *margin)
16022 ClutterLayoutInfo *info;
16026 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16027 g_return_if_fail (margin != NULL);
16029 obj = G_OBJECT (self);
16032 g_object_freeze_notify (obj);
16034 info = _clutter_actor_get_layout_info (self);
16036 if (info->margin.top != margin->top)
16038 info->margin.top = margin->top;
16039 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16043 if (info->margin.right != margin->right)
16045 info->margin.right = margin->right;
16046 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16050 if (info->margin.bottom != margin->bottom)
16052 info->margin.bottom = margin->bottom;
16053 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16057 if (info->margin.left != margin->left)
16059 info->margin.left = margin->left;
16060 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16065 clutter_actor_queue_relayout (self);
16067 g_object_thaw_notify (obj);
16071 * clutter_actor_get_margin:
16072 * @self: a #ClutterActor
16073 * @margin: (out caller-allocates): return location for a #ClutterMargin
16075 * Retrieves all the components of the margin of a #ClutterActor.
16080 clutter_actor_get_margin (ClutterActor *self,
16081 ClutterMargin *margin)
16083 const ClutterLayoutInfo *info;
16085 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16086 g_return_if_fail (margin != NULL);
16088 info = _clutter_actor_get_layout_info_or_defaults (self);
16090 *margin = info->margin;
16094 * clutter_actor_set_margin_top:
16095 * @self: a #ClutterActor
16096 * @margin: the top margin
16098 * Sets the margin from the top of a #ClutterActor.
16103 clutter_actor_set_margin_top (ClutterActor *self,
16106 ClutterLayoutInfo *info;
16108 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16109 g_return_if_fail (margin >= 0.f);
16111 info = _clutter_actor_get_layout_info (self);
16113 if (info->margin.top == margin)
16116 info->margin.top = margin;
16118 clutter_actor_queue_relayout (self);
16120 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16124 * clutter_actor_get_margin_top:
16125 * @self: a #ClutterActor
16127 * Retrieves the top margin of a #ClutterActor.
16129 * Return value: the top margin
16134 clutter_actor_get_margin_top (ClutterActor *self)
16136 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16138 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16142 * clutter_actor_set_margin_bottom:
16143 * @self: a #ClutterActor
16144 * @margin: the bottom margin
16146 * Sets the margin from the bottom of a #ClutterActor.
16151 clutter_actor_set_margin_bottom (ClutterActor *self,
16154 ClutterLayoutInfo *info;
16156 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16157 g_return_if_fail (margin >= 0.f);
16159 info = _clutter_actor_get_layout_info (self);
16161 if (info->margin.bottom == margin)
16164 info->margin.bottom = margin;
16166 clutter_actor_queue_relayout (self);
16168 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16172 * clutter_actor_get_margin_bottom:
16173 * @self: a #ClutterActor
16175 * Retrieves the bottom margin of a #ClutterActor.
16177 * Return value: the bottom margin
16182 clutter_actor_get_margin_bottom (ClutterActor *self)
16184 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16186 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16190 * clutter_actor_set_margin_left:
16191 * @self: a #ClutterActor
16192 * @margin: the left margin
16194 * Sets the margin from the left of a #ClutterActor.
16199 clutter_actor_set_margin_left (ClutterActor *self,
16202 ClutterLayoutInfo *info;
16204 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16205 g_return_if_fail (margin >= 0.f);
16207 info = _clutter_actor_get_layout_info (self);
16209 if (info->margin.left == margin)
16212 info->margin.left = margin;
16214 clutter_actor_queue_relayout (self);
16216 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16220 * clutter_actor_get_margin_left:
16221 * @self: a #ClutterActor
16223 * Retrieves the left margin of a #ClutterActor.
16225 * Return value: the left margin
16230 clutter_actor_get_margin_left (ClutterActor *self)
16232 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16234 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16238 * clutter_actor_set_margin_right:
16239 * @self: a #ClutterActor
16240 * @margin: the right margin
16242 * Sets the margin from the right of a #ClutterActor.
16247 clutter_actor_set_margin_right (ClutterActor *self,
16250 ClutterLayoutInfo *info;
16252 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16253 g_return_if_fail (margin >= 0.f);
16255 info = _clutter_actor_get_layout_info (self);
16257 if (info->margin.right == margin)
16260 info->margin.right = margin;
16262 clutter_actor_queue_relayout (self);
16264 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16268 * clutter_actor_get_margin_right:
16269 * @self: a #ClutterActor
16271 * Retrieves the right margin of a #ClutterActor.
16273 * Return value: the right margin
16278 clutter_actor_get_margin_right (ClutterActor *self)
16280 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16282 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16286 clutter_actor_set_background_color_internal (ClutterActor *self,
16287 const ClutterColor *color)
16289 ClutterActorPrivate *priv = self->priv;
16292 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16295 obj = G_OBJECT (self);
16297 priv->bg_color = *color;
16298 priv->bg_color_set = TRUE;
16300 clutter_actor_queue_redraw (self);
16302 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16303 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16307 * clutter_actor_set_background_color:
16308 * @self: a #ClutterActor
16309 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16312 * Sets the background color of a #ClutterActor.
16314 * The background color will be used to cover the whole allocation of the
16315 * actor. The default background color of an actor is transparent.
16317 * To check whether an actor has a background color, you can use the
16318 * #ClutterActor:background-color-set actor property.
16320 * The #ClutterActor:background-color property is animatable.
16325 clutter_actor_set_background_color (ClutterActor *self,
16326 const ClutterColor *color)
16328 ClutterActorPrivate *priv;
16330 GParamSpec *bg_color_pspec;
16332 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16334 obj = G_OBJECT (self);
16340 priv->bg_color_set = FALSE;
16341 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16342 clutter_actor_queue_redraw (self);
16346 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16347 if (clutter_actor_get_easing_duration (self) != 0)
16349 ClutterTransition *transition;
16351 transition = _clutter_actor_get_transition (self, bg_color_pspec);
16352 if (transition == NULL)
16354 transition = _clutter_actor_create_transition (self, bg_color_pspec,
16357 clutter_timeline_start (CLUTTER_TIMELINE (transition));
16360 _clutter_actor_update_transition (self, bg_color_pspec, color);
16362 clutter_actor_queue_redraw (self);
16365 clutter_actor_set_background_color_internal (self, color);
16369 * clutter_actor_get_background_color:
16370 * @self: a #ClutterActor
16371 * @color: (out caller-allocates): return location for a #ClutterColor
16373 * Retrieves the color set using clutter_actor_set_background_color().
16378 clutter_actor_get_background_color (ClutterActor *self,
16379 ClutterColor *color)
16381 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16382 g_return_if_fail (color != NULL);
16384 *color = self->priv->bg_color;
16388 * clutter_actor_get_previous_sibling:
16389 * @self: a #ClutterActor
16391 * Retrieves the sibling of @self that comes before it in the list
16392 * of children of @self's parent.
16394 * The returned pointer is only valid until the scene graph changes; it
16395 * is not safe to modify the list of children of @self while iterating
16398 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16403 clutter_actor_get_previous_sibling (ClutterActor *self)
16405 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16407 return self->priv->prev_sibling;
16411 * clutter_actor_get_next_sibling:
16412 * @self: a #ClutterActor
16414 * Retrieves the sibling of @self that comes after it in the list
16415 * of children of @self's parent.
16417 * The returned pointer is only valid until the scene graph changes; it
16418 * is not safe to modify the list of children of @self while iterating
16421 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16426 clutter_actor_get_next_sibling (ClutterActor *self)
16428 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16430 return self->priv->next_sibling;
16434 * clutter_actor_get_first_child:
16435 * @self: a #ClutterActor
16437 * Retrieves the first child of @self.
16439 * The returned pointer is only valid until the scene graph changes; it
16440 * is not safe to modify the list of children of @self while iterating
16443 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16448 clutter_actor_get_first_child (ClutterActor *self)
16450 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16452 return self->priv->first_child;
16456 * clutter_actor_get_last_child:
16457 * @self: a #ClutterActor
16459 * Retrieves the last child of @self.
16461 * The returned pointer is only valid until the scene graph changes; it
16462 * is not safe to modify the list of children of @self while iterating
16465 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16470 clutter_actor_get_last_child (ClutterActor *self)
16472 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16474 return self->priv->last_child;
16477 /* easy way to have properly named fields instead of the dummy ones
16478 * we use in the public structure
16480 typedef struct _RealActorIter
16482 ClutterActor *root; /* dummy1 */
16483 ClutterActor *current; /* dummy2 */
16484 gpointer padding_1; /* dummy3 */
16485 gint age; /* dummy4 */
16486 gpointer padding_2; /* dummy5 */
16490 * clutter_actor_iter_init:
16491 * @iter: a #ClutterActorIter
16492 * @root: a #ClutterActor
16494 * Initializes a #ClutterActorIter, which can then be used to iterate
16495 * efficiently over a section of the scene graph, and associates it
16498 * Modifying the scene graph section that contains @root will invalidate
16502 * ClutterActorIter iter;
16503 * ClutterActor *child;
16505 * clutter_actor_iter_init (&iter, container);
16506 * while (clutter_actor_iter_next (&iter, &child))
16508 * /* do something with child */
16515 clutter_actor_iter_init (ClutterActorIter *iter,
16516 ClutterActor *root)
16518 RealActorIter *ri = (RealActorIter *) iter;
16520 g_return_if_fail (iter != NULL);
16521 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16524 ri->current = NULL;
16525 ri->age = root->priv->age;
16529 * clutter_actor_iter_next:
16530 * @iter: a #ClutterActorIter
16531 * @child: (out): return location for a #ClutterActor
16533 * Advances the @iter and retrieves the next child of the root #ClutterActor
16534 * that was used to initialize the #ClutterActorIterator.
16536 * If the iterator can advance, this function returns %TRUE and sets the
16539 * If the iterator cannot advance, this function returns %FALSE, and
16540 * the contents of @child are undefined.
16542 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16547 clutter_actor_iter_next (ClutterActorIter *iter,
16548 ClutterActor **child)
16550 RealActorIter *ri = (RealActorIter *) iter;
16552 g_return_val_if_fail (iter != NULL, FALSE);
16553 g_return_val_if_fail (ri->root != NULL, FALSE);
16554 #ifndef G_DISABLE_ASSERT
16555 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16558 if (ri->current == NULL)
16559 ri->current = ri->root->priv->first_child;
16561 ri->current = ri->current->priv->next_sibling;
16564 *child = ri->current;
16566 return ri->current != NULL;
16570 * clutter_actor_iter_prev:
16571 * @iter: a #ClutterActorIter
16572 * @child: (out): return location for a #ClutterActor
16574 * Advances the @iter and retrieves the previous child of the root
16575 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16577 * If the iterator can advance, this function returns %TRUE and sets the
16580 * If the iterator cannot advance, this function returns %FALSE, and
16581 * the contents of @child are undefined.
16583 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16588 clutter_actor_iter_prev (ClutterActorIter *iter,
16589 ClutterActor **child)
16591 RealActorIter *ri = (RealActorIter *) iter;
16593 g_return_val_if_fail (iter != NULL, FALSE);
16594 g_return_val_if_fail (ri->root != NULL, FALSE);
16595 #ifndef G_DISABLE_ASSERT
16596 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16599 if (ri->current == NULL)
16600 ri->current = ri->root->priv->last_child;
16602 ri->current = ri->current->priv->prev_sibling;
16605 *child = ri->current;
16607 return ri->current != NULL;
16611 * clutter_actor_iter_remove:
16612 * @iter: a #ClutterActorIter
16614 * Safely removes the #ClutterActor currently pointer to by the iterator
16617 * This function can only be called after clutter_actor_iter_next() or
16618 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16619 * than once for the same actor.
16621 * This function will call clutter_actor_remove_child() internally.
16626 clutter_actor_iter_remove (ClutterActorIter *iter)
16628 RealActorIter *ri = (RealActorIter *) iter;
16631 g_return_if_fail (iter != NULL);
16632 g_return_if_fail (ri->root != NULL);
16633 #ifndef G_DISABLE_ASSERT
16634 g_return_if_fail (ri->age == ri->root->priv->age);
16636 g_return_if_fail (ri->current != NULL);
16642 ri->current = cur->priv->prev_sibling;
16644 clutter_actor_remove_child_internal (ri->root, cur,
16645 REMOVE_CHILD_DEFAULT_FLAGS);
16652 * clutter_actor_iter_destroy:
16653 * @iter: a #ClutterActorIter
16655 * Safely destroys the #ClutterActor currently pointer to by the iterator
16658 * This function can only be called after clutter_actor_iter_next() or
16659 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16660 * than once for the same actor.
16662 * This function will call clutter_actor_destroy() internally.
16667 clutter_actor_iter_destroy (ClutterActorIter *iter)
16669 RealActorIter *ri = (RealActorIter *) iter;
16672 g_return_if_fail (iter != NULL);
16673 g_return_if_fail (ri->root != NULL);
16674 #ifndef G_DISABLE_ASSERT
16675 g_return_if_fail (ri->age == ri->root->priv->age);
16677 g_return_if_fail (ri->current != NULL);
16683 ri->current = cur->priv->prev_sibling;
16685 clutter_actor_destroy (cur);
16691 static const ClutterAnimationInfo default_animation_info = {
16692 NULL, /* transitions */
16694 NULL, /* cur_state */
16698 clutter_animation_info_free (gpointer data)
16702 ClutterAnimationInfo *info = data;
16704 if (info->transitions != NULL)
16705 g_hash_table_unref (info->transitions);
16707 if (info->states != NULL)
16708 g_array_unref (info->states);
16710 g_slice_free (ClutterAnimationInfo, info);
16714 const ClutterAnimationInfo *
16715 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16717 const ClutterAnimationInfo *res;
16718 GObject *obj = G_OBJECT (self);
16720 res = g_object_get_qdata (obj, quark_actor_animation_info);
16724 return &default_animation_info;
16727 ClutterAnimationInfo *
16728 _clutter_actor_get_animation_info (ClutterActor *self)
16730 GObject *obj = G_OBJECT (self);
16731 ClutterAnimationInfo *res;
16733 res = g_object_get_qdata (obj, quark_actor_animation_info);
16736 res = g_slice_new (ClutterAnimationInfo);
16738 *res = default_animation_info;
16740 g_object_set_qdata_full (obj, quark_actor_animation_info,
16742 clutter_animation_info_free);
16748 ClutterTransition *
16749 _clutter_actor_get_transition (ClutterActor *actor,
16752 const ClutterAnimationInfo *info;
16754 info = _clutter_actor_get_animation_info_or_defaults (actor);
16756 if (info->transitions == NULL)
16759 return g_hash_table_lookup (info->transitions, pspec->name);
16762 typedef struct _TransitionClosure
16764 ClutterActor *actor;
16765 ClutterTransition *transition;
16767 gulong completed_id;
16768 } TransitionClosure;
16771 transition_closure_free (gpointer data)
16773 if (G_LIKELY (data != NULL))
16775 TransitionClosure *clos = data;
16777 g_signal_handler_disconnect (clos->transition, clos->completed_id);
16778 g_free (clos->name);
16780 g_slice_free (TransitionClosure, clos);
16785 on_transition_completed (ClutterTransition *transition,
16786 TransitionClosure *clos)
16788 ClutterAnimationInfo *info;
16790 info = _clutter_actor_get_animation_info (clos->actor);
16792 /* this will take care of cleaning clos for us */
16793 g_hash_table_remove (info->transitions, clos->name);
16797 _clutter_actor_update_transition (ClutterActor *actor,
16801 TransitionClosure *clos;
16802 ClutterInterval *interval;
16803 const ClutterAnimationInfo *info;
16806 GValue initial = G_VALUE_INIT;
16807 GValue final = G_VALUE_INIT;
16808 char *error = NULL;
16810 info = _clutter_actor_get_animation_info_or_defaults (actor);
16812 if (info->transitions == NULL)
16815 clos = g_hash_table_lookup (info->transitions, pspec->name);
16819 va_start (var_args, pspec);
16821 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16823 g_value_init (&initial, ptype);
16824 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16828 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16831 g_critical ("%s: %s", G_STRLOC, error);
16836 interval = clutter_transition_get_interval (clos->transition);
16837 clutter_interval_set_initial_value (interval, &initial);
16838 clutter_interval_set_final_value (interval, &final);
16840 clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16843 g_value_unset (&initial);
16844 g_value_unset (&final);
16850 * _clutter_actor_create_transition:
16851 * @actor: a #ClutterActor
16852 * @pspec: the property used for the transition
16853 * @...: initial and final state
16855 * Creates a #ClutterTransition for the property represented by @pspec.
16857 * Return value: a #ClutterTransition
16859 ClutterTransition *
16860 _clutter_actor_create_transition (ClutterActor *actor,
16864 ClutterAnimationInfo *info;
16865 ClutterTransition *res = NULL;
16866 gboolean call_restore = FALSE;
16867 TransitionClosure *clos;
16870 info = _clutter_actor_get_animation_info (actor);
16872 if (info->states == NULL)
16874 clutter_actor_save_easing_state (actor);
16875 call_restore = TRUE;
16878 if (info->transitions == NULL)
16879 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
16881 transition_closure_free);
16883 va_start (var_args, pspec);
16885 clos = g_hash_table_lookup (info->transitions, pspec->name);
16888 ClutterInterval *interval;
16889 GValue initial = G_VALUE_INIT;
16890 GValue final = G_VALUE_INIT;
16894 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16896 G_VALUE_COLLECT_INIT (&initial, ptype,
16901 g_critical ("%s: %s", G_STRLOC, error);
16906 G_VALUE_COLLECT_INIT (&final, ptype,
16912 g_critical ("%s: %s", G_STRLOC, error);
16913 g_value_unset (&initial);
16918 interval = clutter_interval_new_with_values (ptype, &initial, &final);
16920 g_value_unset (&initial);
16921 g_value_unset (&final);
16923 res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
16926 clutter_transition_set_interval (res, interval);
16927 clutter_transition_set_remove_on_complete (res, TRUE);
16929 clutter_actor_add_transition (actor, pspec->name, res);
16932 res = clos->transition;
16936 clutter_actor_restore_easing_state (actor);
16944 * clutter_actor_add_transition:
16945 * @self: a #ClutterActor
16946 * @name: the name of the transition to add
16947 * @transition: the #ClutterTransition to add
16949 * Adds a @transition to the #ClutterActor's list of animations.
16951 * The @name string is a per-actor unique identifier of the @transition: only
16952 * one #ClutterTransition can be associated to the specified @name.
16954 * The @transition will be given the easing duration, mode, and delay
16955 * associated to the actor's current easing state; it is possible to modify
16956 * these values after calling clutter_actor_add_transition().
16958 * This function is usually called implicitly when modifying an animatable
16964 clutter_actor_add_transition (ClutterActor *self,
16966 ClutterTransition *transition)
16968 ClutterTimeline *timeline;
16969 TransitionClosure *clos;
16970 ClutterAnimationInfo *info;
16972 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16973 g_return_if_fail (name != NULL);
16974 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
16976 info = _clutter_actor_get_animation_info (self);
16978 if (info->cur_state == NULL)
16980 g_warning ("No easing state is defined for the actor '%s'; you "
16981 "must call clutter_actor_save_easing_state() before "
16982 "calling clutter_actor_add_transition().",
16983 _clutter_actor_get_debug_name (self));
16987 if (info->transitions == NULL)
16988 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
16990 transition_closure_free);
16992 if (g_hash_table_lookup (info->transitions, name) != NULL)
16994 g_warning ("A transition with name '%s' already exists for "
16997 _clutter_actor_get_debug_name (self));
17001 timeline = CLUTTER_TIMELINE (transition);
17003 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17004 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17005 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17007 clos = g_slice_new (TransitionClosure);
17008 clos->actor = self;
17009 clos->transition = transition;
17010 clos->name = g_strdup (name);
17011 clos->completed_id = g_signal_connect (timeline, "completed",
17012 G_CALLBACK (on_transition_completed),
17015 g_hash_table_insert (info->transitions, clos->name, clos);
17019 * clutter_actor_remove_transition:
17020 * @self: a #ClutterActor
17021 * @name: the name of the transition to remove
17023 * Removes the transition stored inside a #ClutterActor using @name
17029 clutter_actor_remove_transition (ClutterActor *self,
17032 const ClutterAnimationInfo *info;
17034 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17035 g_return_if_fail (name != NULL);
17037 info = _clutter_actor_get_animation_info_or_defaults (self);
17039 if (info->transitions == NULL)
17042 g_hash_table_remove (info->transitions, name);
17046 * clutter_actor_remove_all_transitions:
17047 * @self: a #ClutterActor
17049 * Removes all transitions associated to @self.
17054 clutter_actor_remove_all_transitions (ClutterActor *self)
17056 const ClutterAnimationInfo *info;
17058 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17060 info = _clutter_actor_get_animation_info_or_defaults (self);
17061 if (info->transitions == NULL)
17064 g_hash_table_remove_all (info->transitions);
17068 * clutter_actor_set_easing_duration:
17069 * @self: a #ClutterActor
17070 * @msecs: the duration of the easing, or %NULL
17072 * Sets the duration of the tweening for animatable properties
17073 * of @self for the current easing state.
17075 * Calling this function will implicitly call
17076 * clutter_actor_save_easing_state() if no previous call to
17077 * that function was made.
17082 clutter_actor_set_easing_duration (ClutterActor *self,
17085 ClutterAnimationInfo *info;
17087 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17089 info = _clutter_actor_get_animation_info (self);
17091 if (info->states == NULL)
17092 clutter_actor_save_easing_state (self);
17094 if (info->cur_state->easing_duration != msecs)
17095 info->cur_state->easing_duration = msecs;
17099 * clutter_actor_get_easing_duration:
17100 * @self: a #ClutterActor
17102 * Retrieves the duration of the tweening for animatable
17103 * properties of @self for the current easing state.
17105 * Return value: the duration of the tweening, in milliseconds
17110 clutter_actor_get_easing_duration (ClutterActor *self)
17112 const ClutterAnimationInfo *info;
17114 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17116 info = _clutter_actor_get_animation_info_or_defaults (self);
17118 if (info->cur_state != NULL)
17119 return info->cur_state->easing_duration;
17125 * clutter_actor_set_easing_mode:
17126 * @self: a #ClutterActor
17127 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17129 * Sets the easing mode for the tweening of animatable properties
17132 * Calling this function will implicitly call
17133 * clutter_actor_save_easing_state() if no previous calls to
17134 * that function were made.
17139 clutter_actor_set_easing_mode (ClutterActor *self,
17140 ClutterAnimationMode mode)
17142 ClutterAnimationInfo *info;
17144 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17145 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17146 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17148 info = _clutter_actor_get_animation_info (self);
17150 if (info->states == NULL)
17151 clutter_actor_save_easing_state (self);
17153 if (info->cur_state->easing_mode != mode)
17154 info->cur_state->easing_mode = mode;
17158 * clutter_actor_get_easing_mode:
17159 * @self: a #ClutterActor
17161 * Retrieves the easing mode for the tweening of animatable properties
17162 * of @self for the current easing state.
17164 * Return value: an easing mode
17168 ClutterAnimationMode
17169 clutter_actor_get_easing_mode (ClutterActor *self)
17171 const ClutterAnimationInfo *info;
17173 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17175 info = _clutter_actor_get_animation_info_or_defaults (self);
17177 if (info->cur_state != NULL)
17178 return info->cur_state->easing_mode;
17180 return CLUTTER_EASE_OUT_CUBIC;
17184 * clutter_actor_set_easing_delay:
17185 * @self: a #ClutterActor
17186 * @msecs: the delay before the start of the tweening, in milliseconds
17188 * Sets the delay that should be applied before tweening animatable
17191 * Calling this function will implicitly call
17192 * clutter_actor_save_easing_state() if no previous calls to
17193 * that function were made.
17198 clutter_actor_set_easing_delay (ClutterActor *self,
17201 ClutterAnimationInfo *info;
17203 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17205 info = _clutter_actor_get_animation_info (self);
17207 if (info->states == NULL)
17208 clutter_actor_save_easing_state (self);
17210 if (info->cur_state->easing_delay != msecs)
17211 info->cur_state->easing_delay = msecs;
17215 * clutter_actor_get_easing_delay:
17216 * @self: a #ClutterActor
17218 * Retrieves the delay that should be applied when tweening animatable
17221 * Return value: a delay, in milliseconds
17226 clutter_actor_get_easing_delay (ClutterActor *self)
17228 const ClutterAnimationInfo *info;
17230 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17232 info = _clutter_actor_get_animation_info_or_defaults (self);
17234 if (info->cur_state != NULL)
17235 return info->cur_state->easing_delay;
17241 * clutter_actor_get_transition:
17242 * @self: a #ClutterActor
17243 * @name: the name of the transition
17245 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17246 * transition @name.
17248 * Transitions created for animatable properties use the name of the
17249 * property itself, for instance the code below:
17252 * clutter_actor_set_easing_duration (actor, 1000);
17253 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17255 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17256 * g_signal_connect (transition, "completed",
17257 * G_CALLBACK (on_transition_complete),
17261 * will call the <function>on_transition_complete</function> callback when
17262 * the transition is complete.
17264 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17265 * was found to match the passed name; the returned instance is owned
17266 * by Clutter and it should not be freed
17270 ClutterTransition *
17271 clutter_actor_get_transition (ClutterActor *self,
17274 TransitionClosure *clos;
17275 const ClutterAnimationInfo *info;
17277 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17278 g_return_val_if_fail (name != NULL, NULL);
17280 info = _clutter_actor_get_animation_info_or_defaults (self);
17282 if (info->transitions == NULL)
17285 clos = g_hash_table_lookup (info->transitions, name);
17289 return clos->transition;
17293 * clutter_actor_save_easing_state:
17294 * @self: a #ClutterActor
17296 * Saves the current easing state for animatable properties, and creates
17297 * a new state with the default values for easing mode and duration.
17302 clutter_actor_save_easing_state (ClutterActor *self)
17304 ClutterAnimationInfo *info;
17307 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17309 info = _clutter_actor_get_animation_info (self);
17311 if (info->states == NULL)
17312 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17314 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17315 new_state.easing_duration = 250;
17316 new_state.easing_delay = 0;
17318 g_array_append_val (info->states, new_state);
17320 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17324 * clutter_actor_restore_easing_state:
17325 * @self: a #ClutterActor
17327 * Restores the easing state as it was prior to a call to
17328 * clutter_actor_save_easing_state().
17333 clutter_actor_restore_easing_state (ClutterActor *self)
17335 ClutterAnimationInfo *info;
17337 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17339 info = _clutter_actor_get_animation_info (self);
17341 if (info->states == NULL)
17343 g_critical ("The function clutter_actor_restore_easing_state() has "
17344 "called without a previous call to "
17345 "clutter_actor_save_easing_state().");
17349 g_array_remove_index (info->states, info->states->len - 1);
17350 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17354 * clutter_actor_set_content:
17355 * @self: a #ClutterActor
17356 * @content: (allow-none): a #ClutterContent, or %NULL
17358 * Sets the contents of a #ClutterActor.
17363 clutter_actor_set_content (ClutterActor *self,
17364 ClutterContent *content)
17366 ClutterActorPrivate *priv;
17368 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17369 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17373 if (priv->content != NULL)
17375 _clutter_content_detached (priv->content, self);
17376 g_object_unref (priv->content);
17379 priv->content = content;
17381 if (priv->content != NULL)
17383 g_object_ref (priv->content);
17384 _clutter_content_attached (priv->content, self);
17387 /* given that the content is always painted within the allocation,
17388 * we only need to queue a redraw here
17390 clutter_actor_queue_redraw (self);
17392 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17394 /* if the content gravity is not resize-fill, and the new content has a
17395 * different preferred size than the previous one, then the content box
17396 * may have been changed. since we compute that lazily, we just notify
17397 * here, and let whomever watches :content-box do whatever they need to
17400 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17401 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17405 * clutter_actor_get_content:
17406 * @self: a #ClutterActor
17408 * Retrieves the contents of @self.
17410 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17411 * or %NULL if none was set
17416 clutter_actor_get_content (ClutterActor *self)
17418 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17420 return self->priv->content;
17424 * clutter_actor_set_content_gravity:
17425 * @self: a #ClutterActor
17426 * @gravity: the #ClutterContentGravity
17428 * Sets the gravity of the #ClutterContent used by @self.
17430 * See the description of the #ClutterActor:content-gravity property for
17431 * more information.
17436 clutter_actor_set_content_gravity (ClutterActor *self,
17437 ClutterContentGravity gravity)
17439 ClutterActorPrivate *priv;
17441 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17445 if (priv->content_gravity == gravity)
17448 priv->content_gravity = gravity;
17450 clutter_actor_queue_redraw (self);
17452 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17453 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17457 * clutter_actor_get_content_gravity:
17458 * @self: a #ClutterActor
17460 * Retrieves the content gravity as set using
17461 * clutter_actor_get_content_gravity().
17463 * Return value: the content gravity
17467 ClutterContentGravity
17468 clutter_actor_get_content_gravity (ClutterActor *self)
17470 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17471 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17473 return self->priv->content_gravity;
17477 * clutter_actor_get_content_box:
17478 * @self: a #ClutterActor
17479 * @box: (out caller-allocates): the return location for the bounding
17480 * box for the #ClutterContent
17482 * Retrieves the bounding box for the #ClutterContent of @self.
17484 * If no #ClutterContent is set for @self, or if @self has not been
17485 * allocated yet, then the result is undefined.
17487 * The content box is guaranteed to be, at most, as big as the allocation
17488 * of the #ClutterActor.
17490 * If the #ClutterContent used by the actor has a preferred size, then
17491 * it is possible to modify the content box by using the
17492 * #ClutterActor:content-gravity property.
17497 clutter_actor_get_content_box (ClutterActor *self,
17498 ClutterActorBox *box)
17500 ClutterActorPrivate *priv;
17501 gfloat content_w, content_h;
17502 gfloat alloc_w, alloc_h;
17504 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17505 g_return_if_fail (box != NULL);
17509 if (!clutter_actor_has_allocation (self))
17512 if (priv->content == NULL)
17515 *box = priv->allocation;
17517 /* no need to do any more work */
17518 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17521 /* if the content does not have a preferred size then there is
17522 * no point in computing the content box
17524 if (!_clutter_content_get_preferred_size (priv->content,
17529 clutter_actor_box_get_size (&priv->allocation, &alloc_w, &alloc_h);
17531 switch (priv->content_gravity)
17533 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17534 box->x2 = box->x1 + MIN (content_w, alloc_w);
17535 box->y2 = box->y1 + MIN (content_h, alloc_h);
17538 case CLUTTER_CONTENT_GRAVITY_TOP:
17539 if (alloc_w > content_w)
17541 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17542 box->x2 = box->x1 + content_w;
17544 box->y2 = box->y1 + MIN (content_h, alloc_h);
17547 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17548 if (alloc_w > content_w)
17550 box->x1 += (alloc_w - content_w);
17551 box->x2 = box->x1 + content_w;
17553 box->y2 = box->y1 + MIN (content_h, alloc_h);
17556 case CLUTTER_CONTENT_GRAVITY_LEFT:
17557 box->x2 = box->x1 + MIN (content_w, alloc_w);
17558 if (alloc_h > content_h)
17560 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17561 box->y2 = box->y1 + content_h;
17565 case CLUTTER_CONTENT_GRAVITY_CENTER:
17566 if (alloc_w > content_w)
17568 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17569 box->x2 = box->x1 + content_w;
17571 if (alloc_h > content_h)
17573 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17574 box->y2 = box->y1 + content_h;
17578 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17579 if (alloc_w > content_w)
17581 box->x1 += (alloc_w - content_w);
17582 box->x2 = box->x1 + content_w;
17584 if (alloc_h > content_h)
17586 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17587 box->y2 = box->y1 + content_h;
17591 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17592 box->x2 = box->x1 + MIN (content_w, alloc_w);
17593 if (alloc_h > content_h)
17595 box->y1 += (alloc_h - content_h);
17596 box->y2 = box->y1 + content_h;
17600 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17601 if (alloc_w > content_w)
17603 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17604 box->x2 = box->x1 + content_w;
17606 if (alloc_h > content_h)
17608 box->y1 += (alloc_h - content_h);
17609 box->y2 = box->y1 + content_h;
17613 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17614 if (alloc_w > content_w)
17616 box->x1 += (alloc_w - content_w);
17617 box->x2 = box->x1 + content_w;
17619 if (alloc_h > content_h)
17621 box->y1 += (alloc_h - content_h);
17622 box->y2 = box->y1 + content_h;
17626 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17627 g_assert_not_reached ();
17630 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17631 if (content_w >= content_h && content_h > 0)
17633 double ratio = content_w / content_h;
17635 box->x2 = box->x1 + alloc_w;
17637 box->y1 += ceilf ((alloc_h - (alloc_h / ratio)) / 2.0);
17638 box->y2 = box->y1 + (alloc_h / ratio);
17640 else if (content_h > content_w && content_w > 0)
17642 double ratio = content_h / content_w;
17644 box->x1 += ceilf ((alloc_w - (alloc_w / ratio)) / 2.0);
17645 box->x2 = box->x2 + (alloc_w / ratio);
17647 box->y2 = box->x1 + alloc_h;