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 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="bin-layout">
113 * <title>Actors</title>
114 * <graphic fileref="test-actor.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>
245 * CLUTTER_ACTOR_IS_MAPPED:
246 * @a: a #ClutterActor
248 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
250 * The mapped state is set when the actor is visible and all its parents up
251 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
253 * This check can be used to see if an actor is going to be painted, as only
254 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
256 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
257 * not be checked directly; instead, the recommended usage is to connect a
258 * handler on the #GObject::notify signal for the #ClutterActor:mapped
259 * property of #ClutterActor, and check the presence of
260 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
262 * It is also important to note that Clutter may delay the changes of
263 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
264 * limitations, or during the reparenting of an actor, to optimize
265 * unnecessary (and potentially expensive) state changes.
271 * CLUTTER_ACTOR_IS_REALIZED:
272 * @a: a #ClutterActor
274 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
276 * The realized state has an actor-dependant interpretation. If an
277 * actor wants to delay allocating resources until it is attached to a
278 * stage, it may use the realize state to do so. However it is
279 * perfectly acceptable for an actor to allocate Cogl resources before
280 * being realized because there is only one drawing context used by Clutter
281 * so any resources will work on any stage. If an actor is mapped it
282 * must also be realized, but an actor can be realized and unmapped
283 * (this is so hiding an actor temporarily doesn't do an expensive
284 * unrealize/realize).
286 * To be realized an actor must be inside a stage, and all its parents
293 * CLUTTER_ACTOR_IS_VISIBLE:
294 * @a: a #ClutterActor
296 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
297 * Equivalent to the ClutterActor::visible object property.
299 * Note that an actor is only painted onscreen if it's mapped, which
300 * means it's visible, and all its parents are visible, and one of the
301 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
307 * CLUTTER_ACTOR_IS_REACTIVE:
308 * @a: a #ClutterActor
310 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
312 * Only reactive actors will receive event-related signals.
323 #include "cogl/cogl.h"
325 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
326 #define CLUTTER_ENABLE_EXPERIMENTAL_API
328 #include "clutter-actor-private.h"
330 #include "clutter-action.h"
331 #include "clutter-actor-meta-private.h"
332 #include "clutter-animatable.h"
333 #include "clutter-color-static.h"
334 #include "clutter-color.h"
335 #include "clutter-constraint.h"
336 #include "clutter-container.h"
337 #include "clutter-debug.h"
338 #include "clutter-effect-private.h"
339 #include "clutter-enum-types.h"
340 #include "clutter-fixed-layout.h"
341 #include "clutter-main.h"
342 #include "clutter-marshal.h"
343 #include "clutter-flatten-effect.h"
344 #include "clutter-paint-volume-private.h"
345 #include "clutter-private.h"
346 #include "clutter-profile.h"
347 #include "clutter-scriptable.h"
348 #include "clutter-script-private.h"
349 #include "clutter-stage-private.h"
350 #include "clutter-units.h"
352 #include "deprecated/clutter-behaviour.h"
353 #include "deprecated/clutter-container.h"
355 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
356 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
358 /* Internal enum used to control mapped state update. This is a hint
359 * which indicates when to do something other than just enforce
363 MAP_STATE_CHECK, /* just enforce invariants. */
364 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
365 * used when about to unparent.
367 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
368 * used to set mapped on toplevels.
370 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
371 * used just before unmapping parent.
375 /* 3 entries should be a good compromise, few layout managers
376 * will ask for 3 different preferred size in each allocation cycle */
377 #define N_CACHED_SIZE_REQUESTS 3
379 struct _ClutterActorPrivate
382 ClutterRequestMode request_mode;
384 /* our cached size requests for different width / height */
385 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
386 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
388 /* An age of 0 means the entry is not set */
389 guint cached_height_age;
390 guint cached_width_age;
392 /* the bounding box of the actor, relative to the parent's
395 ClutterActorBox allocation;
396 ClutterAllocationFlags allocation_flags;
401 /* clip, in actor coordinates */
402 cairo_rectangle_t clip;
404 /* the cached transformation matrix; see apply_transform() */
405 CoglMatrix transform;
408 gint opacity_override;
410 ClutterOffscreenRedirect offscreen_redirect;
412 /* This is an internal effect used to implement the
413 offscreen-redirect property */
414 ClutterEffect *flatten_effect;
417 ClutterActor *parent;
418 ClutterActor *prev_sibling;
419 ClutterActor *next_sibling;
420 ClutterActor *first_child;
421 ClutterActor *last_child;
425 /* tracks whenever the children of an actor are changed; the
426 * age is incremented by 1 whenever an actor is added or
427 * removed. the age is not incremented when the first or the
428 * last child pointers are changed, or when grandchildren of
429 * an actor are changed.
433 gchar *name; /* a non-unique name, used for debugging */
434 guint32 id; /* unique id, used for backward compatibility */
436 gint32 pick_id; /* per-stage unique id, used for picking */
438 /* a back-pointer to the Pango context that we can use
439 * to create pre-configured PangoLayout
441 PangoContext *pango_context;
443 /* the text direction configured for this child - either by
444 * application code, or by the actor's parent
446 ClutterTextDirection text_direction;
448 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
452 ClutterMetaGroup *actions;
453 ClutterMetaGroup *constraints;
454 ClutterMetaGroup *effects;
456 /* delegate object used to allocate the children of this actor */
457 ClutterLayoutManager *layout_manager;
459 /* used when painting, to update the paint volume */
460 ClutterEffect *current_effect;
462 /* This is used to store an effect which needs to be redrawn. A
463 redraw can be queued to start from a particular effect. This is
464 used by parametrised effects that can cache an image of the
465 actor. If a parameter of the effect changes then it only needs to
466 redraw the cached image, not the actual actor. The pointer is
467 only valid if is_dirty == TRUE. If the pointer is NULL then the
468 whole actor is dirty. */
469 ClutterEffect *effect_to_redraw;
471 /* This is used when painting effects to implement the
472 clutter_actor_continue_paint() function. It points to the node in
473 the list of effects that is next in the chain */
474 const GList *next_effect_to_paint;
476 ClutterPaintVolume paint_volume;
478 /* NB: This volume isn't relative to this actor, it is in eye
479 * coordinates so that it can remain valid after the actor changes.
481 ClutterPaintVolume last_paint_volume;
483 ClutterStageQueueRedrawEntry *queue_redraw_entry;
485 ClutterColor bg_color;
489 /* fixed position and sizes */
490 guint position_set : 1;
491 guint min_width_set : 1;
492 guint min_height_set : 1;
493 guint natural_width_set : 1;
494 guint natural_height_set : 1;
495 /* cached request is invalid (implies allocation is too) */
496 guint needs_width_request : 1;
497 /* cached request is invalid (implies allocation is too) */
498 guint needs_height_request : 1;
499 /* cached allocation is invalid (request has changed, probably) */
500 guint needs_allocation : 1;
501 guint show_on_set_parent : 1;
503 guint clip_to_allocation : 1;
504 guint enable_model_view_transform : 1;
505 guint enable_paint_unmapped : 1;
506 guint has_pointer : 1;
507 guint propagated_one_redraw : 1;
508 guint paint_volume_valid : 1;
509 guint last_paint_volume_valid : 1;
510 guint in_clone_paint : 1;
511 guint transform_valid : 1;
512 /* This is TRUE if anything has queued a redraw since we were last
513 painted. In this case effect_to_redraw will point to an effect
514 the redraw was queued from or it will be NULL if the redraw was
515 queued without an effect. */
517 guint bg_color_set : 1;
526 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
527 * when set they force a size request, when gotten they
528 * get the allocation if the allocation is valid, and the
536 /* Then the rest of these size-related properties are the "actual"
537 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
542 PROP_FIXED_POSITION_SET,
551 PROP_NATURAL_WIDTH_SET,
554 PROP_NATURAL_HEIGHT_SET,
558 /* Allocation properties are read-only */
565 PROP_CLIP_TO_ALLOCATION,
569 PROP_OFFSCREEN_REDIRECT,
582 PROP_ROTATION_ANGLE_X,
583 PROP_ROTATION_ANGLE_Y,
584 PROP_ROTATION_ANGLE_Z,
585 PROP_ROTATION_CENTER_X,
586 PROP_ROTATION_CENTER_Y,
587 PROP_ROTATION_CENTER_Z,
588 /* This property only makes sense for the z rotation because the
589 others would depend on the actor having a size along the
591 PROP_ROTATION_CENTER_Z_GRAVITY,
597 PROP_SHOW_ON_SET_PARENT,
615 PROP_BACKGROUND_COLOR,
616 PROP_BACKGROUND_COLOR_SET,
624 static GParamSpec *obj_props[PROP_LAST];
643 BUTTON_RELEASE_EVENT,
655 static guint actor_signals[LAST_SIGNAL] = { 0, };
657 static void clutter_container_iface_init (ClutterContainerIface *iface);
658 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
659 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
660 static void atk_implementor_iface_init (AtkImplementorIface *iface);
662 /* These setters are all static for now, maybe they should be in the
663 * public API, but they are perhaps obscure enough to leave only as
666 static void clutter_actor_set_min_width (ClutterActor *self,
668 static void clutter_actor_set_min_height (ClutterActor *self,
670 static void clutter_actor_set_natural_width (ClutterActor *self,
671 gfloat natural_width);
672 static void clutter_actor_set_natural_height (ClutterActor *self,
673 gfloat natural_height);
674 static void clutter_actor_set_min_width_set (ClutterActor *self,
675 gboolean use_min_width);
676 static void clutter_actor_set_min_height_set (ClutterActor *self,
677 gboolean use_min_height);
678 static void clutter_actor_set_natural_width_set (ClutterActor *self,
679 gboolean use_natural_width);
680 static void clutter_actor_set_natural_height_set (ClutterActor *self,
681 gboolean use_natural_height);
682 static void clutter_actor_update_map_state (ClutterActor *self,
683 MapStateChange change);
684 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
686 /* Helper routines for managing anchor coords */
687 static void clutter_anchor_coord_get_units (ClutterActor *self,
688 const AnchorCoord *coord,
692 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
697 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
698 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
699 ClutterGravity gravity);
701 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
703 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
705 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
706 ClutterActor *ancestor,
709 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
711 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
713 static void on_layout_manager_changed (ClutterLayoutManager *manager,
716 /* Helper macro which translates by the anchor coord, applies the
717 given transformation and then translates back */
718 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
719 gfloat _tx, _ty, _tz; \
720 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
721 cogl_matrix_translate ((m), _tx, _ty, _tz); \
723 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
725 static GQuark quark_shader_data = 0;
726 static GQuark quark_actor_layout_info = 0;
727 static GQuark quark_actor_transform_info = 0;
729 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
731 G_TYPE_INITIALLY_UNOWNED,
732 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
733 clutter_container_iface_init)
734 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
735 clutter_scriptable_iface_init)
736 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
737 clutter_animatable_iface_init)
738 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
739 atk_implementor_iface_init));
742 * clutter_actor_get_debug_name:
743 * @actor: a #ClutterActor
745 * Retrieves a printable name of @actor for debugging messages
747 * Return value: a string with a printable name
750 _clutter_actor_get_debug_name (ClutterActor *actor)
752 return actor->priv->name != NULL ? actor->priv->name
753 : G_OBJECT_TYPE_NAME (actor);
756 #ifdef CLUTTER_ENABLE_DEBUG
757 /* XXX - this is for debugging only, remove once working (or leave
758 * in only in some debug mode). Should leave it for a little while
759 * until we're confident in the new map/realize/visible handling.
762 clutter_actor_verify_map_state (ClutterActor *self)
764 ClutterActorPrivate *priv = self->priv;
766 if (CLUTTER_ACTOR_IS_REALIZED (self))
768 /* all bets are off during reparent when we're potentially realized,
769 * but should not be according to invariants
771 if (!CLUTTER_ACTOR_IN_REPARENT (self))
773 if (priv->parent == NULL)
775 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
779 g_warning ("Realized non-toplevel actor '%s' should "
781 _clutter_actor_get_debug_name (self));
783 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
785 g_warning ("Realized actor %s has an unrealized parent %s",
786 _clutter_actor_get_debug_name (self),
787 _clutter_actor_get_debug_name (priv->parent));
792 if (CLUTTER_ACTOR_IS_MAPPED (self))
794 if (!CLUTTER_ACTOR_IS_REALIZED (self))
795 g_warning ("Actor '%s' is mapped but not realized",
796 _clutter_actor_get_debug_name (self));
798 /* remaining bets are off during reparent when we're potentially
799 * mapped, but should not be according to invariants
801 if (!CLUTTER_ACTOR_IN_REPARENT (self))
803 if (priv->parent == NULL)
805 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
807 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
808 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
810 g_warning ("Toplevel actor '%s' is mapped "
812 _clutter_actor_get_debug_name (self));
817 g_warning ("Mapped actor '%s' should have a parent",
818 _clutter_actor_get_debug_name (self));
823 ClutterActor *iter = self;
825 /* check for the enable_paint_unmapped flag on the actor
826 * and parents; if the flag is enabled at any point of this
827 * branch of the scene graph then all the later checks
832 if (iter->priv->enable_paint_unmapped)
835 iter = iter->priv->parent;
838 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
840 g_warning ("Actor '%s' should not be mapped if parent '%s'"
842 _clutter_actor_get_debug_name (self),
843 _clutter_actor_get_debug_name (priv->parent));
846 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
848 g_warning ("Actor '%s' should not be mapped if parent '%s'"
850 _clutter_actor_get_debug_name (self),
851 _clutter_actor_get_debug_name (priv->parent));
854 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
856 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
857 g_warning ("Actor '%s' is mapped but its non-toplevel "
858 "parent '%s' is not mapped",
859 _clutter_actor_get_debug_name (self),
860 _clutter_actor_get_debug_name (priv->parent));
867 #endif /* CLUTTER_ENABLE_DEBUG */
870 clutter_actor_set_mapped (ClutterActor *self,
873 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
878 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
879 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
883 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
884 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
888 /* this function updates the mapped and realized states according to
889 * invariants, in the appropriate order.
892 clutter_actor_update_map_state (ClutterActor *self,
893 MapStateChange change)
897 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
899 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
901 /* the mapped flag on top-level actors must be set by the
902 * per-backend implementation because it might be asynchronous.
904 * That is, the MAPPED flag on toplevels currently tracks the X
905 * server mapped-ness of the window, while the expected behavior
906 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
907 * This creates some weird complexity by breaking the invariant
908 * that if we're visible and all ancestors shown then we are
909 * also mapped - instead, we are mapped if all ancestors
910 * _possibly excepting_ the stage are mapped. The stage
911 * will map/unmap for example when it is minimized or
912 * moved to another workspace.
914 * So, the only invariant on the stage is that if visible it
915 * should be realized, and that it has to be visible to be
918 if (CLUTTER_ACTOR_IS_VISIBLE (self))
919 clutter_actor_realize (self);
923 case MAP_STATE_CHECK:
926 case MAP_STATE_MAKE_MAPPED:
927 g_assert (!was_mapped);
928 clutter_actor_set_mapped (self, TRUE);
931 case MAP_STATE_MAKE_UNMAPPED:
932 g_assert (was_mapped);
933 clutter_actor_set_mapped (self, FALSE);
936 case MAP_STATE_MAKE_UNREALIZED:
937 /* we only use MAKE_UNREALIZED in unparent,
938 * and unparenting a stage isn't possible.
939 * If someone wants to just unrealize a stage
940 * then clutter_actor_unrealize() doesn't
941 * go through this codepath.
943 g_warning ("Trying to force unrealize stage is not allowed");
947 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
948 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
949 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
951 g_warning ("Clutter toplevel of type '%s' is not visible, but "
952 "it is somehow still mapped",
953 _clutter_actor_get_debug_name (self));
958 ClutterActorPrivate *priv = self->priv;
959 ClutterActor *parent = priv->parent;
960 gboolean should_be_mapped;
961 gboolean may_be_realized;
962 gboolean must_be_realized;
964 should_be_mapped = FALSE;
965 may_be_realized = TRUE;
966 must_be_realized = FALSE;
968 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
970 may_be_realized = FALSE;
974 /* Maintain invariant that if parent is mapped, and we are
975 * visible, then we are mapped ... unless parent is a
976 * stage, in which case we map regardless of parent's map
977 * state but do require stage to be visible and realized.
979 * If parent is realized, that does not force us to be
980 * realized; but if parent is unrealized, that does force
981 * us to be unrealized.
983 * The reason we don't force children to realize with
984 * parents is _clutter_actor_rerealize(); if we require that
985 * a realized parent means children are realized, then to
986 * unrealize an actor we would have to unrealize its
987 * parents, which would end up meaning unrealizing and
988 * hiding the entire stage. So we allow unrealizing a
989 * child (as long as that child is not mapped) while that
990 * child still has a realized parent.
992 * Also, if we unrealize from leaf nodes to root, and
993 * realize from root to leaf, the invariants are never
994 * violated if we allow children to be unrealized
995 * while parents are realized.
997 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
998 * to force us to unmap, even though parent is still
999 * mapped. This is because we're unmapping from leaf nodes
1002 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1003 change != MAP_STATE_MAKE_UNMAPPED)
1005 gboolean parent_is_visible_realized_toplevel;
1007 parent_is_visible_realized_toplevel =
1008 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1009 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1010 CLUTTER_ACTOR_IS_REALIZED (parent));
1012 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1013 parent_is_visible_realized_toplevel)
1015 must_be_realized = TRUE;
1016 should_be_mapped = TRUE;
1020 /* if the actor has been set to be painted even if unmapped
1021 * then we should map it and check for realization as well;
1022 * this is an override for the branch of the scene graph
1023 * which begins with this node
1025 if (priv->enable_paint_unmapped)
1027 if (priv->parent == NULL)
1028 g_warning ("Attempting to map an unparented actor '%s'",
1029 _clutter_actor_get_debug_name (self));
1031 should_be_mapped = TRUE;
1032 must_be_realized = TRUE;
1035 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1036 may_be_realized = FALSE;
1039 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1042 g_warning ("Attempting to map a child that does not "
1043 "meet the necessary invariants: the actor '%s' "
1045 _clutter_actor_get_debug_name (self));
1047 g_warning ("Attempting to map a child that does not "
1048 "meet the necessary invariants: the actor '%s' "
1049 "is parented to an unmapped actor '%s'",
1050 _clutter_actor_get_debug_name (self),
1051 _clutter_actor_get_debug_name (priv->parent));
1054 /* If in reparent, we temporarily suspend unmap and unrealize.
1056 * We want to go in the order "realize, map" and "unmap, unrealize"
1060 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1061 clutter_actor_set_mapped (self, FALSE);
1064 if (must_be_realized)
1065 clutter_actor_realize (self);
1067 /* if we must be realized then we may be, presumably */
1068 g_assert (!(must_be_realized && !may_be_realized));
1071 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1072 clutter_actor_unrealize_not_hiding (self);
1075 if (should_be_mapped)
1077 if (!must_be_realized)
1078 g_warning ("Somehow we think actor '%s' should be mapped but "
1079 "not realized, which isn't allowed",
1080 _clutter_actor_get_debug_name (self));
1082 /* realization is allowed to fail (though I don't know what
1083 * an app is supposed to do about that - shouldn't it just
1084 * be a g_error? anyway, we have to avoid mapping if this
1087 if (CLUTTER_ACTOR_IS_REALIZED (self))
1088 clutter_actor_set_mapped (self, TRUE);
1092 #ifdef CLUTTER_ENABLE_DEBUG
1093 /* check all invariants were kept */
1094 clutter_actor_verify_map_state (self);
1099 clutter_actor_real_map (ClutterActor *self)
1101 ClutterActorPrivate *priv = self->priv;
1102 ClutterActor *stage, *iter;
1104 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1106 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1107 _clutter_actor_get_debug_name (self));
1109 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1111 stage = _clutter_actor_get_stage_internal (self);
1112 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1114 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1116 _clutter_actor_get_debug_name (self));
1118 /* notify on parent mapped before potentially mapping
1119 * children, so apps see a top-down notification.
1121 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1123 for (iter = self->priv->first_child;
1125 iter = iter->priv->next_sibling)
1127 clutter_actor_map (iter);
1132 * clutter_actor_map:
1133 * @self: A #ClutterActor
1135 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1136 * and realizes its children if they are visible. Does nothing if the
1137 * actor is not visible.
1139 * Calling this function is strongly disencouraged: the default
1140 * implementation of #ClutterActorClass.map() will map all the children
1141 * of an actor when mapping its parent.
1143 * When overriding map, it is mandatory to chain up to the parent
1149 clutter_actor_map (ClutterActor *self)
1151 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1153 if (CLUTTER_ACTOR_IS_MAPPED (self))
1156 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1159 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1163 clutter_actor_real_unmap (ClutterActor *self)
1165 ClutterActorPrivate *priv = self->priv;
1168 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1170 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1171 _clutter_actor_get_debug_name (self));
1173 for (iter = self->priv->first_child;
1175 iter = iter->priv->next_sibling)
1177 clutter_actor_unmap (iter);
1180 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1182 /* clear the contents of the last paint volume, so that hiding + moving +
1183 * showing will not result in the wrong area being repainted
1185 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1186 priv->last_paint_volume_valid = TRUE;
1188 /* notify on parent mapped after potentially unmapping
1189 * children, so apps see a bottom-up notification.
1191 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1193 /* relinquish keyboard focus if we were unmapped while owning it */
1194 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1196 ClutterStage *stage;
1198 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1201 _clutter_stage_release_pick_id (stage, priv->pick_id);
1205 if (stage != NULL &&
1206 clutter_stage_get_key_focus (stage) == self)
1208 clutter_stage_set_key_focus (stage, NULL);
1214 * clutter_actor_unmap:
1215 * @self: A #ClutterActor
1217 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1218 * unmaps its children if they were mapped.
1220 * Calling this function is not encouraged: the default #ClutterActor
1221 * implementation of #ClutterActorClass.unmap() will also unmap any
1222 * eventual children by default when their parent is unmapped.
1224 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1225 * chain up to the parent implementation.
1227 * <note>It is important to note that the implementation of the
1228 * #ClutterActorClass.unmap() virtual function may be called after
1229 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1230 * implementation, but it is guaranteed to be called before the
1231 * #GObjectClass.finalize() implementation.</note>
1236 clutter_actor_unmap (ClutterActor *self)
1238 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1240 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1243 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1247 clutter_actor_real_show (ClutterActor *self)
1249 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1251 ClutterActorPrivate *priv = self->priv;
1253 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1255 /* we notify on the "visible" flag in the clutter_actor_show()
1256 * wrapper so the entire show signal emission completes first
1259 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1261 /* we queue a relayout unless the actor is inside a
1262 * container that explicitly told us not to
1264 if (priv->parent != NULL &&
1265 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1267 /* While an actor is hidden the parent may not have
1268 * allocated/requested so we need to start from scratch
1269 * and avoid the short-circuiting in
1270 * clutter_actor_queue_relayout().
1272 priv->needs_width_request = FALSE;
1273 priv->needs_height_request = FALSE;
1274 priv->needs_allocation = FALSE;
1275 clutter_actor_queue_relayout (self);
1281 set_show_on_set_parent (ClutterActor *self,
1284 ClutterActorPrivate *priv = self->priv;
1286 set_show = !!set_show;
1288 if (priv->show_on_set_parent == set_show)
1291 if (priv->parent == NULL)
1293 priv->show_on_set_parent = set_show;
1294 g_object_notify_by_pspec (G_OBJECT (self),
1295 obj_props[PROP_SHOW_ON_SET_PARENT]);
1300 * clutter_actor_show:
1301 * @self: A #ClutterActor
1303 * Flags an actor to be displayed. An actor that isn't shown will not
1304 * be rendered on the stage.
1306 * Actors are visible by default.
1308 * If this function is called on an actor without a parent, the
1309 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1313 clutter_actor_show (ClutterActor *self)
1315 ClutterActorPrivate *priv;
1317 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1319 /* simple optimization */
1320 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1322 /* we still need to set the :show-on-set-parent property, in
1323 * case show() is called on an unparented actor
1325 set_show_on_set_parent (self, TRUE);
1329 #ifdef CLUTTER_ENABLE_DEBUG
1330 clutter_actor_verify_map_state (self);
1335 g_object_freeze_notify (G_OBJECT (self));
1337 set_show_on_set_parent (self, TRUE);
1339 g_signal_emit (self, actor_signals[SHOW], 0);
1340 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1342 if (priv->parent != NULL)
1343 clutter_actor_queue_redraw (priv->parent);
1345 g_object_thaw_notify (G_OBJECT (self));
1349 * clutter_actor_show_all:
1350 * @self: a #ClutterActor
1352 * Calls clutter_actor_show() on all children of an actor (if any).
1356 * Deprecated: 1.10: Actors are visible by default
1359 clutter_actor_show_all (ClutterActor *self)
1361 ClutterActorClass *klass;
1363 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1365 klass = CLUTTER_ACTOR_GET_CLASS (self);
1366 if (klass->show_all)
1367 klass->show_all (self);
1371 clutter_actor_real_hide (ClutterActor *self)
1373 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1375 ClutterActorPrivate *priv = self->priv;
1377 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1379 /* we notify on the "visible" flag in the clutter_actor_hide()
1380 * wrapper so the entire hide signal emission completes first
1383 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1385 /* we queue a relayout unless the actor is inside a
1386 * container that explicitly told us not to
1388 if (priv->parent != NULL &&
1389 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1390 clutter_actor_queue_relayout (priv->parent);
1395 * clutter_actor_hide:
1396 * @self: A #ClutterActor
1398 * Flags an actor to be hidden. A hidden actor will not be
1399 * rendered on the stage.
1401 * Actors are visible by default.
1403 * If this function is called on an actor without a parent, the
1404 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1408 clutter_actor_hide (ClutterActor *self)
1410 ClutterActorPrivate *priv;
1412 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1414 /* simple optimization */
1415 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1417 /* we still need to set the :show-on-set-parent property, in
1418 * case hide() is called on an unparented actor
1420 set_show_on_set_parent (self, FALSE);
1424 #ifdef CLUTTER_ENABLE_DEBUG
1425 clutter_actor_verify_map_state (self);
1430 g_object_freeze_notify (G_OBJECT (self));
1432 set_show_on_set_parent (self, FALSE);
1434 g_signal_emit (self, actor_signals[HIDE], 0);
1435 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1437 if (priv->parent != NULL)
1438 clutter_actor_queue_redraw (priv->parent);
1440 g_object_thaw_notify (G_OBJECT (self));
1444 * clutter_actor_hide_all:
1445 * @self: a #ClutterActor
1447 * Calls clutter_actor_hide() on all child actors (if any).
1451 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1452 * prevent its children from being painted as well.
1455 clutter_actor_hide_all (ClutterActor *self)
1457 ClutterActorClass *klass;
1459 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1461 klass = CLUTTER_ACTOR_GET_CLASS (self);
1462 if (klass->hide_all)
1463 klass->hide_all (self);
1467 * clutter_actor_realize:
1468 * @self: A #ClutterActor
1470 * Realization informs the actor that it is attached to a stage. It
1471 * can use this to allocate resources if it wanted to delay allocation
1472 * until it would be rendered. However it is perfectly acceptable for
1473 * an actor to create resources before being realized because Clutter
1474 * only ever has a single rendering context so that actor is free to
1475 * be moved from one stage to another.
1477 * This function does nothing if the actor is already realized.
1479 * Because a realized actor must have realized parent actors, calling
1480 * clutter_actor_realize() will also realize all parents of the actor.
1482 * This function does not realize child actors, except in the special
1483 * case that realizing the stage, when the stage is visible, will
1484 * suddenly map (and thus realize) the children of the stage.
1487 clutter_actor_realize (ClutterActor *self)
1489 ClutterActorPrivate *priv;
1491 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1495 #ifdef CLUTTER_ENABLE_DEBUG
1496 clutter_actor_verify_map_state (self);
1499 if (CLUTTER_ACTOR_IS_REALIZED (self))
1502 /* To be realized, our parent actors must be realized first.
1503 * This will only succeed if we're inside a toplevel.
1505 if (priv->parent != NULL)
1506 clutter_actor_realize (priv->parent);
1508 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1510 /* toplevels can be realized at any time */
1514 /* "Fail" the realization if parent is missing or unrealized;
1515 * this should really be a g_warning() not some kind of runtime
1516 * failure; how can an app possibly recover? Instead it's a bug
1517 * in the app and the app should get an explanatory warning so
1518 * someone can fix it. But for now it's too hard to fix this
1519 * because e.g. ClutterTexture needs reworking.
1521 if (priv->parent == NULL ||
1522 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1526 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1528 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1529 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1531 g_signal_emit (self, actor_signals[REALIZE], 0);
1533 /* Stage actor is allowed to unset the realized flag again in its
1534 * default signal handler, though that is a pathological situation.
1537 /* If realization "failed" we'll have to update child state. */
1538 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1542 clutter_actor_real_unrealize (ClutterActor *self)
1544 /* we must be unmapped (implying our children are also unmapped) */
1545 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1549 * clutter_actor_unrealize:
1550 * @self: A #ClutterActor
1552 * Unrealization informs the actor that it may be being destroyed or
1553 * moved to another stage. The actor may want to destroy any
1554 * underlying graphics resources at this point. However it is
1555 * perfectly acceptable for it to retain the resources until the actor
1556 * is destroyed because Clutter only ever uses a single rendering
1557 * context and all of the graphics resources are valid on any stage.
1559 * Because mapped actors must be realized, actors may not be
1560 * unrealized if they are mapped. This function hides the actor to be
1561 * sure it isn't mapped, an application-visible side effect that you
1562 * may not be expecting.
1564 * This function should not be called by application code.
1567 clutter_actor_unrealize (ClutterActor *self)
1569 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1570 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1572 /* This function should not really be in the public API, because
1573 * there isn't a good reason to call it. ClutterActor will already
1574 * unrealize things for you when it's important to do so.
1576 * If you were using clutter_actor_unrealize() in a dispose
1577 * implementation, then don't, just chain up to ClutterActor's
1580 * If you were using clutter_actor_unrealize() to implement
1581 * unrealizing children of your container, then don't, ClutterActor
1582 * will already take care of that.
1584 * If you were using clutter_actor_unrealize() to re-realize to
1585 * create your resources in a different way, then use
1586 * _clutter_actor_rerealize() (inside Clutter) or just call your
1587 * code that recreates your resources directly (outside Clutter).
1590 #ifdef CLUTTER_ENABLE_DEBUG
1591 clutter_actor_verify_map_state (self);
1594 clutter_actor_hide (self);
1596 clutter_actor_unrealize_not_hiding (self);
1599 static ClutterActorTraverseVisitFlags
1600 unrealize_actor_before_children_cb (ClutterActor *self,
1604 /* If an actor is already unrealized we know its children have also
1605 * already been unrealized... */
1606 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1607 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1609 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1611 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1614 static ClutterActorTraverseVisitFlags
1615 unrealize_actor_after_children_cb (ClutterActor *self,
1619 /* We want to unset the realized flag only _after_
1620 * child actors are unrealized, to maintain invariants.
1622 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1623 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1624 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1628 * clutter_actor_unrealize_not_hiding:
1629 * @self: A #ClutterActor
1631 * Unrealization informs the actor that it may be being destroyed or
1632 * moved to another stage. The actor may want to destroy any
1633 * underlying graphics resources at this point. However it is
1634 * perfectly acceptable for it to retain the resources until the actor
1635 * is destroyed because Clutter only ever uses a single rendering
1636 * context and all of the graphics resources are valid on any stage.
1638 * Because mapped actors must be realized, actors may not be
1639 * unrealized if they are mapped. You must hide the actor or one of
1640 * its parents before attempting to unrealize.
1642 * This function is separate from clutter_actor_unrealize() because it
1643 * does not automatically hide the actor.
1644 * Actors need not be hidden to be unrealized, they just need to
1645 * be unmapped. In fact we don't want to mess up the application's
1646 * setting of the "visible" flag, so hiding is very undesirable.
1648 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1649 * backward compatibility.
1652 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1654 _clutter_actor_traverse (self,
1655 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1656 unrealize_actor_before_children_cb,
1657 unrealize_actor_after_children_cb,
1662 * _clutter_actor_rerealize:
1663 * @self: A #ClutterActor
1664 * @callback: Function to call while unrealized
1665 * @data: data for callback
1667 * If an actor is already unrealized, this just calls the callback.
1669 * If it is realized, it unrealizes temporarily, calls the callback,
1670 * and then re-realizes the actor.
1672 * As a side effect, leaves all children of the actor unrealized if
1673 * the actor was realized but not showing. This is because when we
1674 * unrealize the actor temporarily we must unrealize its children
1675 * (e.g. children of a stage can't be realized if stage window is
1676 * gone). And we aren't clever enough to save the realization state of
1677 * all children. In most cases this should not matter, because
1678 * the children will automatically realize when they next become mapped.
1681 _clutter_actor_rerealize (ClutterActor *self,
1682 ClutterCallback callback,
1685 gboolean was_mapped;
1686 gboolean was_showing;
1687 gboolean was_realized;
1689 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1691 #ifdef CLUTTER_ENABLE_DEBUG
1692 clutter_actor_verify_map_state (self);
1695 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1696 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1697 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1699 /* Must be unmapped to unrealize. Note we only have to hide this
1700 * actor if it was mapped (if all parents were showing). If actor
1701 * is merely visible (but not mapped), then that's fine, we can
1705 clutter_actor_hide (self);
1707 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1709 /* unrealize self and all children */
1710 clutter_actor_unrealize_not_hiding (self);
1712 if (callback != NULL)
1714 (* callback) (self, data);
1718 clutter_actor_show (self); /* will realize only if mapping implies it */
1719 else if (was_realized)
1720 clutter_actor_realize (self); /* realize self and all parents */
1724 clutter_actor_real_pick (ClutterActor *self,
1725 const ClutterColor *color)
1727 /* the default implementation is just to paint a rectangle
1728 * with the same size of the actor using the passed color
1730 if (clutter_actor_should_pick_paint (self))
1732 ClutterActorBox box = { 0, };
1733 float width, height;
1735 clutter_actor_get_allocation_box (self, &box);
1737 width = box.x2 - box.x1;
1738 height = box.y2 - box.y1;
1740 cogl_set_source_color4ub (color->red,
1745 cogl_rectangle (0, 0, width, height);
1748 /* XXX - this thoroughly sucks, but we need to maintain compatibility
1749 * with existing container classes that override the pick() virtual
1750 * and chain up to the default implementation - otherwise we'll end up
1751 * painting our children twice.
1753 * this has to go away for 2.0; hopefully along the pick() itself.
1755 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1759 for (iter = self->priv->first_child;
1761 iter = iter->priv->next_sibling)
1762 clutter_actor_paint (iter);
1767 * clutter_actor_should_pick_paint:
1768 * @self: A #ClutterActor
1770 * Should be called inside the implementation of the
1771 * #ClutterActor::pick virtual function in order to check whether
1772 * the actor should paint itself in pick mode or not.
1774 * This function should never be called directly by applications.
1776 * Return value: %TRUE if the actor should paint its silhouette,
1780 clutter_actor_should_pick_paint (ClutterActor *self)
1782 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1784 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1785 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1786 CLUTTER_ACTOR_IS_REACTIVE (self)))
1793 clutter_actor_real_get_preferred_width (ClutterActor *self,
1795 gfloat *min_width_p,
1796 gfloat *natural_width_p)
1798 ClutterActorPrivate *priv = self->priv;
1800 if (priv->n_children != 0 &&
1801 priv->layout_manager != NULL)
1803 ClutterContainer *container = CLUTTER_CONTAINER (self);
1805 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1806 "for the preferred width",
1807 G_OBJECT_TYPE_NAME (priv->layout_manager),
1808 priv->layout_manager);
1810 clutter_layout_manager_get_preferred_width (priv->layout_manager,
1819 /* Default implementation is always 0x0, usually an actor
1820 * using this default is relying on someone to set the
1823 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1828 if (natural_width_p)
1829 *natural_width_p = 0;
1833 clutter_actor_real_get_preferred_height (ClutterActor *self,
1835 gfloat *min_height_p,
1836 gfloat *natural_height_p)
1838 ClutterActorPrivate *priv = self->priv;
1840 if (priv->n_children != 0 &&
1841 priv->layout_manager != NULL)
1843 ClutterContainer *container = CLUTTER_CONTAINER (self);
1845 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1846 "for the preferred height",
1847 G_OBJECT_TYPE_NAME (priv->layout_manager),
1848 priv->layout_manager);
1850 clutter_layout_manager_get_preferred_height (priv->layout_manager,
1858 /* Default implementation is always 0x0, usually an actor
1859 * using this default is relying on someone to set the
1862 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1867 if (natural_height_p)
1868 *natural_height_p = 0;
1872 clutter_actor_store_old_geometry (ClutterActor *self,
1873 ClutterActorBox *box)
1875 *box = self->priv->allocation;
1879 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
1880 const ClutterActorBox *old)
1882 ClutterActorPrivate *priv = self->priv;
1883 GObject *obj = G_OBJECT (self);
1885 g_object_freeze_notify (obj);
1887 /* to avoid excessive requisition or allocation cycles we
1888 * use the cached values.
1890 * - if we don't have an allocation we assume that we need
1892 * - if we don't have a width or a height request we notify
1894 * - if we have a valid allocation then we check the old
1895 * bounding box with the current allocation and we notify
1898 if (priv->needs_allocation)
1900 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1901 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1902 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1903 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1905 else if (priv->needs_width_request || priv->needs_height_request)
1907 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1908 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1913 gfloat widthu, heightu;
1915 xu = priv->allocation.x1;
1916 yu = priv->allocation.y1;
1917 widthu = priv->allocation.x2 - priv->allocation.x1;
1918 heightu = priv->allocation.y2 - priv->allocation.y1;
1921 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1924 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1926 if (widthu != (old->x2 - old->x1))
1927 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1929 if (heightu != (old->y2 - old->y1))
1930 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1933 g_object_thaw_notify (obj);
1937 * clutter_actor_set_allocation_internal:
1938 * @self: a #ClutterActor
1939 * @box: a #ClutterActorBox
1940 * @flags: allocation flags
1942 * Stores the allocation of @self.
1944 * This function only performs basic storage and property notification.
1946 * This function should be called by clutter_actor_set_allocation()
1947 * and by the default implementation of #ClutterActorClass.allocate().
1949 * Return value: %TRUE if the allocation of the #ClutterActor has been
1950 * changed, and %FALSE otherwise
1952 static inline gboolean
1953 clutter_actor_set_allocation_internal (ClutterActor *self,
1954 const ClutterActorBox *box,
1955 ClutterAllocationFlags flags)
1957 ClutterActorPrivate *priv = self->priv;
1959 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1960 gboolean flags_changed;
1962 ClutterActorBox old_alloc = { 0, };
1964 obj = G_OBJECT (self);
1966 g_object_freeze_notify (obj);
1968 clutter_actor_store_old_geometry (self, &old_alloc);
1970 x1_changed = priv->allocation.x1 != box->x1;
1971 y1_changed = priv->allocation.y1 != box->y1;
1972 x2_changed = priv->allocation.x2 != box->x2;
1973 y2_changed = priv->allocation.y2 != box->y2;
1975 flags_changed = priv->allocation_flags != flags;
1977 priv->allocation = *box;
1978 priv->allocation_flags = flags;
1980 /* allocation is authoritative */
1981 priv->needs_width_request = FALSE;
1982 priv->needs_height_request = FALSE;
1983 priv->needs_allocation = FALSE;
1985 if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1987 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1988 _clutter_actor_get_debug_name (self));
1990 priv->transform_valid = FALSE;
1992 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1999 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2001 g_object_thaw_notify (obj);
2006 static void clutter_actor_real_allocate (ClutterActor *self,
2007 const ClutterActorBox *box,
2008 ClutterAllocationFlags flags);
2011 clutter_actor_maybe_layout_children (ClutterActor *self,
2012 const ClutterActorBox *allocation,
2013 ClutterAllocationFlags flags)
2015 ClutterActorPrivate *priv = self->priv;
2017 /* this is going to be a bit hard to follow, so let's put an explanation
2020 * we want ClutterActor to have a default layout manager if the actor was
2021 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2023 * we also want any subclass of ClutterActor that does not override the
2024 * ::allocate() virtual function to delegate to a layout manager.
2026 * finally, we want to allow people subclassing ClutterActor and overriding
2027 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2029 * on the other hand, we want existing actor subclasses overriding the
2030 * ::allocate() virtual function and chaining up to the parent's
2031 * implementation to continue working without allocating their children
2032 * twice, or without entering an allocation loop.
2034 * for the first two points, we check if the class of the actor is
2035 * overridding the ::allocate() virtual function; if it isn't, then we
2036 * follow through with checking whether we have children and a layout
2037 * manager, and eventually calling clutter_layout_manager_allocate().
2039 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2040 * allocation flags that we got passed, and if it is present, we continue
2041 * with the check above.
2043 * if neither of these two checks yields a positive result, we just
2044 * assume that the ::allocate() virtual function that resulted in this
2045 * function being called will also allocate the children of the actor.
2048 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2051 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2057 if (priv->n_children != 0 &&
2058 priv->layout_manager != NULL)
2060 ClutterContainer *container = CLUTTER_CONTAINER (self);
2061 ClutterAllocationFlags children_flags;
2062 ClutterActorBox children_box;
2064 /* normalize the box passed to the layout manager */
2065 children_box.x1 = children_box.y1 = 0.f;
2066 children_box.x2 = (allocation->x2 - allocation->x1);
2067 children_box.y2 = (allocation->y2 - allocation->y1);
2069 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2070 * the actor's children, since it refers only to the current
2071 * actor's allocation.
2073 children_flags = flags;
2074 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2076 CLUTTER_NOTE (LAYOUT,
2077 "Allocating %d children of %s "
2078 "at { %.2f, %.2f - %.2f x %.2f } "
2081 _clutter_actor_get_debug_name (self),
2084 (allocation->x2 - allocation->x1),
2085 (allocation->y2 - allocation->y1),
2086 G_OBJECT_TYPE_NAME (priv->layout_manager));
2088 clutter_layout_manager_allocate (priv->layout_manager,
2096 clutter_actor_real_allocate (ClutterActor *self,
2097 const ClutterActorBox *box,
2098 ClutterAllocationFlags flags)
2100 ClutterActorPrivate *priv = self->priv;
2103 g_object_freeze_notify (G_OBJECT (self));
2105 changed = clutter_actor_set_allocation_internal (self, box, flags);
2107 /* we allocate our children before we notify changes in our geometry,
2108 * so that people connecting to properties will be able to get valid
2109 * data out of the sub-tree of the scene graph that has this actor at
2112 clutter_actor_maybe_layout_children (self, box, flags);
2115 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2117 priv->allocation_flags);
2119 g_object_thaw_notify (G_OBJECT (self));
2123 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2124 ClutterActor *origin)
2126 /* no point in queuing a redraw on a destroyed actor */
2127 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2130 /* NB: We can't bail out early here if the actor is hidden in case
2131 * the actor bas been cloned. In this case the clone will need to
2132 * receive the signal so it can queue its own redraw.
2135 /* calls klass->queue_redraw in default handler */
2136 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2140 clutter_actor_real_queue_redraw (ClutterActor *self,
2141 ClutterActor *origin)
2143 ClutterActor *parent;
2145 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2146 _clutter_actor_get_debug_name (self),
2147 origin != NULL ? _clutter_actor_get_debug_name (origin)
2150 /* no point in queuing a redraw on a destroyed actor */
2151 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2154 /* If the queue redraw is coming from a child then the actor has
2155 become dirty and any queued effect is no longer valid */
2158 self->priv->is_dirty = TRUE;
2159 self->priv->effect_to_redraw = NULL;
2162 /* If the actor isn't visible, we still had to emit the signal
2163 * to allow for a ClutterClone, but the appearance of the parent
2164 * won't change so we don't have to propagate up the hierarchy.
2166 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2169 /* Although we could determine here that a full stage redraw
2170 * has already been queued and immediately bail out, we actually
2171 * guarantee that we will propagate a queue-redraw signal to our
2172 * parent at least once so that it's possible to implement a
2173 * container that tracks which of its children have queued a
2176 if (self->priv->propagated_one_redraw)
2178 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2179 if (stage != NULL &&
2180 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2184 self->priv->propagated_one_redraw = TRUE;
2186 /* notify parents, if they are all visible eventually we'll
2187 * queue redraw on the stage, which queues the redraw idle.
2189 parent = clutter_actor_get_parent (self);
2192 /* this will go up recursively */
2193 _clutter_actor_signal_queue_redraw (parent, origin);
2198 clutter_actor_real_queue_relayout (ClutterActor *self)
2200 ClutterActorPrivate *priv = self->priv;
2202 /* no point in queueing a redraw on a destroyed actor */
2203 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2206 priv->needs_width_request = TRUE;
2207 priv->needs_height_request = TRUE;
2208 priv->needs_allocation = TRUE;
2210 /* reset the cached size requests */
2211 memset (priv->width_requests, 0,
2212 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2213 memset (priv->height_requests, 0,
2214 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2216 /* We need to go all the way up the hierarchy */
2217 if (priv->parent != NULL)
2218 _clutter_actor_queue_only_relayout (priv->parent);
2222 * clutter_actor_apply_relative_transform_to_point:
2223 * @self: A #ClutterActor
2224 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2225 * default #ClutterStage
2226 * @point: A point as #ClutterVertex
2227 * @vertex: (out caller-allocates): The translated #ClutterVertex
2229 * Transforms @point in coordinates relative to the actor into
2230 * ancestor-relative coordinates using the relevant transform
2231 * stack (i.e. scale, rotation, etc).
2233 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2234 * this case, the coordinates returned will be the coordinates on
2235 * the stage before the projection is applied. This is different from
2236 * the behaviour of clutter_actor_apply_transform_to_point().
2241 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2242 ClutterActor *ancestor,
2243 const ClutterVertex *point,
2244 ClutterVertex *vertex)
2249 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2250 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2251 g_return_if_fail (point != NULL);
2252 g_return_if_fail (vertex != NULL);
2257 if (ancestor == NULL)
2258 ancestor = _clutter_actor_get_stage_internal (self);
2260 if (ancestor == NULL)
2266 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2267 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2271 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2272 const ClutterVertex *vertices_in,
2273 ClutterVertex *vertices_out,
2276 ClutterActor *stage;
2277 CoglMatrix modelview;
2278 CoglMatrix projection;
2281 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2283 stage = _clutter_actor_get_stage_internal (self);
2285 /* We really can't do anything meaningful in this case so don't try
2286 * to do any transform */
2290 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2291 * that gets us to stage coordinates, we want to go all the way to eye
2293 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2295 /* Fetch the projection and viewport */
2296 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2297 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2303 _clutter_util_fully_transform_vertices (&modelview,
2314 * clutter_actor_apply_transform_to_point:
2315 * @self: A #ClutterActor
2316 * @point: A point as #ClutterVertex
2317 * @vertex: (out caller-allocates): The translated #ClutterVertex
2319 * Transforms @point in coordinates relative to the actor
2320 * into screen-relative coordinates with the current actor
2321 * transformation (i.e. scale, rotation, etc)
2326 clutter_actor_apply_transform_to_point (ClutterActor *self,
2327 const ClutterVertex *point,
2328 ClutterVertex *vertex)
2330 g_return_if_fail (point != NULL);
2331 g_return_if_fail (vertex != NULL);
2332 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2336 * _clutter_actor_get_relative_transformation_matrix:
2337 * @self: The actor whose coordinate space you want to transform from.
2338 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2339 * or %NULL if you want to transform all the way to eye coordinates.
2340 * @matrix: A #CoglMatrix to store the transformation
2342 * This gets a transformation @matrix that will transform coordinates from the
2343 * coordinate space of @self into the coordinate space of @ancestor.
2345 * For example if you need a matrix that can transform the local actor
2346 * coordinates of @self into stage coordinates you would pass the actor's stage
2347 * pointer as the @ancestor.
2349 * If you pass %NULL then the transformation will take you all the way through
2350 * to eye coordinates. This can be useful if you want to extract the entire
2351 * modelview transform that Clutter applies before applying the projection
2352 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2353 * using cogl_set_modelview_matrix() for example then you would want a matrix
2354 * that transforms into eye coordinates.
2356 * <note><para>This function explicitly initializes the given @matrix. If you just
2357 * want clutter to multiply a relative transformation with an existing matrix
2358 * you can use clutter_actor_apply_relative_transformation_matrix()
2359 * instead.</para></note>
2362 /* XXX: We should consider caching the stage relative modelview along with
2363 * the actor itself */
2365 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2366 ClutterActor *ancestor,
2369 cogl_matrix_init_identity (matrix);
2371 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2374 /* Project the given @box into stage window coordinates, writing the
2375 * transformed vertices to @verts[]. */
2377 _clutter_actor_transform_and_project_box (ClutterActor *self,
2378 const ClutterActorBox *box,
2379 ClutterVertex verts[])
2381 ClutterVertex box_vertices[4];
2383 box_vertices[0].x = box->x1;
2384 box_vertices[0].y = box->y1;
2385 box_vertices[0].z = 0;
2386 box_vertices[1].x = box->x2;
2387 box_vertices[1].y = box->y1;
2388 box_vertices[1].z = 0;
2389 box_vertices[2].x = box->x1;
2390 box_vertices[2].y = box->y2;
2391 box_vertices[2].z = 0;
2392 box_vertices[3].x = box->x2;
2393 box_vertices[3].y = box->y2;
2394 box_vertices[3].z = 0;
2397 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2401 * clutter_actor_get_allocation_vertices:
2402 * @self: A #ClutterActor
2403 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2404 * against, or %NULL to use the #ClutterStage
2405 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2406 * location for an array of 4 #ClutterVertex in which to store the result
2408 * Calculates the transformed coordinates of the four corners of the
2409 * actor in the plane of @ancestor. The returned vertices relate to
2410 * the #ClutterActorBox coordinates as follows:
2412 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2413 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2414 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2415 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2418 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2419 * this case, the coordinates returned will be the coordinates on
2420 * the stage before the projection is applied. This is different from
2421 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2426 clutter_actor_get_allocation_vertices (ClutterActor *self,
2427 ClutterActor *ancestor,
2428 ClutterVertex verts[])
2430 ClutterActorPrivate *priv;
2431 ClutterActorBox box;
2432 ClutterVertex vertices[4];
2433 CoglMatrix modelview;
2435 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2436 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2438 if (ancestor == NULL)
2439 ancestor = _clutter_actor_get_stage_internal (self);
2441 /* Fallback to a NOP transform if the actor isn't parented under a
2443 if (ancestor == NULL)
2448 /* if the actor needs to be allocated we force a relayout, so that
2449 * we will have valid values to use in the transformations */
2450 if (priv->needs_allocation)
2452 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2454 _clutter_stage_maybe_relayout (stage);
2457 box.x1 = box.y1 = 0;
2458 /* The result isn't really meaningful in this case but at
2459 * least try to do something *vaguely* reasonable... */
2460 clutter_actor_get_size (self, &box.x2, &box.y2);
2464 clutter_actor_get_allocation_box (self, &box);
2466 vertices[0].x = box.x1;
2467 vertices[0].y = box.y1;
2469 vertices[1].x = box.x2;
2470 vertices[1].y = box.y1;
2472 vertices[2].x = box.x1;
2473 vertices[2].y = box.y2;
2475 vertices[3].x = box.x2;
2476 vertices[3].y = box.y2;
2479 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2482 cogl_matrix_transform_points (&modelview,
2484 sizeof (ClutterVertex),
2486 sizeof (ClutterVertex),
2492 * clutter_actor_get_abs_allocation_vertices:
2493 * @self: A #ClutterActor
2494 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2495 * of 4 #ClutterVertex where to store the result.
2497 * Calculates the transformed screen coordinates of the four corners of
2498 * the actor; the returned vertices relate to the #ClutterActorBox
2499 * coordinates as follows:
2501 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2502 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2503 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2504 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2510 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2511 ClutterVertex verts[])
2513 ClutterActorPrivate *priv;
2514 ClutterActorBox actor_space_allocation;
2516 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2520 /* if the actor needs to be allocated we force a relayout, so that
2521 * the actor allocation box will be valid for
2522 * _clutter_actor_transform_and_project_box()
2524 if (priv->needs_allocation)
2526 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2527 /* There's nothing meaningful we can do now */
2531 _clutter_stage_maybe_relayout (stage);
2534 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2535 * own coordinate space... */
2536 actor_space_allocation.x1 = 0;
2537 actor_space_allocation.y1 = 0;
2538 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2539 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2540 _clutter_actor_transform_and_project_box (self,
2541 &actor_space_allocation,
2546 clutter_actor_real_apply_transform (ClutterActor *self,
2549 ClutterActorPrivate *priv = self->priv;
2551 if (!priv->transform_valid)
2553 CoglMatrix *transform = &priv->transform;
2554 const ClutterTransformInfo *info;
2556 info = _clutter_actor_get_transform_info_or_defaults (self);
2558 cogl_matrix_init_identity (transform);
2560 cogl_matrix_translate (transform,
2561 priv->allocation.x1,
2562 priv->allocation.y1,
2566 cogl_matrix_translate (transform, 0, 0, priv->z);
2569 * because the rotation involves translations, we must scale
2570 * before applying the rotations (if we apply the scale after
2571 * the rotations, the translations included in the rotation are
2572 * not scaled and so the entire object will move on the screen
2573 * as a result of rotating it).
2575 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2577 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2578 &info->scale_center,
2579 cogl_matrix_scale (transform,
2586 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2588 cogl_matrix_rotate (transform,
2593 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2595 cogl_matrix_rotate (transform,
2600 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2602 cogl_matrix_rotate (transform,
2606 if (!clutter_anchor_coord_is_zero (&info->anchor))
2610 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2611 cogl_matrix_translate (transform, -x, -y, -z);
2614 priv->transform_valid = TRUE;
2617 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2620 /* Applies the transforms associated with this actor to the given
2623 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2626 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2630 * clutter_actor_apply_relative_transformation_matrix:
2631 * @self: The actor whose coordinate space you want to transform from.
2632 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2633 * or %NULL if you want to transform all the way to eye coordinates.
2634 * @matrix: A #CoglMatrix to apply the transformation too.
2636 * This multiplies a transform with @matrix that will transform coordinates
2637 * from the coordinate space of @self into the coordinate space of @ancestor.
2639 * For example if you need a matrix that can transform the local actor
2640 * coordinates of @self into stage coordinates you would pass the actor's stage
2641 * pointer as the @ancestor.
2643 * If you pass %NULL then the transformation will take you all the way through
2644 * to eye coordinates. This can be useful if you want to extract the entire
2645 * modelview transform that Clutter applies before applying the projection
2646 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2647 * using cogl_set_modelview_matrix() for example then you would want a matrix
2648 * that transforms into eye coordinates.
2650 * <note>This function doesn't initialize the given @matrix, it simply
2651 * multiplies the requested transformation matrix with the existing contents of
2652 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2653 * before calling this function, or you can use
2654 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2657 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2658 ClutterActor *ancestor,
2661 ClutterActor *parent;
2663 /* Note we terminate before ever calling stage->apply_transform()
2664 * since that would conceptually be relative to the underlying
2665 * window OpenGL coordinates so we'd need a special @ancestor
2666 * value to represent the fake parent of the stage. */
2667 if (self == ancestor)
2670 parent = clutter_actor_get_parent (self);
2673 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2676 _clutter_actor_apply_modelview_transform (self, matrix);
2680 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2681 ClutterPaintVolume *pv,
2683 const CoglColor *color)
2685 static CoglPipeline *outline = NULL;
2686 CoglPrimitive *prim;
2687 ClutterVertex line_ends[12 * 2];
2690 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2691 /* XXX: at some point we'll query this from the stage but we can't
2692 * do that until the osx backend uses Cogl natively. */
2693 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2695 if (outline == NULL)
2696 outline = cogl_pipeline_new (ctx);
2698 _clutter_paint_volume_complete (pv);
2700 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2703 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2704 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2705 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2706 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2711 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2712 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2713 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2714 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2716 /* Lines connecting front face to back face */
2717 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2718 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2719 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2720 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2723 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2725 (CoglVertexP3 *)line_ends);
2727 cogl_pipeline_set_color (outline, color);
2728 cogl_framebuffer_draw_primitive (fb, outline, prim);
2729 cogl_object_unref (prim);
2733 PangoLayout *layout;
2734 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2735 pango_layout_set_text (layout, label, -1);
2736 cogl_pango_render_layout (layout,
2741 g_object_unref (layout);
2746 _clutter_actor_draw_paint_volume (ClutterActor *self)
2748 ClutterPaintVolume *pv;
2751 pv = _clutter_actor_get_paint_volume_mutable (self);
2754 gfloat width, height;
2755 ClutterPaintVolume fake_pv;
2757 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2758 _clutter_paint_volume_init_static (&fake_pv, stage);
2760 clutter_actor_get_size (self, &width, &height);
2761 clutter_paint_volume_set_width (&fake_pv, width);
2762 clutter_paint_volume_set_height (&fake_pv, height);
2764 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2765 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2766 _clutter_actor_get_debug_name (self),
2769 clutter_paint_volume_free (&fake_pv);
2773 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2774 _clutter_actor_draw_paint_volume_full (self, pv,
2775 _clutter_actor_get_debug_name (self),
2781 _clutter_actor_paint_cull_result (ClutterActor *self,
2783 ClutterCullResult result)
2785 ClutterPaintVolume *pv;
2790 if (result == CLUTTER_CULL_RESULT_IN)
2791 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2792 else if (result == CLUTTER_CULL_RESULT_OUT)
2793 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2795 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2798 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2800 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2801 _clutter_actor_draw_paint_volume_full (self, pv,
2802 _clutter_actor_get_debug_name (self),
2806 PangoLayout *layout;
2808 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2809 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2810 cogl_set_source_color (&color);
2812 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2813 pango_layout_set_text (layout, label, -1);
2814 cogl_pango_render_layout (layout,
2820 g_object_unref (layout);
2824 static int clone_paint_level = 0;
2827 _clutter_actor_push_clone_paint (void)
2829 clone_paint_level++;
2833 _clutter_actor_pop_clone_paint (void)
2835 clone_paint_level--;
2839 in_clone_paint (void)
2841 return clone_paint_level > 0;
2844 /* Returns TRUE if the actor can be ignored */
2845 /* FIXME: we should return a ClutterCullResult, and
2846 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2847 * means there's no point in trying to cull descendants of the current
2850 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2852 ClutterActorPrivate *priv = self->priv;
2853 ClutterActor *stage;
2854 const ClutterPlane *stage_clip;
2856 if (!priv->last_paint_volume_valid)
2858 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2859 "->last_paint_volume_valid == FALSE",
2860 _clutter_actor_get_debug_name (self));
2864 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2867 stage = _clutter_actor_get_stage_internal (self);
2868 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2869 if (G_UNLIKELY (!stage_clip))
2871 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2872 "No stage clip set",
2873 _clutter_actor_get_debug_name (self));
2877 if (cogl_get_draw_framebuffer () !=
2878 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2880 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2881 "Current framebuffer doesn't correspond to stage",
2882 _clutter_actor_get_debug_name (self));
2887 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2892 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2894 ClutterActorPrivate *priv = self->priv;
2895 const ClutterPaintVolume *pv;
2897 if (priv->last_paint_volume_valid)
2899 clutter_paint_volume_free (&priv->last_paint_volume);
2900 priv->last_paint_volume_valid = FALSE;
2903 pv = clutter_actor_get_paint_volume (self);
2906 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2907 "Actor failed to report a paint volume",
2908 _clutter_actor_get_debug_name (self));
2912 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2914 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2915 NULL); /* eye coordinates */
2917 priv->last_paint_volume_valid = TRUE;
2920 static inline gboolean
2921 actor_has_shader_data (ClutterActor *self)
2923 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2927 _clutter_actor_get_pick_id (ClutterActor *self)
2929 if (self->priv->pick_id < 0)
2932 return self->priv->pick_id;
2935 /* This is the same as clutter_actor_add_effect except that it doesn't
2936 queue a redraw and it doesn't notify on the effect property */
2938 _clutter_actor_add_effect_internal (ClutterActor *self,
2939 ClutterEffect *effect)
2941 ClutterActorPrivate *priv = self->priv;
2943 if (priv->effects == NULL)
2945 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2946 priv->effects->actor = self;
2949 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2952 /* This is the same as clutter_actor_remove_effect except that it doesn't
2953 queue a redraw and it doesn't notify on the effect property */
2955 _clutter_actor_remove_effect_internal (ClutterActor *self,
2956 ClutterEffect *effect)
2958 ClutterActorPrivate *priv = self->priv;
2960 if (priv->effects == NULL)
2963 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2967 needs_flatten_effect (ClutterActor *self)
2969 ClutterActorPrivate *priv = self->priv;
2971 if (G_UNLIKELY (clutter_paint_debug_flags &
2972 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2975 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2977 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2979 if (clutter_actor_get_paint_opacity (self) < 255 &&
2980 clutter_actor_has_overlaps (self))
2988 add_or_remove_flatten_effect (ClutterActor *self)
2990 ClutterActorPrivate *priv = self->priv;
2992 /* Add or remove the flatten effect depending on the
2993 offscreen-redirect property. */
2994 if (needs_flatten_effect (self))
2996 if (priv->flatten_effect == NULL)
2998 ClutterActorMeta *actor_meta;
3001 priv->flatten_effect = _clutter_flatten_effect_new ();
3002 /* Keep a reference to the effect so that we can queue
3004 g_object_ref_sink (priv->flatten_effect);
3006 /* Set the priority of the effect to high so that it will
3007 always be applied to the actor first. It uses an internal
3008 priority so that it won't be visible to applications */
3009 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3010 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3011 _clutter_actor_meta_set_priority (actor_meta, priority);
3013 /* This will add the effect without queueing a redraw */
3014 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3019 if (priv->flatten_effect != NULL)
3021 /* Destroy the effect so that it will lose its fbo cache of
3023 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3024 g_object_unref (priv->flatten_effect);
3025 priv->flatten_effect = NULL;
3031 clutter_actor_real_paint (ClutterActor *actor)
3033 ClutterActorPrivate *priv = actor->priv;
3036 /* paint the background color, if set */
3037 if (priv->bg_color_set)
3039 float width, height;
3042 clutter_actor_box_get_size (&priv->allocation, &width, &height);
3044 real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3045 * priv->bg_color.alpha
3048 cogl_set_source_color4ub (priv->bg_color.red,
3049 priv->bg_color.green,
3050 priv->bg_color.blue,
3053 cogl_rectangle (0, 0, width, height);
3056 for (iter = priv->first_child;
3058 iter = iter->priv->next_sibling)
3060 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3061 _clutter_actor_get_debug_name (iter),
3062 _clutter_actor_get_debug_name (actor),
3063 iter->priv->allocation.x1,
3064 iter->priv->allocation.y1,
3065 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3066 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3068 clutter_actor_paint (iter);
3073 * clutter_actor_paint:
3074 * @self: A #ClutterActor
3076 * Renders the actor to display.
3078 * This function should not be called directly by applications.
3079 * Call clutter_actor_queue_redraw() to queue paints, instead.
3081 * This function is context-aware, and will either cause a
3082 * regular paint or a pick paint.
3084 * This function will emit the #ClutterActor::paint signal or
3085 * the #ClutterActor::pick signal, depending on the context.
3087 * This function does not paint the actor if the actor is set to 0,
3088 * unless it is performing a pick paint.
3091 clutter_actor_paint (ClutterActor *self)
3093 ClutterActorPrivate *priv;
3094 ClutterPickMode pick_mode;
3095 gboolean clip_set = FALSE;
3096 gboolean shader_applied = FALSE;
3098 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3099 "Actor real-paint counter",
3100 "Increments each time any actor is painted",
3101 0 /* no application private data */);
3102 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3103 "Actor pick-paint counter",
3104 "Increments each time any actor is painted "
3106 0 /* no application private data */);
3108 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3110 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3115 pick_mode = _clutter_context_get_pick_mode ();
3117 if (pick_mode == CLUTTER_PICK_NONE)
3118 priv->propagated_one_redraw = FALSE;
3120 /* It's an important optimization that we consider painting of
3121 * actors with 0 opacity to be a NOP... */
3122 if (pick_mode == CLUTTER_PICK_NONE &&
3123 /* ignore top-levels, since they might be transparent */
3124 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3125 /* Use the override opacity if its been set */
3126 ((priv->opacity_override >= 0) ?
3127 priv->opacity_override : priv->opacity) == 0)
3130 /* if we aren't paintable (not in a toplevel with all
3131 * parents paintable) then do nothing.
3133 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3136 /* mark that we are in the paint process */
3137 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3141 if (priv->enable_model_view_transform)
3145 /* XXX: It could be better to cache the modelview with the actor
3146 * instead of progressively building up the transformations on
3147 * the matrix stack every time we paint. */
3148 cogl_get_modelview_matrix (&matrix);
3149 _clutter_actor_apply_modelview_transform (self, &matrix);
3151 #ifdef CLUTTER_ENABLE_DEBUG
3152 /* Catch when out-of-band transforms have been made by actors not as part
3153 * of an apply_transform vfunc... */
3154 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3156 CoglMatrix expected_matrix;
3158 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3161 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3163 GString *buf = g_string_sized_new (1024);
3164 ClutterActor *parent;
3167 while (parent != NULL)
3169 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3171 if (parent->priv->parent != NULL)
3172 g_string_append (buf, "->");
3174 parent = parent->priv->parent;
3177 g_warning ("Unexpected transform found when painting actor "
3178 "\"%s\". This will be caused by one of the actor's "
3179 "ancestors (%s) using the Cogl API directly to transform "
3180 "children instead of using ::apply_transform().",
3181 _clutter_actor_get_debug_name (self),
3184 g_string_free (buf, TRUE);
3187 #endif /* CLUTTER_ENABLE_DEBUG */
3189 cogl_set_modelview_matrix (&matrix);
3194 cogl_clip_push_rectangle (priv->clip.x,
3196 priv->clip.x + priv->clip.width,
3197 priv->clip.y + priv->clip.height);
3200 else if (priv->clip_to_allocation)
3202 gfloat width, height;
3204 width = priv->allocation.x2 - priv->allocation.x1;
3205 height = priv->allocation.y2 - priv->allocation.y1;
3207 cogl_clip_push_rectangle (0, 0, width, height);
3211 if (pick_mode == CLUTTER_PICK_NONE)
3213 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3215 /* We check whether we need to add the flatten effect before
3216 each paint so that we can avoid having a mechanism for
3217 applications to notify when the value of the
3218 has_overlaps virtual changes. */
3219 add_or_remove_flatten_effect (self);
3222 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3224 /* We save the current paint volume so that the next time the
3225 * actor queues a redraw we can constrain the redraw to just
3226 * cover the union of the new bounding box and the old.
3228 * We also fetch the current paint volume to perform culling so
3229 * we can avoid painting actors outside the current clip region.
3231 * If we are painting inside a clone, we should neither update
3232 * the paint volume or use it to cull painting, since the paint
3233 * box represents the location of the source actor on the
3236 * XXX: We are starting to do a lot of vertex transforms on
3237 * the CPU in a typical paint, so at some point we should
3238 * audit these and consider caching some things.
3240 * NB: We don't perform culling while picking at this point because
3241 * clutter-stage.c doesn't setup the clipping planes appropriately.
3243 * NB: We don't want to update the last-paint-volume during picking
3244 * because the last-paint-volume is used to determine the old screen
3245 * space location of an actor that has moved so we can know the
3246 * minimal region to redraw to clear an old view of the actor. If we
3247 * update this during picking then by the time we come around to
3248 * paint then the last-paint-volume would likely represent the new
3249 * actor position not the old.
3251 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3254 /* annoyingly gcc warns if uninitialized even though
3255 * the initialization is redundant :-( */
3256 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3258 if (G_LIKELY ((clutter_paint_debug_flags &
3259 (CLUTTER_DEBUG_DISABLE_CULLING |
3260 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3261 (CLUTTER_DEBUG_DISABLE_CULLING |
3262 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3263 _clutter_actor_update_last_paint_volume (self);
3265 success = cull_actor (self, &result);
3267 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3268 _clutter_actor_paint_cull_result (self, success, result);
3269 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3273 if (priv->effects == NULL)
3275 if (pick_mode == CLUTTER_PICK_NONE &&
3276 actor_has_shader_data (self))
3278 _clutter_actor_shader_pre_paint (self, FALSE);
3279 shader_applied = TRUE;
3282 priv->next_effect_to_paint = NULL;
3285 priv->next_effect_to_paint =
3286 _clutter_meta_group_peek_metas (priv->effects);
3288 clutter_actor_continue_paint (self);
3291 _clutter_actor_shader_post_paint (self);
3293 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3294 pick_mode == CLUTTER_PICK_NONE))
3295 _clutter_actor_draw_paint_volume (self);
3298 /* If we make it here then the actor has run through a complete
3299 paint run including all the effects so it's no longer dirty */
3300 if (pick_mode == CLUTTER_PICK_NONE)
3301 priv->is_dirty = FALSE;
3308 /* paint sequence complete */
3309 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3313 * clutter_actor_continue_paint:
3314 * @self: A #ClutterActor
3316 * Run the next stage of the paint sequence. This function should only
3317 * be called within the implementation of the ‘run’ virtual of a
3318 * #ClutterEffect. It will cause the run method of the next effect to
3319 * be applied, or it will paint the actual actor if the current effect
3320 * is the last effect in the chain.
3325 clutter_actor_continue_paint (ClutterActor *self)
3327 ClutterActorPrivate *priv;
3329 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3330 /* This should only be called from with in the ‘run’ implementation
3331 of a ClutterEffect */
3332 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3336 /* Skip any effects that are disabled */
3337 while (priv->next_effect_to_paint &&
3338 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3339 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3341 /* If this has come from the last effect then we'll just paint the
3343 if (priv->next_effect_to_paint == NULL)
3345 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3347 g_signal_emit (self, actor_signals[PAINT], 0);
3351 ClutterColor col = { 0, };
3353 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3355 /* Actor will then paint silhouette of itself in supplied
3356 * color. See clutter_stage_get_actor_at_pos() for where
3357 * picking is enabled.
3359 g_signal_emit (self, actor_signals[PICK], 0, &col);
3364 ClutterEffect *old_current_effect;
3365 ClutterEffectPaintFlags run_flags = 0;
3367 /* Cache the current effect so that we can put it back before
3369 old_current_effect = priv->current_effect;
3371 priv->current_effect = priv->next_effect_to_paint->data;
3372 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3374 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3378 /* If there's an effect queued with this redraw then all
3379 effects up to that one will be considered dirty. It
3380 is expected the queued effect will paint the cached
3381 image and not call clutter_actor_continue_paint again
3382 (although it should work ok if it does) */
3383 if (priv->effect_to_redraw == NULL ||
3384 priv->current_effect != priv->effect_to_redraw)
3385 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3388 _clutter_effect_paint (priv->current_effect, run_flags);
3392 /* We can't determine when an actor has been modified since
3393 its last pick so lets just assume it has always been
3395 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3397 _clutter_effect_pick (priv->current_effect, run_flags);
3400 priv->current_effect = old_current_effect;
3404 static ClutterActorTraverseVisitFlags
3405 invalidate_queue_redraw_entry (ClutterActor *self,
3409 ClutterActorPrivate *priv = self->priv;
3411 if (priv->queue_redraw_entry != NULL)
3413 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3414 priv->queue_redraw_entry = NULL;
3417 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3421 remove_child (ClutterActor *self,
3422 ClutterActor *child)
3424 ClutterActor *prev_sibling, *next_sibling;
3426 prev_sibling = child->priv->prev_sibling;
3427 next_sibling = child->priv->next_sibling;
3429 if (prev_sibling != NULL)
3430 prev_sibling->priv->next_sibling = next_sibling;
3432 if (next_sibling != NULL)
3433 next_sibling->priv->prev_sibling = prev_sibling;
3435 if (self->priv->first_child == child)
3436 self->priv->first_child = next_sibling;
3438 if (self->priv->last_child == child)
3439 self->priv->last_child = prev_sibling;
3441 child->priv->parent = NULL;
3442 child->priv->prev_sibling = NULL;
3443 child->priv->next_sibling = NULL;
3447 REMOVE_CHILD_DESTROY_META = 1 << 0,
3448 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3449 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3450 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3451 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3452 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3454 /* default flags for public API */
3455 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3456 REMOVE_CHILD_EMIT_PARENT_SET |
3457 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3458 REMOVE_CHILD_CHECK_STATE |
3459 REMOVE_CHILD_FLUSH_QUEUE |
3460 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3462 /* flags for legacy/deprecated API */
3463 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3464 REMOVE_CHILD_FLUSH_QUEUE |
3465 REMOVE_CHILD_EMIT_PARENT_SET |
3466 REMOVE_CHILD_NOTIFY_FIRST_LAST
3467 } ClutterActorRemoveChildFlags;
3470 * clutter_actor_remove_child_internal:
3471 * @self: a #ClutterActor
3472 * @child: the child of @self that has to be removed
3473 * @flags: control the removal operations
3475 * Removes @child from the list of children of @self.
3478 clutter_actor_remove_child_internal (ClutterActor *self,
3479 ClutterActor *child,
3480 ClutterActorRemoveChildFlags flags)
3482 ClutterActor *old_first, *old_last;
3483 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3484 gboolean flush_queue;
3485 gboolean notify_first_last;
3486 gboolean was_mapped;
3488 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3489 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3490 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3491 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3492 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3493 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3495 g_object_freeze_notify (G_OBJECT (self));
3498 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3502 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3504 /* we need to unrealize *before* we set parent_actor to NULL,
3505 * because in an unrealize method actors are dissociating from the
3506 * stage, which means they need to be able to
3507 * clutter_actor_get_stage().
3509 * yhis should unmap and unrealize, unless we're reparenting.
3511 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3518 /* We take this opportunity to invalidate any queue redraw entry
3519 * associated with the actor and descendants since we won't be able to
3520 * determine the appropriate stage after this.
3522 * we do this after we updated the mapped state because actors might
3523 * end up queueing redraws inside their mapped/unmapped virtual
3524 * functions, and if we invalidate the redraw entry we could end up
3525 * with an inconsistent state and weird memory corruption. see
3528 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3529 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3531 _clutter_actor_traverse (child,
3533 invalidate_queue_redraw_entry,
3538 old_first = self->priv->first_child;
3539 old_last = self->priv->last_child;
3541 remove_child (self, child);
3543 self->priv->n_children -= 1;
3545 self->priv->age += 1;
3547 /* clutter_actor_reparent() will emit ::parent-set for us */
3548 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3549 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3551 /* if the child was mapped then we need to relayout ourselves to account
3552 * for the removed child
3555 clutter_actor_queue_relayout (self);
3557 /* we need to emit the signal before dropping the reference */
3558 if (emit_actor_removed)
3559 g_signal_emit_by_name (self, "actor-removed", child);
3561 if (notify_first_last)
3563 if (old_first != self->priv->first_child)
3564 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3566 if (old_last != self->priv->last_child)
3567 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3570 g_object_thaw_notify (G_OBJECT (self));
3572 /* remove the reference we acquired in clutter_actor_add_child() */
3573 g_object_unref (child);
3576 static const ClutterTransformInfo default_transform_info = {
3577 0.0, { 0, }, /* rotation-x */
3578 0.0, { 0, }, /* rotation-y */
3579 0.0, { 0, }, /* rotation-z */
3581 1.0, 1.0, { 0, }, /* scale */
3583 { 0, }, /* anchor */
3587 * _clutter_actor_get_transform_info_or_defaults:
3588 * @self: a #ClutterActor
3590 * Retrieves the ClutterTransformInfo structure associated to an actor.
3592 * If the actor does not have a ClutterTransformInfo structure associated
3593 * to it, then the default structure will be returned.
3595 * This function should only be used for getters.
3597 * Return value: a const pointer to the ClutterTransformInfo structure
3599 const ClutterTransformInfo *
3600 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3602 ClutterTransformInfo *info;
3604 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3608 return &default_transform_info;
3612 clutter_transform_info_free (gpointer data)
3615 g_slice_free (ClutterTransformInfo, data);
3619 * _clutter_actor_get_transform_info:
3620 * @self: a #ClutterActor
3622 * Retrieves a pointer to the ClutterTransformInfo structure.
3624 * If the actor does not have a ClutterTransformInfo associated to it, one
3625 * will be created and initialized to the default values.
3627 * This function should be used for setters.
3629 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3632 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3635 ClutterTransformInfo *
3636 _clutter_actor_get_transform_info (ClutterActor *self)
3638 ClutterTransformInfo *info;
3640 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3643 info = g_slice_new (ClutterTransformInfo);
3645 *info = default_transform_info;
3647 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3649 clutter_transform_info_free);
3656 * clutter_actor_set_rotation_angle_internal:
3657 * @self: a #ClutterActor
3658 * @axis: the axis of the angle to change
3659 * @angle: the angle of rotation
3661 * Sets the rotation angle on the given axis without affecting the
3662 * rotation center point.
3665 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3666 ClutterRotateAxis axis,
3669 GObject *obj = G_OBJECT (self);
3670 ClutterTransformInfo *info;
3672 info = _clutter_actor_get_transform_info (self);
3674 g_object_freeze_notify (obj);
3678 case CLUTTER_X_AXIS:
3679 info->rx_angle = angle;
3680 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3683 case CLUTTER_Y_AXIS:
3684 info->ry_angle = angle;
3685 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3688 case CLUTTER_Z_AXIS:
3689 info->rz_angle = angle;
3690 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3694 self->priv->transform_valid = FALSE;
3696 g_object_thaw_notify (obj);
3698 clutter_actor_queue_redraw (self);
3702 * clutter_actor_set_rotation_center_internal:
3703 * @self: a #ClutterActor
3704 * @axis: the axis of the center to change
3705 * @center: the coordinates of the rotation center
3707 * Sets the rotation center on the given axis without affecting the
3711 clutter_actor_set_rotation_center_internal (ClutterActor *self,
3712 ClutterRotateAxis axis,
3713 const ClutterVertex *center)
3715 GObject *obj = G_OBJECT (self);
3716 ClutterTransformInfo *info;
3717 ClutterVertex v = { 0, 0, 0 };
3719 info = _clutter_actor_get_transform_info (self);
3724 g_object_freeze_notify (obj);
3728 case CLUTTER_X_AXIS:
3729 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3730 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3733 case CLUTTER_Y_AXIS:
3734 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3735 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3738 case CLUTTER_Z_AXIS:
3739 /* if the previously set rotation center was fractional, then
3740 * setting explicit coordinates will have to notify the
3741 * :rotation-center-z-gravity property as well
3743 if (info->rz_center.is_fractional)
3744 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3746 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3747 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3751 self->priv->transform_valid = FALSE;
3753 g_object_thaw_notify (obj);
3755 clutter_actor_queue_redraw (self);
3759 clutter_actor_set_scale_factor (ClutterActor *self,
3760 ClutterRotateAxis axis,
3763 GObject *obj = G_OBJECT (self);
3764 ClutterTransformInfo *info;
3766 info = _clutter_actor_get_transform_info (self);
3768 g_object_freeze_notify (obj);
3772 case CLUTTER_X_AXIS:
3773 info->scale_x = factor;
3774 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3777 case CLUTTER_Y_AXIS:
3778 info->scale_y = factor;
3779 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3783 g_assert_not_reached ();
3786 self->priv->transform_valid = FALSE;
3788 clutter_actor_queue_redraw (self);
3790 g_object_thaw_notify (obj);
3794 clutter_actor_set_scale_center (ClutterActor *self,
3795 ClutterRotateAxis axis,
3798 GObject *obj = G_OBJECT (self);
3799 ClutterTransformInfo *info;
3800 gfloat center_x, center_y;
3802 info = _clutter_actor_get_transform_info (self);
3804 g_object_freeze_notify (obj);
3806 /* get the current scale center coordinates */
3807 clutter_anchor_coord_get_units (self, &info->scale_center,
3812 /* we need to notify this too, because setting explicit coordinates will
3813 * change the gravity as a side effect
3815 if (info->scale_center.is_fractional)
3816 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3820 case CLUTTER_X_AXIS:
3821 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3822 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3825 case CLUTTER_Y_AXIS:
3826 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3827 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3831 g_assert_not_reached ();
3834 self->priv->transform_valid = FALSE;
3836 clutter_actor_queue_redraw (self);
3838 g_object_thaw_notify (obj);
3842 clutter_actor_set_anchor_coord (ClutterActor *self,
3843 ClutterRotateAxis axis,
3846 GObject *obj = G_OBJECT (self);
3847 ClutterTransformInfo *info;
3848 gfloat anchor_x, anchor_y;
3850 info = _clutter_actor_get_transform_info (self);
3852 g_object_freeze_notify (obj);
3854 clutter_anchor_coord_get_units (self, &info->anchor,
3859 if (info->anchor.is_fractional)
3860 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3864 case CLUTTER_X_AXIS:
3865 clutter_anchor_coord_set_units (&info->anchor,
3869 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3872 case CLUTTER_Y_AXIS:
3873 clutter_anchor_coord_set_units (&info->anchor,
3877 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3881 g_assert_not_reached ();
3884 self->priv->transform_valid = FALSE;
3886 clutter_actor_queue_redraw (self);
3888 g_object_thaw_notify (obj);
3892 clutter_actor_set_property (GObject *object,
3894 const GValue *value,
3897 ClutterActor *actor = CLUTTER_ACTOR (object);
3898 ClutterActorPrivate *priv = actor->priv;
3903 clutter_actor_set_x (actor, g_value_get_float (value));
3907 clutter_actor_set_y (actor, g_value_get_float (value));
3911 clutter_actor_set_width (actor, g_value_get_float (value));
3915 clutter_actor_set_height (actor, g_value_get_float (value));
3919 clutter_actor_set_x (actor, g_value_get_float (value));
3923 clutter_actor_set_y (actor, g_value_get_float (value));
3926 case PROP_FIXED_POSITION_SET:
3927 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3930 case PROP_MIN_WIDTH:
3931 clutter_actor_set_min_width (actor, g_value_get_float (value));
3934 case PROP_MIN_HEIGHT:
3935 clutter_actor_set_min_height (actor, g_value_get_float (value));
3938 case PROP_NATURAL_WIDTH:
3939 clutter_actor_set_natural_width (actor, g_value_get_float (value));
3942 case PROP_NATURAL_HEIGHT:
3943 clutter_actor_set_natural_height (actor, g_value_get_float (value));
3946 case PROP_MIN_WIDTH_SET:
3947 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3950 case PROP_MIN_HEIGHT_SET:
3951 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3954 case PROP_NATURAL_WIDTH_SET:
3955 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3958 case PROP_NATURAL_HEIGHT_SET:
3959 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3962 case PROP_REQUEST_MODE:
3963 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3967 clutter_actor_set_depth (actor, g_value_get_float (value));
3971 clutter_actor_set_opacity (actor, g_value_get_uint (value));
3974 case PROP_OFFSCREEN_REDIRECT:
3975 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3979 clutter_actor_set_name (actor, g_value_get_string (value));
3983 if (g_value_get_boolean (value) == TRUE)
3984 clutter_actor_show (actor);
3986 clutter_actor_hide (actor);
3990 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3991 g_value_get_double (value));
3995 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
3996 g_value_get_double (value));
3999 case PROP_SCALE_CENTER_X:
4000 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4001 g_value_get_float (value));
4004 case PROP_SCALE_CENTER_Y:
4005 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4006 g_value_get_float (value));
4009 case PROP_SCALE_GRAVITY:
4011 const ClutterTransformInfo *info;
4012 ClutterGravity gravity;
4014 info = _clutter_actor_get_transform_info_or_defaults (actor);
4015 gravity = g_value_get_enum (value);
4017 clutter_actor_set_scale_with_gravity (actor,
4026 const ClutterGeometry *geom = g_value_get_boxed (value);
4028 clutter_actor_set_clip (actor,
4030 geom->width, geom->height);
4034 case PROP_CLIP_TO_ALLOCATION:
4035 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4039 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4042 case PROP_ROTATION_ANGLE_X:
4043 clutter_actor_set_rotation_angle_internal (actor,
4045 g_value_get_double (value));
4048 case PROP_ROTATION_ANGLE_Y:
4049 clutter_actor_set_rotation_angle_internal (actor,
4051 g_value_get_double (value));
4054 case PROP_ROTATION_ANGLE_Z:
4055 clutter_actor_set_rotation_angle_internal (actor,
4057 g_value_get_double (value));
4060 case PROP_ROTATION_CENTER_X:
4061 clutter_actor_set_rotation_center_internal (actor,
4063 g_value_get_boxed (value));
4066 case PROP_ROTATION_CENTER_Y:
4067 clutter_actor_set_rotation_center_internal (actor,
4069 g_value_get_boxed (value));
4072 case PROP_ROTATION_CENTER_Z:
4073 clutter_actor_set_rotation_center_internal (actor,
4075 g_value_get_boxed (value));
4078 case PROP_ROTATION_CENTER_Z_GRAVITY:
4080 const ClutterTransformInfo *info;
4082 info = _clutter_actor_get_transform_info_or_defaults (actor);
4083 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4084 g_value_get_enum (value));
4089 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4090 g_value_get_float (value));
4094 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4095 g_value_get_float (value));
4098 case PROP_ANCHOR_GRAVITY:
4099 clutter_actor_set_anchor_point_from_gravity (actor,
4100 g_value_get_enum (value));
4103 case PROP_SHOW_ON_SET_PARENT:
4104 priv->show_on_set_parent = g_value_get_boolean (value);
4107 case PROP_TEXT_DIRECTION:
4108 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4112 clutter_actor_add_action (actor, g_value_get_object (value));
4115 case PROP_CONSTRAINTS:
4116 clutter_actor_add_constraint (actor, g_value_get_object (value));
4120 clutter_actor_add_effect (actor, g_value_get_object (value));
4123 case PROP_LAYOUT_MANAGER:
4124 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4128 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4132 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4135 case PROP_MARGIN_TOP:
4136 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4139 case PROP_MARGIN_BOTTOM:
4140 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4143 case PROP_MARGIN_LEFT:
4144 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4147 case PROP_MARGIN_RIGHT:
4148 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4151 case PROP_BACKGROUND_COLOR:
4152 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4156 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4162 clutter_actor_get_property (GObject *object,
4167 ClutterActor *actor = CLUTTER_ACTOR (object);
4168 ClutterActorPrivate *priv = actor->priv;
4173 g_value_set_float (value, clutter_actor_get_x (actor));
4177 g_value_set_float (value, clutter_actor_get_y (actor));
4181 g_value_set_float (value, clutter_actor_get_width (actor));
4185 g_value_set_float (value, clutter_actor_get_height (actor));
4190 const ClutterLayoutInfo *info;
4192 info = _clutter_actor_get_layout_info_or_defaults (actor);
4193 g_value_set_float (value, info->fixed_x);
4199 const ClutterLayoutInfo *info;
4201 info = _clutter_actor_get_layout_info_or_defaults (actor);
4202 g_value_set_float (value, info->fixed_y);
4206 case PROP_FIXED_POSITION_SET:
4207 g_value_set_boolean (value, priv->position_set);
4210 case PROP_MIN_WIDTH:
4212 const ClutterLayoutInfo *info;
4214 info = _clutter_actor_get_layout_info_or_defaults (actor);
4215 g_value_set_float (value, info->min_width);
4219 case PROP_MIN_HEIGHT:
4221 const ClutterLayoutInfo *info;
4223 info = _clutter_actor_get_layout_info_or_defaults (actor);
4224 g_value_set_float (value, info->min_height);
4228 case PROP_NATURAL_WIDTH:
4230 const ClutterLayoutInfo *info;
4232 info = _clutter_actor_get_layout_info_or_defaults (actor);
4233 g_value_set_float (value, info->natural_width);
4237 case PROP_NATURAL_HEIGHT:
4239 const ClutterLayoutInfo *info;
4241 info = _clutter_actor_get_layout_info_or_defaults (actor);
4242 g_value_set_float (value, info->natural_height);
4246 case PROP_MIN_WIDTH_SET:
4247 g_value_set_boolean (value, priv->min_width_set);
4250 case PROP_MIN_HEIGHT_SET:
4251 g_value_set_boolean (value, priv->min_height_set);
4254 case PROP_NATURAL_WIDTH_SET:
4255 g_value_set_boolean (value, priv->natural_width_set);
4258 case PROP_NATURAL_HEIGHT_SET:
4259 g_value_set_boolean (value, priv->natural_height_set);
4262 case PROP_REQUEST_MODE:
4263 g_value_set_enum (value, priv->request_mode);
4266 case PROP_ALLOCATION:
4267 g_value_set_boxed (value, &priv->allocation);
4271 g_value_set_float (value, clutter_actor_get_depth (actor));
4275 g_value_set_uint (value, priv->opacity);
4278 case PROP_OFFSCREEN_REDIRECT:
4279 g_value_set_enum (value, priv->offscreen_redirect);
4283 g_value_set_string (value, priv->name);
4287 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4291 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4295 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4299 g_value_set_boolean (value, priv->has_clip);
4304 ClutterGeometry clip;
4306 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4307 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4308 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4309 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4311 g_value_set_boxed (value, &clip);
4315 case PROP_CLIP_TO_ALLOCATION:
4316 g_value_set_boolean (value, priv->clip_to_allocation);
4321 const ClutterTransformInfo *info;
4323 info = _clutter_actor_get_transform_info_or_defaults (actor);
4324 g_value_set_double (value, info->scale_x);
4330 const ClutterTransformInfo *info;
4332 info = _clutter_actor_get_transform_info_or_defaults (actor);
4333 g_value_set_double (value, info->scale_y);
4337 case PROP_SCALE_CENTER_X:
4341 clutter_actor_get_scale_center (actor, ¢er, NULL);
4343 g_value_set_float (value, center);
4347 case PROP_SCALE_CENTER_Y:
4351 clutter_actor_get_scale_center (actor, NULL, ¢er);
4353 g_value_set_float (value, center);
4357 case PROP_SCALE_GRAVITY:
4358 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4362 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4365 case PROP_ROTATION_ANGLE_X:
4367 const ClutterTransformInfo *info;
4369 info = _clutter_actor_get_transform_info_or_defaults (actor);
4370 g_value_set_double (value, info->rx_angle);
4374 case PROP_ROTATION_ANGLE_Y:
4376 const ClutterTransformInfo *info;
4378 info = _clutter_actor_get_transform_info_or_defaults (actor);
4379 g_value_set_double (value, info->ry_angle);
4383 case PROP_ROTATION_ANGLE_Z:
4385 const ClutterTransformInfo *info;
4387 info = _clutter_actor_get_transform_info_or_defaults (actor);
4388 g_value_set_double (value, info->rz_angle);
4392 case PROP_ROTATION_CENTER_X:
4394 ClutterVertex center;
4396 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4401 g_value_set_boxed (value, ¢er);
4405 case PROP_ROTATION_CENTER_Y:
4407 ClutterVertex center;
4409 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4414 g_value_set_boxed (value, ¢er);
4418 case PROP_ROTATION_CENTER_Z:
4420 ClutterVertex center;
4422 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4427 g_value_set_boxed (value, ¢er);
4431 case PROP_ROTATION_CENTER_Z_GRAVITY:
4432 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4437 const ClutterTransformInfo *info;
4440 info = _clutter_actor_get_transform_info_or_defaults (actor);
4441 clutter_anchor_coord_get_units (actor, &info->anchor,
4445 g_value_set_float (value, anchor_x);
4451 const ClutterTransformInfo *info;
4454 info = _clutter_actor_get_transform_info_or_defaults (actor);
4455 clutter_anchor_coord_get_units (actor, &info->anchor,
4459 g_value_set_float (value, anchor_y);
4463 case PROP_ANCHOR_GRAVITY:
4464 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4467 case PROP_SHOW_ON_SET_PARENT:
4468 g_value_set_boolean (value, priv->show_on_set_parent);
4471 case PROP_TEXT_DIRECTION:
4472 g_value_set_enum (value, priv->text_direction);
4475 case PROP_HAS_POINTER:
4476 g_value_set_boolean (value, priv->has_pointer);
4479 case PROP_LAYOUT_MANAGER:
4480 g_value_set_object (value, priv->layout_manager);
4485 const ClutterLayoutInfo *info;
4487 info = _clutter_actor_get_layout_info_or_defaults (actor);
4488 g_value_set_enum (value, info->x_align);
4494 const ClutterLayoutInfo *info;
4496 info = _clutter_actor_get_layout_info_or_defaults (actor);
4497 g_value_set_enum (value, info->y_align);
4501 case PROP_MARGIN_TOP:
4503 const ClutterLayoutInfo *info;
4505 info = _clutter_actor_get_layout_info_or_defaults (actor);
4506 g_value_set_float (value, info->margin.top);
4510 case PROP_MARGIN_BOTTOM:
4512 const ClutterLayoutInfo *info;
4514 info = _clutter_actor_get_layout_info_or_defaults (actor);
4515 g_value_set_float (value, info->margin.bottom);
4519 case PROP_MARGIN_LEFT:
4521 const ClutterLayoutInfo *info;
4523 info = _clutter_actor_get_layout_info_or_defaults (actor);
4524 g_value_set_float (value, info->margin.left);
4528 case PROP_MARGIN_RIGHT:
4530 const ClutterLayoutInfo *info;
4532 info = _clutter_actor_get_layout_info_or_defaults (actor);
4533 g_value_set_float (value, info->margin.right);
4537 case PROP_BACKGROUND_COLOR_SET:
4538 g_value_set_boolean (value, priv->bg_color_set);
4541 case PROP_BACKGROUND_COLOR:
4542 g_value_set_boxed (value, &priv->bg_color);
4545 case PROP_FIRST_CHILD:
4546 g_value_set_object (value, priv->first_child);
4549 case PROP_LAST_CHILD:
4550 g_value_set_object (value, priv->last_child);
4554 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4560 clutter_actor_dispose (GObject *object)
4562 ClutterActor *self = CLUTTER_ACTOR (object);
4563 ClutterActorPrivate *priv = self->priv;
4565 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4567 g_type_name (G_OBJECT_TYPE (self)),
4570 g_signal_emit (self, actor_signals[DESTROY], 0);
4572 /* avoid recursing when called from clutter_actor_destroy() */
4573 if (priv->parent != NULL)
4575 ClutterActor *parent = priv->parent;
4577 /* go through the Container implementation unless this
4578 * is an internal child and has been marked as such.
4580 * removing the actor from its parent will reset the
4581 * realized and mapped states.
4583 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4584 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4586 clutter_actor_remove_child_internal (parent, self,
4587 REMOVE_CHILD_LEGACY_FLAGS);
4590 /* parent must be gone at this point */
4591 g_assert (priv->parent == NULL);
4593 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4595 /* can't be mapped or realized with no parent */
4596 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4597 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4600 g_clear_object (&priv->pango_context);
4601 g_clear_object (&priv->actions);
4602 g_clear_object (&priv->constraints);
4603 g_clear_object (&priv->effects);
4604 g_clear_object (&priv->flatten_effect);
4606 if (priv->layout_manager != NULL)
4608 clutter_layout_manager_set_container (priv->layout_manager, NULL);
4609 g_object_unref (priv->layout_manager);
4610 priv->layout_manager = NULL;
4613 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4617 clutter_actor_finalize (GObject *object)
4619 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4621 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4622 priv->name != NULL ? priv->name : "<none>",
4624 g_type_name (G_OBJECT_TYPE (object)));
4626 _clutter_context_release_id (priv->id);
4628 g_free (priv->name);
4630 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4635 * clutter_actor_get_accessible:
4636 * @self: a #ClutterActor
4638 * Returns the accessible object that describes the actor to an
4639 * assistive technology.
4641 * If no class-specific #AtkObject implementation is available for the
4642 * actor instance in question, it will inherit an #AtkObject
4643 * implementation from the first ancestor class for which such an
4644 * implementation is defined.
4646 * The documentation of the <ulink
4647 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4648 * library contains more information about accessible objects and
4651 * Returns: (transfer none): the #AtkObject associated with @actor
4654 clutter_actor_get_accessible (ClutterActor *self)
4656 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4658 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4662 clutter_actor_real_get_accessible (ClutterActor *actor)
4664 return atk_gobject_accessible_for_object (G_OBJECT (actor));
4668 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4670 AtkObject *accessible;
4672 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4673 if (accessible != NULL)
4674 g_object_ref (accessible);
4680 atk_implementor_iface_init (AtkImplementorIface *iface)
4682 iface->ref_accessible = _clutter_actor_ref_accessible;
4686 clutter_actor_real_get_paint_volume (ClutterActor *self,
4687 ClutterPaintVolume *volume)
4689 ClutterActorPrivate *priv = self->priv;
4690 ClutterActor *child;
4691 ClutterActorClass *klass;
4694 klass = CLUTTER_ACTOR_GET_CLASS (self);
4696 /* XXX - this thoroughly sucks, but we don't want to penalize users
4697 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
4698 * redraw. This should go away in 2.0.
4700 if (klass->paint == clutter_actor_real_paint &&
4701 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
4707 /* this is the default return value: we cannot know if a class
4708 * is going to paint outside its allocation, so we take the
4709 * conservative approach.
4714 /* we start from the allocation */
4715 clutter_paint_volume_set_width (volume,
4716 priv->allocation.x2 - priv->allocation.x1);
4717 clutter_paint_volume_set_height (volume,
4718 priv->allocation.y2 - priv->allocation.y1);
4720 /* if the actor has a clip set then we have a pretty definite
4721 * size for the paint volume: the actor cannot possibly paint
4722 * outside the clip region.
4724 if (priv->clip_to_allocation)
4726 /* the allocation has already been set, so we just flip the
4733 if (priv->has_clip &&
4734 priv->clip.width >= 0 &&
4735 priv->clip.height >= 0)
4737 ClutterVertex origin;
4739 origin.x = priv->clip.x;
4740 origin.y = priv->clip.y;
4743 clutter_paint_volume_set_origin (volume, &origin);
4744 clutter_paint_volume_set_width (volume, priv->clip.width);
4745 clutter_paint_volume_set_height (volume, priv->clip.height);
4750 /* if we don't have children we just bail out here... */
4751 if (priv->n_children == 0)
4754 /* ...but if we have children then we ask for their paint volume in
4755 * our coordinates. if any of our children replies that it doesn't
4756 * have a paint volume, we bail out
4758 for (child = priv->first_child;
4760 child = child->priv->next_sibling)
4762 const ClutterPaintVolume *child_volume;
4764 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4765 if (child_volume == NULL)
4771 clutter_paint_volume_union (volume, child_volume);
4780 clutter_actor_real_has_overlaps (ClutterActor *self)
4782 /* By default we'll assume that all actors need an offscreen redirect to get
4783 * the correct opacity. Actors such as ClutterTexture that would never need
4784 * an offscreen redirect can override this to return FALSE. */
4789 clutter_actor_real_destroy (ClutterActor *actor)
4791 ClutterActorIter iter;
4793 clutter_actor_iter_init (&iter, actor);
4794 while (clutter_actor_iter_next (&iter, NULL))
4795 clutter_actor_iter_destroy (&iter);
4799 clutter_actor_constructor (GType gtype,
4801 GObjectConstructParam *props)
4803 GObjectClass *gobject_class;
4807 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4808 retval = gobject_class->constructor (gtype, n_props, props);
4809 self = CLUTTER_ACTOR (retval);
4811 if (self->priv->layout_manager == NULL)
4813 ClutterLayoutManager *default_layout;
4815 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4817 default_layout = clutter_fixed_layout_new ();
4818 clutter_actor_set_layout_manager (self, default_layout);
4825 clutter_actor_class_init (ClutterActorClass *klass)
4827 GObjectClass *object_class = G_OBJECT_CLASS (klass);
4829 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4830 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4831 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4833 object_class->constructor = clutter_actor_constructor;
4834 object_class->set_property = clutter_actor_set_property;
4835 object_class->get_property = clutter_actor_get_property;
4836 object_class->dispose = clutter_actor_dispose;
4837 object_class->finalize = clutter_actor_finalize;
4839 klass->show = clutter_actor_real_show;
4840 klass->show_all = clutter_actor_show;
4841 klass->hide = clutter_actor_real_hide;
4842 klass->hide_all = clutter_actor_hide;
4843 klass->map = clutter_actor_real_map;
4844 klass->unmap = clutter_actor_real_unmap;
4845 klass->unrealize = clutter_actor_real_unrealize;
4846 klass->pick = clutter_actor_real_pick;
4847 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4848 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4849 klass->allocate = clutter_actor_real_allocate;
4850 klass->queue_redraw = clutter_actor_real_queue_redraw;
4851 klass->queue_relayout = clutter_actor_real_queue_relayout;
4852 klass->apply_transform = clutter_actor_real_apply_transform;
4853 klass->get_accessible = clutter_actor_real_get_accessible;
4854 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4855 klass->has_overlaps = clutter_actor_real_has_overlaps;
4856 klass->paint = clutter_actor_real_paint;
4857 klass->destroy = clutter_actor_real_destroy;
4859 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4864 * X coordinate of the actor in pixels. If written, forces a fixed
4865 * position for the actor. If read, returns the fixed position if any,
4866 * otherwise the allocation if available, otherwise 0.
4869 g_param_spec_float ("x",
4871 P_("X coordinate of the actor"),
4872 -G_MAXFLOAT, G_MAXFLOAT,
4874 CLUTTER_PARAM_READWRITE);
4879 * Y coordinate of the actor in pixels. If written, forces a fixed
4880 * position for the actor. If read, returns the fixed position if
4881 * any, otherwise the allocation if available, otherwise 0.
4884 g_param_spec_float ("y",
4886 P_("Y coordinate of the actor"),
4887 -G_MAXFLOAT, G_MAXFLOAT,
4889 CLUTTER_PARAM_READWRITE);
4892 * ClutterActor:width:
4894 * Width of the actor (in pixels). If written, forces the minimum and
4895 * natural size request of the actor to the given width. If read, returns
4896 * the allocated width if available, otherwise the width request.
4898 obj_props[PROP_WIDTH] =
4899 g_param_spec_float ("width",
4901 P_("Width of the actor"),
4904 CLUTTER_PARAM_READWRITE);
4907 * ClutterActor:height:
4909 * Height of the actor (in pixels). If written, forces the minimum and
4910 * natural size request of the actor to the given height. If read, returns
4911 * the allocated height if available, otherwise the height request.
4913 obj_props[PROP_HEIGHT] =
4914 g_param_spec_float ("height",
4916 P_("Height of the actor"),
4919 CLUTTER_PARAM_READWRITE);
4922 * ClutterActor:fixed-x:
4924 * The fixed X position of the actor in pixels.
4926 * Writing this property sets #ClutterActor:fixed-position-set
4927 * property as well, as a side effect
4931 obj_props[PROP_FIXED_X] =
4932 g_param_spec_float ("fixed-x",
4934 P_("Forced X position of the actor"),
4935 -G_MAXFLOAT, G_MAXFLOAT,
4937 CLUTTER_PARAM_READWRITE);
4940 * ClutterActor:fixed-y:
4942 * The fixed Y position of the actor in pixels.
4944 * Writing this property sets the #ClutterActor:fixed-position-set
4945 * property as well, as a side effect
4949 obj_props[PROP_FIXED_Y] =
4950 g_param_spec_float ("fixed-y",
4952 P_("Forced Y position of the actor"),
4953 -G_MAXFLOAT, G_MAXFLOAT,
4955 CLUTTER_PARAM_READWRITE);
4958 * ClutterActor:fixed-position-set:
4960 * This flag controls whether the #ClutterActor:fixed-x and
4961 * #ClutterActor:fixed-y properties are used
4965 obj_props[PROP_FIXED_POSITION_SET] =
4966 g_param_spec_boolean ("fixed-position-set",
4967 P_("Fixed position set"),
4968 P_("Whether to use fixed positioning for the actor"),
4970 CLUTTER_PARAM_READWRITE);
4973 * ClutterActor:min-width:
4975 * A forced minimum width request for the actor, in pixels
4977 * Writing this property sets the #ClutterActor:min-width-set property
4978 * as well, as a side effect.
4980 *This property overrides the usual width request of the actor.
4984 obj_props[PROP_MIN_WIDTH] =
4985 g_param_spec_float ("min-width",
4987 P_("Forced minimum width request for the actor"),
4990 CLUTTER_PARAM_READWRITE);
4993 * ClutterActor:min-height:
4995 * A forced minimum height request for the actor, in pixels
4997 * Writing this property sets the #ClutterActor:min-height-set property
4998 * as well, as a side effect. This property overrides the usual height
4999 * request of the actor.
5003 obj_props[PROP_MIN_HEIGHT] =
5004 g_param_spec_float ("min-height",
5006 P_("Forced minimum height request for the actor"),
5009 CLUTTER_PARAM_READWRITE);
5012 * ClutterActor:natural-width:
5014 * A forced natural width request for the actor, in pixels
5016 * Writing this property sets the #ClutterActor:natural-width-set
5017 * property as well, as a side effect. This property overrides the
5018 * usual width request of the actor
5022 obj_props[PROP_NATURAL_WIDTH] =
5023 g_param_spec_float ("natural-width",
5024 P_("Natural Width"),
5025 P_("Forced natural width request for the actor"),
5028 CLUTTER_PARAM_READWRITE);
5031 * ClutterActor:natural-height:
5033 * A forced natural height request for the actor, in pixels
5035 * Writing this property sets the #ClutterActor:natural-height-set
5036 * property as well, as a side effect. This property overrides the
5037 * usual height request of the actor
5041 obj_props[PROP_NATURAL_HEIGHT] =
5042 g_param_spec_float ("natural-height",
5043 P_("Natural Height"),
5044 P_("Forced natural height request for the actor"),
5047 CLUTTER_PARAM_READWRITE);
5050 * ClutterActor:min-width-set:
5052 * This flag controls whether the #ClutterActor:min-width property
5057 obj_props[PROP_MIN_WIDTH_SET] =
5058 g_param_spec_boolean ("min-width-set",
5059 P_("Minimum width set"),
5060 P_("Whether to use the min-width property"),
5062 CLUTTER_PARAM_READWRITE);
5065 * ClutterActor:min-height-set:
5067 * This flag controls whether the #ClutterActor:min-height property
5072 obj_props[PROP_MIN_HEIGHT_SET] =
5073 g_param_spec_boolean ("min-height-set",
5074 P_("Minimum height set"),
5075 P_("Whether to use the min-height property"),
5077 CLUTTER_PARAM_READWRITE);
5080 * ClutterActor:natural-width-set:
5082 * This flag controls whether the #ClutterActor:natural-width property
5087 obj_props[PROP_NATURAL_WIDTH_SET] =
5088 g_param_spec_boolean ("natural-width-set",
5089 P_("Natural width set"),
5090 P_("Whether to use the natural-width property"),
5092 CLUTTER_PARAM_READWRITE);
5095 * ClutterActor:natural-height-set:
5097 * This flag controls whether the #ClutterActor:natural-height property
5102 obj_props[PROP_NATURAL_HEIGHT_SET] =
5103 g_param_spec_boolean ("natural-height-set",
5104 P_("Natural height set"),
5105 P_("Whether to use the natural-height property"),
5107 CLUTTER_PARAM_READWRITE);
5110 * ClutterActor:allocation:
5112 * The allocation for the actor, in pixels
5114 * This is property is read-only, but you might monitor it to know when an
5115 * actor moves or resizes
5119 obj_props[PROP_ALLOCATION] =
5120 g_param_spec_boxed ("allocation",
5122 P_("The actor's allocation"),
5123 CLUTTER_TYPE_ACTOR_BOX,
5124 CLUTTER_PARAM_READABLE);
5127 * ClutterActor:request-mode:
5129 * Request mode for the #ClutterActor. The request mode determines the
5130 * type of geometry management used by the actor, either height for width
5131 * (the default) or width for height.
5133 * For actors implementing height for width, the parent container should get
5134 * the preferred width first, and then the preferred height for that width.
5136 * For actors implementing width for height, the parent container should get
5137 * the preferred height first, and then the preferred width for that height.
5142 * ClutterRequestMode mode;
5143 * gfloat natural_width, min_width;
5144 * gfloat natural_height, min_height;
5146 * mode = clutter_actor_get_request_mode (child);
5147 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5149 * clutter_actor_get_preferred_width (child, -1,
5151 * &natural_width);
5152 * clutter_actor_get_preferred_height (child, natural_width,
5154 * &natural_height);
5158 * clutter_actor_get_preferred_height (child, -1,
5160 * &natural_height);
5161 * clutter_actor_get_preferred_width (child, natural_height,
5163 * &natural_width);
5167 * will retrieve the minimum and natural width and height depending on the
5168 * preferred request mode of the #ClutterActor "child".
5170 * The clutter_actor_get_preferred_size() function will implement this
5175 obj_props[PROP_REQUEST_MODE] =
5176 g_param_spec_enum ("request-mode",
5178 P_("The actor's request mode"),
5179 CLUTTER_TYPE_REQUEST_MODE,
5180 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5181 CLUTTER_PARAM_READWRITE);
5184 * ClutterActor:depth:
5186 * The position of the actor on the Z axis
5190 obj_props[PROP_DEPTH] =
5191 g_param_spec_float ("depth",
5193 P_("Position on the Z axis"),
5194 -G_MAXFLOAT, G_MAXFLOAT,
5196 CLUTTER_PARAM_READWRITE);
5199 * ClutterActor:opacity:
5201 * Opacity of an actor, between 0 (fully transparent) and
5202 * 255 (fully opaque)
5204 obj_props[PROP_OPACITY] =
5205 g_param_spec_uint ("opacity",
5207 P_("Opacity of an actor"),
5210 CLUTTER_PARAM_READWRITE);
5213 * ClutterActor:offscreen-redirect:
5215 * Determines the conditions in which the actor will be redirected
5216 * to an offscreen framebuffer while being painted. For example this
5217 * can be used to cache an actor in a framebuffer or for improved
5218 * handling of transparent actors. See
5219 * clutter_actor_set_offscreen_redirect() for details.
5223 obj_props[PROP_OFFSCREEN_REDIRECT] =
5224 g_param_spec_flags ("offscreen-redirect",
5225 P_("Offscreen redirect"),
5226 P_("Flags controlling when to flatten the actor into a single image"),
5227 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5229 CLUTTER_PARAM_READWRITE);
5232 * ClutterActor:visible:
5234 * Whether the actor is set to be visible or not
5236 * See also #ClutterActor:mapped
5238 obj_props[PROP_VISIBLE] =
5239 g_param_spec_boolean ("visible",
5241 P_("Whether the actor is visible or not"),
5243 CLUTTER_PARAM_READWRITE);
5246 * ClutterActor:mapped:
5248 * Whether the actor is mapped (will be painted when the stage
5249 * to which it belongs is mapped)
5253 obj_props[PROP_MAPPED] =
5254 g_param_spec_boolean ("mapped",
5256 P_("Whether the actor will be painted"),
5258 CLUTTER_PARAM_READABLE);
5261 * ClutterActor:realized:
5263 * Whether the actor has been realized
5267 obj_props[PROP_REALIZED] =
5268 g_param_spec_boolean ("realized",
5270 P_("Whether the actor has been realized"),
5272 CLUTTER_PARAM_READABLE);
5275 * ClutterActor:reactive:
5277 * Whether the actor is reactive to events or not
5279 * Only reactive actors will emit event-related signals
5283 obj_props[PROP_REACTIVE] =
5284 g_param_spec_boolean ("reactive",
5286 P_("Whether the actor is reactive to events"),
5288 CLUTTER_PARAM_READWRITE);
5291 * ClutterActor:has-clip:
5293 * Whether the actor has the #ClutterActor:clip property set or not
5295 obj_props[PROP_HAS_CLIP] =
5296 g_param_spec_boolean ("has-clip",
5298 P_("Whether the actor has a clip set"),
5300 CLUTTER_PARAM_READABLE);
5303 * ClutterActor:clip:
5305 * The clip region for the actor, in actor-relative coordinates
5307 * Every part of the actor outside the clip region will not be
5310 obj_props[PROP_CLIP] =
5311 g_param_spec_boxed ("clip",
5313 P_("The clip region for the actor"),
5314 CLUTTER_TYPE_GEOMETRY,
5315 CLUTTER_PARAM_READWRITE);
5318 * ClutterActor:name:
5320 * The name of the actor
5324 obj_props[PROP_NAME] =
5325 g_param_spec_string ("name",
5327 P_("Name of the actor"),
5329 CLUTTER_PARAM_READWRITE);
5332 * ClutterActor:scale-x:
5334 * The horizontal scale of the actor
5338 obj_props[PROP_SCALE_X] =
5339 g_param_spec_double ("scale-x",
5341 P_("Scale factor on the X axis"),
5344 CLUTTER_PARAM_READWRITE);
5347 * ClutterActor:scale-y:
5349 * The vertical scale of the actor
5353 obj_props[PROP_SCALE_Y] =
5354 g_param_spec_double ("scale-y",
5356 P_("Scale factor on the Y axis"),
5359 CLUTTER_PARAM_READWRITE);
5362 * ClutterActor:scale-center-x:
5364 * The horizontal center point for scaling
5368 obj_props[PROP_SCALE_CENTER_X] =
5369 g_param_spec_float ("scale-center-x",
5370 P_("Scale Center X"),
5371 P_("Horizontal scale center"),
5372 -G_MAXFLOAT, G_MAXFLOAT,
5374 CLUTTER_PARAM_READWRITE);
5377 * ClutterActor:scale-center-y:
5379 * The vertical center point for scaling
5383 obj_props[PROP_SCALE_CENTER_Y] =
5384 g_param_spec_float ("scale-center-y",
5385 P_("Scale Center Y"),
5386 P_("Vertical scale center"),
5387 -G_MAXFLOAT, G_MAXFLOAT,
5389 CLUTTER_PARAM_READWRITE);
5392 * ClutterActor:scale-gravity:
5394 * The center point for scaling expressed as a #ClutterGravity
5398 obj_props[PROP_SCALE_GRAVITY] =
5399 g_param_spec_enum ("scale-gravity",
5400 P_("Scale Gravity"),
5401 P_("The center of scaling"),
5402 CLUTTER_TYPE_GRAVITY,
5403 CLUTTER_GRAVITY_NONE,
5404 CLUTTER_PARAM_READWRITE);
5407 * ClutterActor:rotation-angle-x:
5409 * The rotation angle on the X axis
5413 obj_props[PROP_ROTATION_ANGLE_X] =
5414 g_param_spec_double ("rotation-angle-x",
5415 P_("Rotation Angle X"),
5416 P_("The rotation angle on the X axis"),
5417 -G_MAXDOUBLE, G_MAXDOUBLE,
5419 CLUTTER_PARAM_READWRITE);
5422 * ClutterActor:rotation-angle-y:
5424 * The rotation angle on the Y axis
5428 obj_props[PROP_ROTATION_ANGLE_Y] =
5429 g_param_spec_double ("rotation-angle-y",
5430 P_("Rotation Angle Y"),
5431 P_("The rotation angle on the Y axis"),
5432 -G_MAXDOUBLE, G_MAXDOUBLE,
5434 CLUTTER_PARAM_READWRITE);
5437 * ClutterActor:rotation-angle-z:
5439 * The rotation angle on the Z axis
5443 obj_props[PROP_ROTATION_ANGLE_Z] =
5444 g_param_spec_double ("rotation-angle-z",
5445 P_("Rotation Angle Z"),
5446 P_("The rotation angle on the Z axis"),
5447 -G_MAXDOUBLE, G_MAXDOUBLE,
5449 CLUTTER_PARAM_READWRITE);
5452 * ClutterActor:rotation-center-x:
5454 * The rotation center on the X axis.
5458 obj_props[PROP_ROTATION_CENTER_X] =
5459 g_param_spec_boxed ("rotation-center-x",
5460 P_("Rotation Center X"),
5461 P_("The rotation center on the X axis"),
5462 CLUTTER_TYPE_VERTEX,
5463 CLUTTER_PARAM_READWRITE);
5466 * ClutterActor:rotation-center-y:
5468 * The rotation center on the Y axis.
5472 obj_props[PROP_ROTATION_CENTER_Y] =
5473 g_param_spec_boxed ("rotation-center-y",
5474 P_("Rotation Center Y"),
5475 P_("The rotation center on the Y axis"),
5476 CLUTTER_TYPE_VERTEX,
5477 CLUTTER_PARAM_READWRITE);
5480 * ClutterActor:rotation-center-z:
5482 * The rotation center on the Z axis.
5486 obj_props[PROP_ROTATION_CENTER_Z] =
5487 g_param_spec_boxed ("rotation-center-z",
5488 P_("Rotation Center Z"),
5489 P_("The rotation center on the Z axis"),
5490 CLUTTER_TYPE_VERTEX,
5491 CLUTTER_PARAM_READWRITE);
5494 * ClutterActor:rotation-center-z-gravity:
5496 * The rotation center on the Z axis expressed as a #ClutterGravity.
5500 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5501 g_param_spec_enum ("rotation-center-z-gravity",
5502 P_("Rotation Center Z Gravity"),
5503 P_("Center point for rotation around the Z axis"),
5504 CLUTTER_TYPE_GRAVITY,
5505 CLUTTER_GRAVITY_NONE,
5506 CLUTTER_PARAM_READWRITE);
5509 * ClutterActor:anchor-x:
5511 * The X coordinate of an actor's anchor point, relative to
5512 * the actor coordinate space, in pixels
5516 obj_props[PROP_ANCHOR_X] =
5517 g_param_spec_float ("anchor-x",
5519 P_("X coordinate of the anchor point"),
5520 -G_MAXFLOAT, G_MAXFLOAT,
5522 CLUTTER_PARAM_READWRITE);
5525 * ClutterActor:anchor-y:
5527 * The Y coordinate of an actor's anchor point, relative to
5528 * the actor coordinate space, in pixels
5532 obj_props[PROP_ANCHOR_Y] =
5533 g_param_spec_float ("anchor-y",
5535 P_("Y coordinate of the anchor point"),
5536 -G_MAXFLOAT, G_MAXFLOAT,
5538 CLUTTER_PARAM_READWRITE);
5541 * ClutterActor:anchor-gravity:
5543 * The anchor point expressed as a #ClutterGravity
5547 obj_props[PROP_ANCHOR_GRAVITY] =
5548 g_param_spec_enum ("anchor-gravity",
5549 P_("Anchor Gravity"),
5550 P_("The anchor point as a ClutterGravity"),
5551 CLUTTER_TYPE_GRAVITY,
5552 CLUTTER_GRAVITY_NONE,
5553 CLUTTER_PARAM_READWRITE);
5556 * ClutterActor:show-on-set-parent:
5558 * If %TRUE, the actor is automatically shown when parented.
5560 * Calling clutter_actor_hide() on an actor which has not been
5561 * parented will set this property to %FALSE as a side effect.
5565 obj_props[PROP_SHOW_ON_SET_PARENT] =
5566 g_param_spec_boolean ("show-on-set-parent",
5567 P_("Show on set parent"),
5568 P_("Whether the actor is shown when parented"),
5570 CLUTTER_PARAM_READWRITE);
5573 * ClutterActor:clip-to-allocation:
5575 * Whether the clip region should track the allocated area
5578 * This property is ignored if a clip area has been explicitly
5579 * set using clutter_actor_set_clip().
5583 obj_props[PROP_CLIP_TO_ALLOCATION] =
5584 g_param_spec_boolean ("clip-to-allocation",
5585 P_("Clip to Allocation"),
5586 P_("Sets the clip region to track the actor's allocation"),
5588 CLUTTER_PARAM_READWRITE);
5591 * ClutterActor:text-direction:
5593 * The direction of the text inside a #ClutterActor.
5597 obj_props[PROP_TEXT_DIRECTION] =
5598 g_param_spec_enum ("text-direction",
5599 P_("Text Direction"),
5600 P_("Direction of the text"),
5601 CLUTTER_TYPE_TEXT_DIRECTION,
5602 CLUTTER_TEXT_DIRECTION_LTR,
5603 CLUTTER_PARAM_READWRITE);
5606 * ClutterActor:has-pointer:
5608 * Whether the actor contains the pointer of a #ClutterInputDevice
5613 obj_props[PROP_HAS_POINTER] =
5614 g_param_spec_boolean ("has-pointer",
5616 P_("Whether the actor contains the pointer of an input device"),
5618 CLUTTER_PARAM_READABLE);
5621 * ClutterActor:actions:
5623 * Adds a #ClutterAction to the actor
5627 obj_props[PROP_ACTIONS] =
5628 g_param_spec_object ("actions",
5630 P_("Adds an action to the actor"),
5631 CLUTTER_TYPE_ACTION,
5632 CLUTTER_PARAM_WRITABLE);
5635 * ClutterActor:constraints:
5637 * Adds a #ClutterConstraint to the actor
5641 obj_props[PROP_CONSTRAINTS] =
5642 g_param_spec_object ("constraints",
5644 P_("Adds a constraint to the actor"),
5645 CLUTTER_TYPE_CONSTRAINT,
5646 CLUTTER_PARAM_WRITABLE);
5649 * ClutterActor:effect:
5651 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5655 obj_props[PROP_EFFECT] =
5656 g_param_spec_object ("effect",
5658 P_("Add an effect to be applied on the actor"),
5659 CLUTTER_TYPE_EFFECT,
5660 CLUTTER_PARAM_WRITABLE);
5663 * ClutterActor:layout-manager:
5665 * A delegate object for controlling the layout of the children of
5670 obj_props[PROP_LAYOUT_MANAGER] =
5671 g_param_spec_object ("layout-manager",
5672 P_("Layout Manager"),
5673 P_("The object controlling the layout of an actor's children"),
5674 CLUTTER_TYPE_LAYOUT_MANAGER,
5675 CLUTTER_PARAM_READWRITE);
5679 * ClutterActor:x-align:
5681 * The alignment of an actor on the X axis, if the actor has been given
5682 * extra space for its allocation.
5686 obj_props[PROP_X_ALIGN] =
5687 g_param_spec_enum ("x-align",
5689 P_("The alignment of the actor on the X axis within its allocation"),
5690 CLUTTER_TYPE_ACTOR_ALIGN,
5691 CLUTTER_ACTOR_ALIGN_FILL,
5692 CLUTTER_PARAM_READWRITE);
5695 * ClutterActor:y-align:
5697 * The alignment of an actor on the Y axis, if the actor has been given
5698 * extra space for its allocation.
5702 obj_props[PROP_Y_ALIGN] =
5703 g_param_spec_enum ("y-align",
5705 P_("The alignment of the actor on the Y axis within its allocation"),
5706 CLUTTER_TYPE_ACTOR_ALIGN,
5707 CLUTTER_ACTOR_ALIGN_FILL,
5708 CLUTTER_PARAM_READWRITE);
5711 * ClutterActor:margin-top:
5713 * The margin (in pixels) from the top of the actor.
5715 * This property adds a margin to the actor's preferred size; the margin
5716 * will be automatically taken into account when allocating the actor.
5720 obj_props[PROP_MARGIN_TOP] =
5721 g_param_spec_float ("margin-top",
5723 P_("Extra space at the top"),
5726 CLUTTER_PARAM_READWRITE);
5729 * ClutterActor:margin-bottom:
5731 * The margin (in pixels) from the bottom of the actor.
5733 * This property adds a margin to the actor's preferred size; the margin
5734 * will be automatically taken into account when allocating the actor.
5738 obj_props[PROP_MARGIN_BOTTOM] =
5739 g_param_spec_float ("margin-bottom",
5740 P_("Margin Bottom"),
5741 P_("Extra space at the bottom"),
5744 CLUTTER_PARAM_READWRITE);
5747 * ClutterActor:margin-left:
5749 * The margin (in pixels) from the left of the actor.
5751 * This property adds a margin to the actor's preferred size; the margin
5752 * will be automatically taken into account when allocating the actor.
5756 obj_props[PROP_MARGIN_LEFT] =
5757 g_param_spec_float ("margin-left",
5759 P_("Extra space at the left"),
5762 CLUTTER_PARAM_READWRITE);
5765 * ClutterActor:margin-right:
5767 * The margin (in pixels) from the right of the actor.
5769 * This property adds a margin to the actor's preferred size; the margin
5770 * will be automatically taken into account when allocating the actor.
5774 obj_props[PROP_MARGIN_RIGHT] =
5775 g_param_spec_float ("margin-right",
5777 P_("Extra space at the right"),
5780 CLUTTER_PARAM_READWRITE);
5783 * ClutterActor:background-color-set:
5785 * Whether the #ClutterActor:background-color property has been set.
5789 obj_props[PROP_BACKGROUND_COLOR_SET] =
5790 g_param_spec_boolean ("background-color-set",
5791 P_("Background Color Set"),
5792 P_("Whether the background color is set"),
5794 CLUTTER_PARAM_READABLE);
5797 * ClutterActor:background-color:
5799 * Paints a solid fill of the actor's allocation using the specified
5804 obj_props[PROP_BACKGROUND_COLOR] =
5805 clutter_param_spec_color ("background-color",
5806 P_("Background color"),
5807 P_("The actor's background color"),
5808 CLUTTER_COLOR_Transparent,
5809 CLUTTER_PARAM_READWRITE);
5812 * ClutterActor:first-child:
5814 * The actor's first child.
5818 obj_props[PROP_FIRST_CHILD] =
5819 g_param_spec_object ("first-child",
5821 P_("The actor's first child"),
5823 CLUTTER_PARAM_READABLE);
5826 * ClutterActor:last-child:
5828 * The actor's last child.
5832 obj_props[PROP_LAST_CHILD] =
5833 g_param_spec_object ("last-child",
5835 P_("The actor's last child"),
5837 CLUTTER_PARAM_READABLE);
5839 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5842 * ClutterActor::destroy:
5843 * @actor: the #ClutterActor which emitted the signal
5845 * The ::destroy signal notifies that all references held on the
5846 * actor which emitted it should be released.
5848 * The ::destroy signal should be used by all holders of a reference
5851 * This signal might result in the finalization of the #ClutterActor
5852 * if all references are released.
5854 * Composite actors and actors implementing the #ClutterContainer
5855 * interface should override the default implementation of the
5856 * class handler of this signal and call clutter_actor_destroy() on
5857 * their children. When overriding the default class handler, it is
5858 * required to chain up to the parent's implementation.
5862 actor_signals[DESTROY] =
5863 g_signal_new (I_("destroy"),
5864 G_TYPE_FROM_CLASS (object_class),
5865 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5866 G_STRUCT_OFFSET (ClutterActorClass, destroy),
5868 _clutter_marshal_VOID__VOID,
5871 * ClutterActor::show:
5872 * @actor: the object which received the signal
5874 * The ::show signal is emitted when an actor is visible and
5875 * rendered on the stage.
5879 actor_signals[SHOW] =
5880 g_signal_new (I_("show"),
5881 G_TYPE_FROM_CLASS (object_class),
5883 G_STRUCT_OFFSET (ClutterActorClass, show),
5885 _clutter_marshal_VOID__VOID,
5888 * ClutterActor::hide:
5889 * @actor: the object which received the signal
5891 * The ::hide signal is emitted when an actor is no longer rendered
5896 actor_signals[HIDE] =
5897 g_signal_new (I_("hide"),
5898 G_TYPE_FROM_CLASS (object_class),
5900 G_STRUCT_OFFSET (ClutterActorClass, hide),
5902 _clutter_marshal_VOID__VOID,
5905 * ClutterActor::parent-set:
5906 * @actor: the object which received the signal
5907 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5909 * This signal is emitted when the parent of the actor changes.
5913 actor_signals[PARENT_SET] =
5914 g_signal_new (I_("parent-set"),
5915 G_TYPE_FROM_CLASS (object_class),
5917 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5919 _clutter_marshal_VOID__OBJECT,
5921 CLUTTER_TYPE_ACTOR);
5924 * ClutterActor::queue-redraw:
5925 * @actor: the actor we're bubbling the redraw request through
5926 * @origin: the actor which initiated the redraw request
5928 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5929 * is called on @origin.
5931 * The default implementation for #ClutterActor chains up to the
5932 * parent actor and queues a redraw on the parent, thus "bubbling"
5933 * the redraw queue up through the actor graph. The default
5934 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
5935 * in a main loop idle handler.
5937 * Note that the @origin actor may be the stage, or a container; it
5938 * does not have to be a leaf node in the actor graph.
5940 * Toolkits embedding a #ClutterStage which require a redraw and
5941 * relayout cycle can stop the emission of this signal using the
5942 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
5947 * on_redraw_complete (gpointer data)
5949 * ClutterStage *stage = data;
5951 * /* execute the Clutter drawing pipeline */
5952 * clutter_stage_ensure_redraw (stage);
5956 * on_stage_queue_redraw (ClutterStage *stage)
5958 * /* this prevents the default handler to run */
5959 * g_signal_stop_emission_by_name (stage, "queue-redraw");
5961 * /* queue a redraw with the host toolkit and call
5962 * * a function when the redraw has been completed
5964 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
5968 * <note><para>This signal is emitted before the Clutter paint
5969 * pipeline is executed. If you want to know when the pipeline has
5970 * been completed you should connect to the ::paint signal on the
5971 * Stage with g_signal_connect_after().</para></note>
5975 actor_signals[QUEUE_REDRAW] =
5976 g_signal_new (I_("queue-redraw"),
5977 G_TYPE_FROM_CLASS (object_class),
5979 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
5981 _clutter_marshal_VOID__OBJECT,
5983 CLUTTER_TYPE_ACTOR);
5986 * ClutterActor::queue-relayout
5987 * @actor: the actor being queued for relayout
5989 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
5990 * is called on an actor.
5992 * The default implementation for #ClutterActor chains up to the
5993 * parent actor and queues a relayout on the parent, thus "bubbling"
5994 * the relayout queue up through the actor graph.
5996 * The main purpose of this signal is to allow relayout to be propagated
5997 * properly in the procense of #ClutterClone actors. Applications will
5998 * not normally need to connect to this signal.
6002 actor_signals[QUEUE_RELAYOUT] =
6003 g_signal_new (I_("queue-relayout"),
6004 G_TYPE_FROM_CLASS (object_class),
6006 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6008 _clutter_marshal_VOID__VOID,
6012 * ClutterActor::event:
6013 * @actor: the actor which received the event
6014 * @event: a #ClutterEvent
6016 * The ::event signal is emitted each time an event is received
6017 * by the @actor. This signal will be emitted on every actor,
6018 * following the hierarchy chain, until it reaches the top-level
6019 * container (the #ClutterStage).
6021 * Return value: %TRUE if the event has been handled by the actor,
6022 * or %FALSE to continue the emission.
6026 actor_signals[EVENT] =
6027 g_signal_new (I_("event"),
6028 G_TYPE_FROM_CLASS (object_class),
6030 G_STRUCT_OFFSET (ClutterActorClass, event),
6031 _clutter_boolean_handled_accumulator, NULL,
6032 _clutter_marshal_BOOLEAN__BOXED,
6034 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6036 * ClutterActor::button-press-event:
6037 * @actor: the actor which received the event
6038 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6040 * The ::button-press-event signal is emitted each time a mouse button
6041 * is pressed on @actor.
6043 * Return value: %TRUE if the event has been handled by the actor,
6044 * or %FALSE to continue the emission.
6048 actor_signals[BUTTON_PRESS_EVENT] =
6049 g_signal_new (I_("button-press-event"),
6050 G_TYPE_FROM_CLASS (object_class),
6052 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6053 _clutter_boolean_handled_accumulator, NULL,
6054 _clutter_marshal_BOOLEAN__BOXED,
6056 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6058 * ClutterActor::button-release-event:
6059 * @actor: the actor which received the event
6060 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6062 * The ::button-release-event signal is emitted each time a mouse button
6063 * is released on @actor.
6065 * Return value: %TRUE if the event has been handled by the actor,
6066 * or %FALSE to continue the emission.
6070 actor_signals[BUTTON_RELEASE_EVENT] =
6071 g_signal_new (I_("button-release-event"),
6072 G_TYPE_FROM_CLASS (object_class),
6074 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6075 _clutter_boolean_handled_accumulator, NULL,
6076 _clutter_marshal_BOOLEAN__BOXED,
6078 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6080 * ClutterActor::scroll-event:
6081 * @actor: the actor which received the event
6082 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6084 * The ::scroll-event signal is emitted each time the mouse is
6085 * scrolled on @actor
6087 * Return value: %TRUE if the event has been handled by the actor,
6088 * or %FALSE to continue the emission.
6092 actor_signals[SCROLL_EVENT] =
6093 g_signal_new (I_("scroll-event"),
6094 G_TYPE_FROM_CLASS (object_class),
6096 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6097 _clutter_boolean_handled_accumulator, NULL,
6098 _clutter_marshal_BOOLEAN__BOXED,
6100 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6102 * ClutterActor::key-press-event:
6103 * @actor: the actor which received the event
6104 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6106 * The ::key-press-event signal is emitted each time a keyboard button
6107 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6109 * Return value: %TRUE if the event has been handled by the actor,
6110 * or %FALSE to continue the emission.
6114 actor_signals[KEY_PRESS_EVENT] =
6115 g_signal_new (I_("key-press-event"),
6116 G_TYPE_FROM_CLASS (object_class),
6118 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6119 _clutter_boolean_handled_accumulator, NULL,
6120 _clutter_marshal_BOOLEAN__BOXED,
6122 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6124 * ClutterActor::key-release-event:
6125 * @actor: the actor which received the event
6126 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6128 * The ::key-release-event signal is emitted each time a keyboard button
6129 * is released while @actor has key focus (see
6130 * clutter_stage_set_key_focus()).
6132 * Return value: %TRUE if the event has been handled by the actor,
6133 * or %FALSE to continue the emission.
6137 actor_signals[KEY_RELEASE_EVENT] =
6138 g_signal_new (I_("key-release-event"),
6139 G_TYPE_FROM_CLASS (object_class),
6141 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6142 _clutter_boolean_handled_accumulator, NULL,
6143 _clutter_marshal_BOOLEAN__BOXED,
6145 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6147 * ClutterActor::motion-event:
6148 * @actor: the actor which received the event
6149 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6151 * The ::motion-event signal is emitted each time the mouse pointer is
6152 * moved over @actor.
6154 * Return value: %TRUE if the event has been handled by the actor,
6155 * or %FALSE to continue the emission.
6159 actor_signals[MOTION_EVENT] =
6160 g_signal_new (I_("motion-event"),
6161 G_TYPE_FROM_CLASS (object_class),
6163 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6164 _clutter_boolean_handled_accumulator, NULL,
6165 _clutter_marshal_BOOLEAN__BOXED,
6167 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6170 * ClutterActor::key-focus-in:
6171 * @actor: the actor which now has key focus
6173 * The ::key-focus-in signal is emitted when @actor receives key focus.
6177 actor_signals[KEY_FOCUS_IN] =
6178 g_signal_new (I_("key-focus-in"),
6179 G_TYPE_FROM_CLASS (object_class),
6181 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6183 _clutter_marshal_VOID__VOID,
6187 * ClutterActor::key-focus-out:
6188 * @actor: the actor which now has key focus
6190 * The ::key-focus-out signal is emitted when @actor loses key focus.
6194 actor_signals[KEY_FOCUS_OUT] =
6195 g_signal_new (I_("key-focus-out"),
6196 G_TYPE_FROM_CLASS (object_class),
6198 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6200 _clutter_marshal_VOID__VOID,
6204 * ClutterActor::enter-event:
6205 * @actor: the actor which the pointer has entered.
6206 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6208 * The ::enter-event signal is emitted when the pointer enters the @actor
6210 * Return value: %TRUE if the event has been handled by the actor,
6211 * or %FALSE to continue the emission.
6215 actor_signals[ENTER_EVENT] =
6216 g_signal_new (I_("enter-event"),
6217 G_TYPE_FROM_CLASS (object_class),
6219 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6220 _clutter_boolean_handled_accumulator, NULL,
6221 _clutter_marshal_BOOLEAN__BOXED,
6223 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6226 * ClutterActor::leave-event:
6227 * @actor: the actor which the pointer has left
6228 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6230 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6232 * Return value: %TRUE if the event has been handled by the actor,
6233 * or %FALSE to continue the emission.
6237 actor_signals[LEAVE_EVENT] =
6238 g_signal_new (I_("leave-event"),
6239 G_TYPE_FROM_CLASS (object_class),
6241 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6242 _clutter_boolean_handled_accumulator, NULL,
6243 _clutter_marshal_BOOLEAN__BOXED,
6245 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6248 * ClutterActor::captured-event:
6249 * @actor: the actor which received the signal
6250 * @event: a #ClutterEvent
6252 * The ::captured-event signal is emitted when an event is captured
6253 * by Clutter. This signal will be emitted starting from the top-level
6254 * container (the #ClutterStage) to the actor which received the event
6255 * going down the hierarchy. This signal can be used to intercept every
6256 * event before the specialized events (like
6257 * ClutterActor::button-press-event or ::key-released-event) are
6260 * Return value: %TRUE if the event has been handled by the actor,
6261 * or %FALSE to continue the emission.
6265 actor_signals[CAPTURED_EVENT] =
6266 g_signal_new (I_("captured-event"),
6267 G_TYPE_FROM_CLASS (object_class),
6269 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6270 _clutter_boolean_handled_accumulator, NULL,
6271 _clutter_marshal_BOOLEAN__BOXED,
6273 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6276 * ClutterActor::paint:
6277 * @actor: the #ClutterActor that received the signal
6279 * The ::paint signal is emitted each time an actor is being painted.
6281 * Subclasses of #ClutterActor should override the class signal handler
6282 * and paint themselves in that function.
6284 * It is possible to connect a handler to the ::paint signal in order
6285 * to set up some custom aspect of a paint.
6289 actor_signals[PAINT] =
6290 g_signal_new (I_("paint"),
6291 G_TYPE_FROM_CLASS (object_class),
6293 G_STRUCT_OFFSET (ClutterActorClass, paint),
6295 _clutter_marshal_VOID__VOID,
6298 * ClutterActor::realize:
6299 * @actor: the #ClutterActor that received the signal
6301 * The ::realize signal is emitted each time an actor is being
6306 actor_signals[REALIZE] =
6307 g_signal_new (I_("realize"),
6308 G_TYPE_FROM_CLASS (object_class),
6310 G_STRUCT_OFFSET (ClutterActorClass, realize),
6312 _clutter_marshal_VOID__VOID,
6315 * ClutterActor::unrealize:
6316 * @actor: the #ClutterActor that received the signal
6318 * The ::unrealize signal is emitted each time an actor is being
6323 actor_signals[UNREALIZE] =
6324 g_signal_new (I_("unrealize"),
6325 G_TYPE_FROM_CLASS (object_class),
6327 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6329 _clutter_marshal_VOID__VOID,
6333 * ClutterActor::pick:
6334 * @actor: the #ClutterActor that received the signal
6335 * @color: the #ClutterColor to be used when picking
6337 * The ::pick signal is emitted each time an actor is being painted
6338 * in "pick mode". The pick mode is used to identify the actor during
6339 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6340 * The actor should paint its shape using the passed @pick_color.
6342 * Subclasses of #ClutterActor should override the class signal handler
6343 * and paint themselves in that function.
6345 * It is possible to connect a handler to the ::pick signal in order
6346 * to set up some custom aspect of a paint in pick mode.
6350 actor_signals[PICK] =
6351 g_signal_new (I_("pick"),
6352 G_TYPE_FROM_CLASS (object_class),
6354 G_STRUCT_OFFSET (ClutterActorClass, pick),
6356 _clutter_marshal_VOID__BOXED,
6358 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6361 * ClutterActor::allocation-changed:
6362 * @actor: the #ClutterActor that emitted the signal
6363 * @box: a #ClutterActorBox with the new allocation
6364 * @flags: #ClutterAllocationFlags for the allocation
6366 * The ::allocation-changed signal is emitted when the
6367 * #ClutterActor:allocation property changes. Usually, application
6368 * code should just use the notifications for the :allocation property
6369 * but if you want to track the allocation flags as well, for instance
6370 * to know whether the absolute origin of @actor changed, then you might
6371 * want use this signal instead.
6375 actor_signals[ALLOCATION_CHANGED] =
6376 g_signal_new (I_("allocation-changed"),
6377 G_TYPE_FROM_CLASS (object_class),
6381 _clutter_marshal_VOID__BOXED_FLAGS,
6383 CLUTTER_TYPE_ACTOR_BOX,
6384 CLUTTER_TYPE_ALLOCATION_FLAGS);
6388 clutter_actor_init (ClutterActor *self)
6390 ClutterActorPrivate *priv;
6392 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6394 priv->id = _clutter_context_acquire_id (self);
6397 priv->opacity = 0xff;
6398 priv->show_on_set_parent = TRUE;
6400 priv->needs_width_request = TRUE;
6401 priv->needs_height_request = TRUE;
6402 priv->needs_allocation = TRUE;
6404 priv->cached_width_age = 1;
6405 priv->cached_height_age = 1;
6407 priv->opacity_override = -1;
6408 priv->enable_model_view_transform = TRUE;
6410 /* Initialize an empty paint volume to start with */
6411 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6412 priv->last_paint_volume_valid = TRUE;
6414 priv->transform_valid = FALSE;
6418 * clutter_actor_new:
6420 * Creates a new #ClutterActor.
6422 * A newly created actor has a floating reference, which will be sunk
6423 * when it is added to another actor.
6425 * Return value: (transfer full): the newly created #ClutterActor
6430 clutter_actor_new (void)
6432 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6436 * clutter_actor_destroy:
6437 * @self: a #ClutterActor
6439 * Destroys an actor. When an actor is destroyed, it will break any
6440 * references it holds to other objects. If the actor is inside a
6441 * container, the actor will be removed.
6443 * When you destroy a container, its children will be destroyed as well.
6445 * Note: you cannot destroy the #ClutterStage returned by
6446 * clutter_stage_get_default().
6449 clutter_actor_destroy (ClutterActor *self)
6451 g_return_if_fail (CLUTTER_IS_ACTOR (self));
6453 g_object_ref (self);
6455 /* avoid recursion while destroying */
6456 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6458 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6460 g_object_run_dispose (G_OBJECT (self));
6462 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6465 g_object_unref (self);
6469 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6470 ClutterPaintVolume *clip)
6472 ClutterActorPrivate *priv = self->priv;
6473 ClutterPaintVolume *pv;
6476 /* If we've been explicitly passed a clip volume then there's
6477 * nothing more to calculate, but otherwise the only thing we know
6478 * is that the change is constrained to the given actor.
6480 * The idea is that if we know the paint volume for where the actor
6481 * was last drawn (in eye coordinates) and we also have the paint
6482 * volume for where it will be drawn next (in actor coordinates)
6483 * then if we queue a redraw for both these volumes that will cover
6484 * everything that needs to be redrawn to clear the old view and
6485 * show the latest view of the actor.
6487 * Don't clip this redraw if we don't know what position we had for
6488 * the previous redraw since we don't know where to set the clip so
6489 * it will clear the actor as it is currently.
6493 _clutter_actor_set_queue_redraw_clip (self, clip);
6496 else if (G_LIKELY (priv->last_paint_volume_valid))
6498 pv = _clutter_actor_get_paint_volume_mutable (self);
6501 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6503 /* make sure we redraw the actors old position... */
6504 _clutter_actor_set_queue_redraw_clip (stage,
6505 &priv->last_paint_volume);
6506 _clutter_actor_signal_queue_redraw (stage, stage);
6507 _clutter_actor_set_queue_redraw_clip (stage, NULL);
6509 /* XXX: Ideally the redraw signal would take a clip volume
6510 * argument, but that would be an ABI break. Until we can
6511 * break the ABI we pass the argument out-of-band
6514 /* setup the clip for the actors new position... */
6515 _clutter_actor_set_queue_redraw_clip (self, pv);
6524 _clutter_actor_signal_queue_redraw (self, self);
6526 /* Just in case anyone is manually firing redraw signals without
6527 * using the public queue_redraw() API we are careful to ensure that
6528 * our out-of-band clip member is cleared before returning...
6530 * Note: A NULL clip denotes a full-stage, un-clipped redraw
6532 if (G_LIKELY (clipped))
6533 _clutter_actor_set_queue_redraw_clip (self, NULL);
6535 priv->queue_redraw_entry = NULL;
6539 _clutter_actor_get_allocation_clip (ClutterActor *self,
6540 ClutterActorBox *clip)
6542 ClutterActorBox allocation;
6544 /* XXX: we don't care if we get an out of date allocation here
6545 * because clutter_actor_queue_redraw_with_clip knows to ignore
6546 * the clip if the actor's allocation is invalid.
6548 * This is noted because clutter_actor_get_allocation_box does some
6549 * unnecessary work to support buggy code with a comment suggesting
6550 * that it could be changed later which would be good for this use
6553 clutter_actor_get_allocation_box (self, &allocation);
6555 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6556 * actor's own coordinate space but the allocation is in parent
6560 clip->x2 = allocation.x2 - allocation.x1;
6561 clip->y2 = allocation.y2 - allocation.y1;
6565 _clutter_actor_queue_redraw_full (ClutterActor *self,
6566 ClutterRedrawFlags flags,
6567 ClutterPaintVolume *volume,
6568 ClutterEffect *effect)
6570 ClutterActorPrivate *priv = self->priv;
6571 ClutterPaintVolume allocation_pv;
6572 ClutterPaintVolume *pv;
6573 gboolean should_free_pv;
6574 ClutterActor *stage;
6576 /* Here's an outline of the actor queue redraw mechanism:
6578 * The process starts in one of the following two functions which
6579 * are wrappers for this function:
6580 * clutter_actor_queue_redraw
6581 * _clutter_actor_queue_redraw_with_clip
6583 * additionally, an effect can queue a redraw by wrapping this
6584 * function in clutter_effect_queue_rerun
6586 * This functions queues an entry in a list associated with the
6587 * stage which is a list of actors that queued a redraw while
6588 * updating the timelines, performing layouting and processing other
6589 * mainloop sources before the next paint starts.
6591 * We aim to minimize the processing done at this point because
6592 * there is a good chance other events will happen while updating
6593 * the scenegraph that would invalidate any expensive work we might
6594 * otherwise try to do here. For example we don't try and resolve
6595 * the screen space bounding box of an actor at this stage so as to
6596 * minimize how much of the screen redraw because it's possible
6597 * something else will happen which will force a full redraw anyway.
6599 * When all updates are complete and we come to paint the stage then
6600 * we iterate this list and actually emit the "queue-redraw" signals
6601 * for each of the listed actors which will bubble up to the stage
6602 * for each actor and at that point we will transform the actors
6603 * paint volume into screen coordinates to determine the clip region
6604 * for what needs to be redrawn in the next paint.
6606 * Besides minimizing redundant work another reason for this
6607 * deferred design is that it's more likely we will be able to
6608 * determine the paint volume of an actor once we've finished
6609 * updating the scenegraph because its allocation should be up to
6610 * date. NB: If we can't determine an actors paint volume then we
6611 * can't automatically queue a clipped redraw which can make a big
6612 * difference to performance.
6614 * So the control flow goes like this:
6615 * One of clutter_actor_queue_redraw,
6616 * _clutter_actor_queue_redraw_with_clip
6617 * or clutter_effect_queue_rerun
6619 * then control moves to:
6620 * _clutter_stage_queue_actor_redraw
6622 * later during _clutter_stage_do_update, once relayouting is done
6623 * and the scenegraph has been updated we will call:
6624 * _clutter_stage_finish_queue_redraws
6626 * _clutter_stage_finish_queue_redraws will call
6627 * _clutter_actor_finish_queue_redraw for each listed actor.
6628 * Note: actors *are* allowed to queue further redraws during this
6629 * process (considering clone actors or texture_new_from_actor which
6630 * respond to their source queueing a redraw by queuing a redraw
6631 * themselves). We repeat the process until the list is empty.
6633 * This will result in the "queue-redraw" signal being fired for
6634 * each actor which will pass control to the default signal handler:
6635 * clutter_actor_real_queue_redraw
6637 * This will bubble up to the stages handler:
6638 * clutter_stage_real_queue_redraw
6640 * clutter_stage_real_queue_redraw will transform the actors paint
6641 * volume into screen space and add it as a clip region for the next
6645 /* ignore queueing a redraw for actors being destroyed */
6646 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6649 stage = _clutter_actor_get_stage_internal (self);
6651 /* Ignore queueing a redraw for actors not descended from a stage */
6655 /* ignore queueing a redraw on stages that are being destroyed */
6656 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6659 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6661 ClutterActorBox allocation_clip;
6662 ClutterVertex origin;
6664 /* If the actor doesn't have a valid allocation then we will
6665 * queue a full stage redraw. */
6666 if (priv->needs_allocation)
6668 /* NB: NULL denotes an undefined clip which will result in a
6670 _clutter_actor_set_queue_redraw_clip (self, NULL);
6671 _clutter_actor_signal_queue_redraw (self, self);
6675 _clutter_paint_volume_init_static (&allocation_pv, self);
6676 pv = &allocation_pv;
6678 _clutter_actor_get_allocation_clip (self, &allocation_clip);
6680 origin.x = allocation_clip.x1;
6681 origin.y = allocation_clip.y1;
6683 clutter_paint_volume_set_origin (pv, &origin);
6684 clutter_paint_volume_set_width (pv,
6685 allocation_clip.x2 - allocation_clip.x1);
6686 clutter_paint_volume_set_height (pv,
6687 allocation_clip.y2 -
6688 allocation_clip.y1);
6689 should_free_pv = TRUE;
6694 should_free_pv = FALSE;
6697 self->priv->queue_redraw_entry =
6698 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6699 priv->queue_redraw_entry,
6704 clutter_paint_volume_free (pv);
6706 /* If this is the first redraw queued then we can directly use the
6708 if (!priv->is_dirty)
6709 priv->effect_to_redraw = effect;
6710 /* Otherwise we need to merge it with the existing effect parameter */
6711 else if (effect != NULL)
6713 /* If there's already an effect then we need to use whichever is
6714 later in the chain of actors. Otherwise a full redraw has
6715 already been queued on the actor so we need to ignore the
6717 if (priv->effect_to_redraw != NULL)
6719 if (priv->effects == NULL)
6720 g_warning ("Redraw queued with an effect that is "
6721 "not applied to the actor");
6726 for (l = _clutter_meta_group_peek_metas (priv->effects);
6730 if (l->data == priv->effect_to_redraw ||
6732 priv->effect_to_redraw = l->data;
6739 /* If no effect is specified then we need to redraw the whole
6741 priv->effect_to_redraw = NULL;
6744 priv->is_dirty = TRUE;
6748 * clutter_actor_queue_redraw:
6749 * @self: A #ClutterActor
6751 * Queues up a redraw of an actor and any children. The redraw occurs
6752 * once the main loop becomes idle (after the current batch of events
6753 * has been processed, roughly).
6755 * Applications rarely need to call this, as redraws are handled
6756 * automatically by modification functions.
6758 * This function will not do anything if @self is not visible, or
6759 * if the actor is inside an invisible part of the scenegraph.
6761 * Also be aware that painting is a NOP for actors with an opacity of
6764 * When you are implementing a custom actor you must queue a redraw
6765 * whenever some private state changes that will affect painting or
6766 * picking of your actor.
6769 clutter_actor_queue_redraw (ClutterActor *self)
6771 g_return_if_fail (CLUTTER_IS_ACTOR (self));
6773 _clutter_actor_queue_redraw_full (self,
6775 NULL, /* clip volume */
6780 * _clutter_actor_queue_redraw_with_clip:
6781 * @self: A #ClutterActor
6782 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6783 * this queue redraw.
6784 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6785 * redrawn or %NULL if you are just using a @flag to state your
6788 * Queues up a clipped redraw of an actor and any children. The redraw
6789 * occurs once the main loop becomes idle (after the current batch of
6790 * events has been processed, roughly).
6792 * If no flags are given the clip volume is defined by @volume
6793 * specified in actor coordinates and tells Clutter that only content
6794 * within this volume has been changed so Clutter can optionally
6795 * optimize the redraw.
6797 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6798 * should be %NULL and this tells Clutter to use the actor's current
6799 * allocation as a clip box. This flag can only be used for 2D actors,
6800 * because any actor with depth may be projected outside its
6803 * Applications rarely need to call this, as redraws are handled
6804 * automatically by modification functions.
6806 * This function will not do anything if @self is not visible, or if
6807 * the actor is inside an invisible part of the scenegraph.
6809 * Also be aware that painting is a NOP for actors with an opacity of
6812 * When you are implementing a custom actor you must queue a redraw
6813 * whenever some private state changes that will affect painting or
6814 * picking of your actor.
6817 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
6818 ClutterRedrawFlags flags,
6819 ClutterPaintVolume *volume)
6821 _clutter_actor_queue_redraw_full (self,
6823 volume, /* clip volume */
6828 _clutter_actor_queue_only_relayout (ClutterActor *self)
6830 ClutterActorPrivate *priv = self->priv;
6832 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6835 if (priv->needs_width_request &&
6836 priv->needs_height_request &&
6837 priv->needs_allocation)
6838 return; /* save some cpu cycles */
6840 #if CLUTTER_ENABLE_DEBUG
6841 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6843 g_warning ("The actor '%s' is currently inside an allocation "
6844 "cycle; calling clutter_actor_queue_relayout() is "
6846 _clutter_actor_get_debug_name (self));
6848 #endif /* CLUTTER_ENABLE_DEBUG */
6850 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6854 * clutter_actor_queue_redraw_with_clip:
6855 * @self: a #ClutterActor
6856 * @clip: (allow-none): a rectangular clip region, or %NULL
6858 * Queues a redraw on @self limited to a specific, actor-relative
6861 * If @clip is %NULL this function is equivalent to
6862 * clutter_actor_queue_redraw().
6867 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
6868 const cairo_rectangle_int_t *clip)
6870 ClutterPaintVolume volume;
6871 ClutterVertex origin;
6873 g_return_if_fail (CLUTTER_IS_ACTOR (self));
6877 clutter_actor_queue_redraw (self);
6881 _clutter_paint_volume_init_static (&volume, self);
6887 clutter_paint_volume_set_origin (&volume, &origin);
6888 clutter_paint_volume_set_width (&volume, clip->width);
6889 clutter_paint_volume_set_height (&volume, clip->height);
6891 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6893 clutter_paint_volume_free (&volume);
6897 * clutter_actor_queue_relayout:
6898 * @self: A #ClutterActor
6900 * Indicates that the actor's size request or other layout-affecting
6901 * properties may have changed. This function is used inside #ClutterActor
6902 * subclass implementations, not by applications directly.
6904 * Queueing a new layout automatically queues a redraw as well.
6909 clutter_actor_queue_relayout (ClutterActor *self)
6911 g_return_if_fail (CLUTTER_IS_ACTOR (self));
6913 _clutter_actor_queue_only_relayout (self);
6914 clutter_actor_queue_redraw (self);
6918 * clutter_actor_get_preferred_size:
6919 * @self: a #ClutterActor
6920 * @min_width_p: (out) (allow-none): return location for the minimum
6922 * @min_height_p: (out) (allow-none): return location for the minimum
6924 * @natural_width_p: (out) (allow-none): return location for the natural
6926 * @natural_height_p: (out) (allow-none): return location for the natural
6929 * Computes the preferred minimum and natural size of an actor, taking into
6930 * account the actor's geometry management (either height-for-width
6931 * or width-for-height).
6933 * The width and height used to compute the preferred height and preferred
6934 * width are the actor's natural ones.
6936 * If you need to control the height for the preferred width, or the width for
6937 * the preferred height, you should use clutter_actor_get_preferred_width()
6938 * and clutter_actor_get_preferred_height(), and check the actor's preferred
6939 * geometry management using the #ClutterActor:request-mode property.
6944 clutter_actor_get_preferred_size (ClutterActor *self,
6945 gfloat *min_width_p,
6946 gfloat *min_height_p,
6947 gfloat *natural_width_p,
6948 gfloat *natural_height_p)
6950 ClutterActorPrivate *priv;
6951 gfloat min_width, min_height;
6952 gfloat natural_width, natural_height;
6954 g_return_if_fail (CLUTTER_IS_ACTOR (self));
6958 min_width = min_height = 0;
6959 natural_width = natural_height = 0;
6961 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
6963 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
6964 clutter_actor_get_preferred_width (self, -1,
6967 clutter_actor_get_preferred_height (self, natural_width,
6973 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
6974 clutter_actor_get_preferred_height (self, -1,
6977 clutter_actor_get_preferred_width (self, natural_height,
6983 *min_width_p = min_width;
6986 *min_height_p = min_height;
6988 if (natural_width_p)
6989 *natural_width_p = natural_width;
6991 if (natural_height_p)
6992 *natural_height_p = natural_height;
6997 * @align: a #ClutterActorAlign
6998 * @direction: a #ClutterTextDirection
7000 * Retrieves the correct alignment depending on the text direction
7002 * Return value: the effective alignment
7004 static ClutterActorAlign
7005 effective_align (ClutterActorAlign align,
7006 ClutterTextDirection direction)
7008 ClutterActorAlign res;
7012 case CLUTTER_ACTOR_ALIGN_START:
7013 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7014 ? CLUTTER_ACTOR_ALIGN_END
7015 : CLUTTER_ACTOR_ALIGN_START;
7018 case CLUTTER_ACTOR_ALIGN_END:
7019 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7020 ? CLUTTER_ACTOR_ALIGN_START
7021 : CLUTTER_ACTOR_ALIGN_END;
7033 adjust_for_margin (float margin_start,
7035 float *minimum_size,
7036 float *natural_size,
7037 float *allocated_start,
7038 float *allocated_end)
7040 *minimum_size -= (margin_start + margin_end);
7041 *natural_size -= (margin_start + margin_end);
7042 *allocated_start += margin_start;
7043 *allocated_end -= margin_end;
7047 adjust_for_alignment (ClutterActorAlign alignment,
7049 float *allocated_start,
7050 float *allocated_end)
7052 float allocated_size = *allocated_end - *allocated_start;
7056 case CLUTTER_ACTOR_ALIGN_FILL:
7060 case CLUTTER_ACTOR_ALIGN_START:
7062 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7065 case CLUTTER_ACTOR_ALIGN_END:
7066 if (allocated_size > natural_size)
7068 *allocated_start += (allocated_size - natural_size);
7069 *allocated_end = *allocated_start + natural_size;
7073 case CLUTTER_ACTOR_ALIGN_CENTER:
7074 if (allocated_size > natural_size)
7076 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7077 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7084 * clutter_actor_adjust_width:
7085 * @self: a #ClutterActor
7086 * @minimum_width: (inout): the actor's preferred minimum width, which
7087 * will be adjusted depending on the margin
7088 * @natural_width: (inout): the actor's preferred natural width, which
7089 * will be adjusted depending on the margin
7090 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7091 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7093 * Adjusts the preferred and allocated position and size of an actor,
7094 * depending on the margin and alignment properties.
7097 clutter_actor_adjust_width (ClutterActor *self,
7098 gfloat *minimum_width,
7099 gfloat *natural_width,
7100 gfloat *adjusted_x1,
7101 gfloat *adjusted_x2)
7103 ClutterTextDirection text_dir;
7104 const ClutterLayoutInfo *info;
7106 info = _clutter_actor_get_layout_info_or_defaults (self);
7107 text_dir = clutter_actor_get_text_direction (self);
7109 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7111 /* this will tweak natural_width to remove the margin, so that
7112 * adjust_for_alignment() will use the correct size
7114 adjust_for_margin (info->margin.left, info->margin.right,
7115 minimum_width, natural_width,
7116 adjusted_x1, adjusted_x2);
7118 adjust_for_alignment (effective_align (info->x_align, text_dir),
7120 adjusted_x1, adjusted_x2);
7124 * clutter_actor_adjust_height:
7125 * @self: a #ClutterActor
7126 * @minimum_height: (inout): the actor's preferred minimum height, which
7127 * will be adjusted depending on the margin
7128 * @natural_height: (inout): the actor's preferred natural height, which
7129 * will be adjusted depending on the margin
7130 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7131 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7133 * Adjusts the preferred and allocated position and size of an actor,
7134 * depending on the margin and alignment properties.
7137 clutter_actor_adjust_height (ClutterActor *self,
7138 gfloat *minimum_height,
7139 gfloat *natural_height,
7140 gfloat *adjusted_y1,
7141 gfloat *adjusted_y2)
7143 const ClutterLayoutInfo *info;
7145 info = _clutter_actor_get_layout_info_or_defaults (self);
7147 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7149 /* this will tweak natural_height to remove the margin, so that
7150 * adjust_for_alignment() will use the correct size
7152 adjust_for_margin (info->margin.top, info->margin.bottom,
7153 minimum_height, natural_height,
7157 /* we don't use effective_align() here, because text direction
7158 * only affects the horizontal axis
7160 adjust_for_alignment (info->y_align,
7167 /* looks for a cached size request for this for_size. If not
7168 * found, returns the oldest entry so it can be overwritten */
7170 _clutter_actor_get_cached_size_request (gfloat for_size,
7171 SizeRequest *cached_size_requests,
7172 SizeRequest **result)
7176 *result = &cached_size_requests[0];
7178 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7182 sr = &cached_size_requests[i];
7185 sr->for_size == for_size)
7187 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7191 else if (sr->age < (*result)->age)
7197 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7203 * clutter_actor_get_preferred_width:
7204 * @self: A #ClutterActor
7205 * @for_height: available height when computing the preferred width,
7206 * or a negative value to indicate that no height is defined
7207 * @min_width_p: (out) (allow-none): return location for minimum width,
7209 * @natural_width_p: (out) (allow-none): return location for the natural
7212 * Computes the requested minimum and natural widths for an actor,
7213 * optionally depending on the specified height, or if they are
7214 * already computed, returns the cached values.
7216 * An actor may not get its request - depending on the layout
7217 * manager that's in effect.
7219 * A request should not incorporate the actor's scale or anchor point;
7220 * those transformations do not affect layout, only rendering.
7225 clutter_actor_get_preferred_width (ClutterActor *self,
7227 gfloat *min_width_p,
7228 gfloat *natural_width_p)
7230 float request_min_width, request_natural_width;
7231 SizeRequest *cached_size_request;
7232 const ClutterLayoutInfo *info;
7233 ClutterActorPrivate *priv;
7234 gboolean found_in_cache;
7236 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7240 info = _clutter_actor_get_layout_info_or_defaults (self);
7242 /* we shortcircuit the case of a fixed size set using set_width() */
7243 if (priv->min_width_set && priv->natural_width_set)
7245 if (min_width_p != NULL)
7246 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7248 if (natural_width_p != NULL)
7249 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7254 /* the remaining cases are:
7256 * - either min_width or natural_width have been set
7257 * - neither min_width or natural_width have been set
7259 * in both cases, we go through the cache (and through the actor in case
7260 * of cache misses) and determine the authoritative value depending on
7264 if (!priv->needs_width_request)
7267 _clutter_actor_get_cached_size_request (for_height,
7268 priv->width_requests,
7269 &cached_size_request);
7273 /* if the actor needs a width request we use the first slot */
7274 found_in_cache = FALSE;
7275 cached_size_request = &priv->width_requests[0];
7278 if (!found_in_cache)
7280 gfloat minimum_width, natural_width;
7281 ClutterActorClass *klass;
7283 minimum_width = natural_width = 0;
7285 /* adjust for the margin */
7286 if (for_height >= 0)
7288 for_height -= (info->margin.top + info->margin.bottom);
7293 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7295 klass = CLUTTER_ACTOR_GET_CLASS (self);
7296 klass->get_preferred_width (self, for_height,
7300 /* adjust for the margin */
7301 minimum_width += (info->margin.left + info->margin.right);
7302 natural_width += (info->margin.left + info->margin.right);
7304 /* Due to accumulated float errors, it's better not to warn
7305 * on this, but just fix it.
7307 if (natural_width < minimum_width)
7308 natural_width = minimum_width;
7310 cached_size_request->min_size = minimum_width;
7311 cached_size_request->natural_size = natural_width;
7312 cached_size_request->for_size = for_height;
7313 cached_size_request->age = priv->cached_width_age;
7315 priv->cached_width_age += 1;
7316 priv->needs_width_request = FALSE;
7319 if (!priv->min_width_set)
7320 request_min_width = cached_size_request->min_size;
7322 request_min_width = info->min_width;
7324 if (!priv->natural_width_set)
7325 request_natural_width = cached_size_request->natural_size;
7327 request_natural_width = info->natural_width;
7330 *min_width_p = request_min_width;
7332 if (natural_width_p)
7333 *natural_width_p = request_natural_width;
7337 * clutter_actor_get_preferred_height:
7338 * @self: A #ClutterActor
7339 * @for_width: available width to assume in computing desired height,
7340 * or a negative value to indicate that no width is defined
7341 * @min_height_p: (out) (allow-none): return location for minimum height,
7343 * @natural_height_p: (out) (allow-none): return location for natural
7346 * Computes the requested minimum and natural heights for an actor,
7347 * or if they are already computed, returns the cached values.
7349 * An actor may not get its request - depending on the layout
7350 * manager that's in effect.
7352 * A request should not incorporate the actor's scale or anchor point;
7353 * those transformations do not affect layout, only rendering.
7358 clutter_actor_get_preferred_height (ClutterActor *self,
7360 gfloat *min_height_p,
7361 gfloat *natural_height_p)
7363 float request_min_height, request_natural_height;
7364 SizeRequest *cached_size_request;
7365 const ClutterLayoutInfo *info;
7366 ClutterActorPrivate *priv;
7367 gboolean found_in_cache;
7369 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7373 info = _clutter_actor_get_layout_info_or_defaults (self);
7375 /* we shortcircuit the case of a fixed size set using set_height() */
7376 if (priv->min_height_set && priv->natural_height_set)
7378 if (min_height_p != NULL)
7379 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7381 if (natural_height_p != NULL)
7382 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7387 /* the remaining cases are:
7389 * - either min_height or natural_height have been set
7390 * - neither min_height or natural_height have been set
7392 * in both cases, we go through the cache (and through the actor in case
7393 * of cache misses) and determine the authoritative value depending on
7397 if (!priv->needs_height_request)
7400 _clutter_actor_get_cached_size_request (for_width,
7401 priv->height_requests,
7402 &cached_size_request);
7406 found_in_cache = FALSE;
7407 cached_size_request = &priv->height_requests[0];
7410 if (!found_in_cache)
7412 gfloat minimum_height, natural_height;
7413 ClutterActorClass *klass;
7415 minimum_height = natural_height = 0;
7417 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7419 /* adjust for margin */
7422 for_width -= (info->margin.left + info->margin.right);
7427 klass = CLUTTER_ACTOR_GET_CLASS (self);
7428 klass->get_preferred_height (self, for_width,
7432 /* adjust for margin */
7433 minimum_height += (info->margin.top + info->margin.bottom);
7434 natural_height += (info->margin.top + info->margin.bottom);
7436 /* Due to accumulated float errors, it's better not to warn
7437 * on this, but just fix it.
7439 if (natural_height < minimum_height)
7440 natural_height = minimum_height;
7442 cached_size_request->min_size = minimum_height;
7443 cached_size_request->natural_size = natural_height;
7444 cached_size_request->for_size = for_width;
7445 cached_size_request->age = priv->cached_height_age;
7447 priv->cached_height_age += 1;
7448 priv->needs_height_request = FALSE;
7451 if (!priv->min_height_set)
7452 request_min_height = cached_size_request->min_size;
7454 request_min_height = info->min_height;
7456 if (!priv->natural_height_set)
7457 request_natural_height = cached_size_request->natural_size;
7459 request_natural_height = info->natural_height;
7462 *min_height_p = request_min_height;
7464 if (natural_height_p)
7465 *natural_height_p = request_natural_height;
7469 * clutter_actor_get_allocation_box:
7470 * @self: A #ClutterActor
7471 * @box: (out): the function fills this in with the actor's allocation
7473 * Gets the layout box an actor has been assigned. The allocation can
7474 * only be assumed valid inside a paint() method; anywhere else, it
7475 * may be out-of-date.
7477 * An allocation does not incorporate the actor's scale or anchor point;
7478 * those transformations do not affect layout, only rendering.
7480 * <note>Do not call any of the clutter_actor_get_allocation_*() family
7481 * of functions inside the implementation of the get_preferred_width()
7482 * or get_preferred_height() virtual functions.</note>
7487 clutter_actor_get_allocation_box (ClutterActor *self,
7488 ClutterActorBox *box)
7490 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7492 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7493 * which limits calling get_allocation to inside paint() basically; or
7494 * we can 2) force a layout, which could be expensive if someone calls
7495 * get_allocation somewhere silly; or we can 3) just return the latest
7496 * value, allowing it to be out-of-date, and assume people know what
7499 * The least-surprises approach that keeps existing code working is
7500 * likely to be 2). People can end up doing some inefficient things,
7501 * though, and in general code that requires 2) is probably broken.
7504 /* this implements 2) */
7505 if (G_UNLIKELY (self->priv->needs_allocation))
7507 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7509 /* do not queue a relayout on an unparented actor */
7511 _clutter_stage_maybe_relayout (stage);
7514 /* commenting out the code above and just keeping this assigment
7517 *box = self->priv->allocation;
7521 * clutter_actor_get_allocation_geometry:
7522 * @self: A #ClutterActor
7523 * @geom: (out): allocation geometry in pixels
7525 * Gets the layout box an actor has been assigned. The allocation can
7526 * only be assumed valid inside a paint() method; anywhere else, it
7527 * may be out-of-date.
7529 * An allocation does not incorporate the actor's scale or anchor point;
7530 * those transformations do not affect layout, only rendering.
7532 * The returned rectangle is in pixels.
7537 clutter_actor_get_allocation_geometry (ClutterActor *self,
7538 ClutterGeometry *geom)
7540 ClutterActorBox box;
7542 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7543 g_return_if_fail (geom != NULL);
7545 clutter_actor_get_allocation_box (self, &box);
7547 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7548 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7549 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7550 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7554 clutter_actor_update_constraints (ClutterActor *self,
7555 ClutterActorBox *allocation)
7557 ClutterActorPrivate *priv = self->priv;
7558 const GList *constraints, *l;
7560 if (priv->constraints == NULL)
7563 constraints = _clutter_meta_group_peek_metas (priv->constraints);
7564 for (l = constraints; l != NULL; l = l->next)
7566 ClutterConstraint *constraint = l->data;
7567 ClutterActorMeta *meta = l->data;
7569 if (clutter_actor_meta_get_enabled (meta))
7571 _clutter_constraint_update_allocation (constraint,
7579 * clutter_actor_adjust_allocation:
7580 * @self: a #ClutterActor
7581 * @allocation: (inout): the allocation to adjust
7583 * Adjusts the passed allocation box taking into account the actor's
7584 * layout information, like alignment, expansion, and margin.
7587 clutter_actor_adjust_allocation (ClutterActor *self,
7588 ClutterActorBox *allocation)
7590 ClutterActorBox adj_allocation;
7591 float alloc_width, alloc_height;
7592 float min_width, min_height;
7593 float nat_width, nat_height;
7594 ClutterRequestMode req_mode;
7596 adj_allocation = *allocation;
7598 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7600 /* we want to hit the cache, so we use the public API */
7601 req_mode = clutter_actor_get_request_mode (self);
7603 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7605 clutter_actor_get_preferred_width (self, -1,
7608 clutter_actor_get_preferred_height (self, alloc_width,
7612 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7614 clutter_actor_get_preferred_height (self, -1,
7617 clutter_actor_get_preferred_height (self, alloc_height,
7622 #ifdef CLUTTER_ENABLE_DEBUG
7623 /* warn about underallocations */
7624 if (_clutter_diagnostic_enabled () &&
7625 (floorf (min_width - alloc_width) > 0 ||
7626 floorf (min_height - alloc_height) > 0))
7628 ClutterActor *parent = clutter_actor_get_parent (self);
7630 /* the only actors that are allowed to be underallocated are the Stage,
7631 * as it doesn't have an implicit size, and Actors that specifically
7632 * told us that they want to opt-out from layout control mechanisms
7633 * through the NO_LAYOUT escape hatch.
7635 if (parent != NULL &&
7636 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7638 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7639 "of %.2f x %.2f from its parent actor '%s', but its "
7640 "requested minimum size is of %.2f x %.2f",
7641 _clutter_actor_get_debug_name (self),
7642 alloc_width, alloc_height,
7643 _clutter_actor_get_debug_name (parent),
7644 min_width, min_height);
7649 clutter_actor_adjust_width (self,
7653 &adj_allocation.x2);
7655 clutter_actor_adjust_height (self,
7659 &adj_allocation.y2);
7661 /* we maintain the invariant that an allocation cannot be adjusted
7662 * to be outside the parent-given box
7664 if (adj_allocation.x1 < allocation->x1 ||
7665 adj_allocation.y1 < allocation->y1 ||
7666 adj_allocation.x2 > allocation->x2 ||
7667 adj_allocation.y2 > allocation->y2)
7669 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7670 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7671 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7672 _clutter_actor_get_debug_name (self),
7673 adj_allocation.x1, adj_allocation.y1,
7674 adj_allocation.x2 - adj_allocation.x1,
7675 adj_allocation.y2 - adj_allocation.y1,
7676 allocation->x1, allocation->y1,
7677 allocation->x2 - allocation->x1,
7678 allocation->y2 - allocation->y1);
7682 *allocation = adj_allocation;
7686 * clutter_actor_allocate:
7687 * @self: A #ClutterActor
7688 * @box: new allocation of the actor, in parent-relative coordinates
7689 * @flags: flags that control the allocation
7691 * Called by the parent of an actor to assign the actor its size.
7692 * Should never be called by applications (except when implementing
7693 * a container or layout manager).
7695 * Actors can know from their allocation box whether they have moved
7696 * with respect to their parent actor. The @flags parameter describes
7697 * additional information about the allocation, for instance whether
7698 * the parent has moved with respect to the stage, for example because
7699 * a grandparent's origin has moved.
7704 clutter_actor_allocate (ClutterActor *self,
7705 const ClutterActorBox *box,
7706 ClutterAllocationFlags flags)
7708 ClutterActorPrivate *priv;
7709 ClutterActorClass *klass;
7710 ClutterActorBox old_allocation, real_allocation;
7711 gboolean origin_changed, child_moved, size_changed;
7712 gboolean stage_allocation_changed;
7714 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7715 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7717 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7718 "which isn't a descendent of the stage!\n",
7719 self, _clutter_actor_get_debug_name (self));
7725 old_allocation = priv->allocation;
7726 real_allocation = *box;
7728 /* constraints are allowed to modify the allocation only here; we do
7729 * this prior to all the other checks so that we can bail out if the
7730 * allocation did not change
7732 clutter_actor_update_constraints (self, &real_allocation);
7734 /* adjust the allocation depending on the align/margin properties */
7735 clutter_actor_adjust_allocation (self, &real_allocation);
7737 if (real_allocation.x2 < real_allocation.x1 ||
7738 real_allocation.y2 < real_allocation.y1)
7740 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7741 _clutter_actor_get_debug_name (self),
7742 real_allocation.x2 - real_allocation.x1,
7743 real_allocation.y2 - real_allocation.y1);
7746 /* we allow 0-sized actors, but not negative-sized ones */
7747 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7748 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7750 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7752 child_moved = (real_allocation.x1 != old_allocation.x1 ||
7753 real_allocation.y1 != old_allocation.y1);
7755 size_changed = (real_allocation.x2 != old_allocation.x2 ||
7756 real_allocation.y2 != old_allocation.y2);
7758 if (origin_changed || child_moved || size_changed)
7759 stage_allocation_changed = TRUE;
7761 stage_allocation_changed = FALSE;
7763 /* If we get an allocation "out of the blue"
7764 * (we did not queue relayout), then we want to
7765 * ignore it. But if we have needs_allocation set,
7766 * we want to guarantee that allocate() virtual
7767 * method is always called, i.e. that queue_relayout()
7768 * always results in an allocate() invocation on
7771 * The optimization here is to avoid re-allocating
7772 * actors that did not queue relayout and were
7775 if (!priv->needs_allocation && !stage_allocation_changed)
7777 CLUTTER_NOTE (LAYOUT, "No allocation needed");
7781 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7782 * clutter_actor_allocate(), it indicates whether the parent has its
7783 * absolute origin moved; when passed in to ClutterActor::allocate()
7784 * virtual method though, it indicates whether the child has its
7785 * absolute origin moved. So we set it when child_moved is TRUE
7788 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7790 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7792 klass = CLUTTER_ACTOR_GET_CLASS (self);
7793 klass->allocate (self, &real_allocation, flags);
7795 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7797 if (stage_allocation_changed)
7798 clutter_actor_queue_redraw (self);
7802 * clutter_actor_set_allocation:
7803 * @self: a #ClutterActor
7804 * @box: a #ClutterActorBox
7805 * @flags: allocation flags
7807 * Stores the allocation of @self as defined by @box.
7809 * This function can only be called from within the implementation of
7810 * the #ClutterActorClass.allocate() virtual function.
7812 * The allocation should have been adjusted to take into account constraints,
7813 * alignment, and margin properties. If you are implementing a #ClutterActor
7814 * subclass that provides its own layout management policy for its children
7815 * instead of using a #ClutterLayoutManager delegate, you should not call
7816 * this function on the children of @self; instead, you should call
7817 * clutter_actor_allocate(), which will adjust the allocation box for
7820 * This function should only be used by subclasses of #ClutterActor
7821 * that wish to store their allocation but cannot chain up to the
7822 * parent's implementation; the default implementation of the
7823 * #ClutterActorClass.allocate() virtual function will call this
7826 * It is important to note that, while chaining up was the recommended
7827 * behaviour for #ClutterActor subclasses prior to the introduction of
7828 * this function, it is recommended to call clutter_actor_set_allocation()
7831 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7832 * to handle the allocation of its children, this function will call
7833 * the clutter_layout_manager_allocate() function only if the
7834 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7835 * expected that the subclass will call clutter_layout_manager_allocate()
7836 * by itself. For instance, the following code:
7840 * my_actor_allocate (ClutterActor *actor,
7841 * const ClutterActorBox *allocation,
7842 * ClutterAllocationFlags flags)
7844 * ClutterActorBox new_alloc;
7845 * ClutterAllocationFlags new_flags;
7847 * adjust_allocation (allocation, &new_alloc);
7849 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7851 * /* this will use the layout manager set on the actor */
7852 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
7856 * is equivalent to this:
7860 * my_actor_allocate (ClutterActor *actor,
7861 * const ClutterActorBox *allocation,
7862 * ClutterAllocationFlags flags)
7864 * ClutterLayoutManager *layout;
7865 * ClutterActorBox new_alloc;
7867 * adjust_allocation (allocation, &new_alloc);
7869 * clutter_actor_set_allocation (actor, &new_alloc, flags);
7871 * layout = clutter_actor_get_layout_manager (actor);
7872 * clutter_layout_manager_allocate (layout,
7873 * CLUTTER_CONTAINER (actor),
7882 clutter_actor_set_allocation (ClutterActor *self,
7883 const ClutterActorBox *box,
7884 ClutterAllocationFlags flags)
7886 ClutterActorPrivate *priv;
7889 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7890 g_return_if_fail (box != NULL);
7892 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7894 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7895 "can only be called from within the implementation of "
7896 "the ClutterActor::allocate() virtual function.");
7902 g_object_freeze_notify (G_OBJECT (self));
7904 changed = clutter_actor_set_allocation_internal (self, box, flags);
7906 /* we allocate our children before we notify changes in our geometry,
7907 * so that people connecting to properties will be able to get valid
7908 * data out of the sub-tree of the scene graph that has this actor at
7911 clutter_actor_maybe_layout_children (self, box, flags);
7914 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
7916 priv->allocation_flags);
7918 g_object_thaw_notify (G_OBJECT (self));
7922 * clutter_actor_set_geometry:
7923 * @self: A #ClutterActor
7924 * @geometry: A #ClutterGeometry
7926 * Sets the actor's fixed position and forces its minimum and natural
7927 * size, in pixels. This means the untransformed actor will have the
7928 * given geometry. This is the same as calling clutter_actor_set_position()
7929 * and clutter_actor_set_size().
7931 * Deprecated: 1.10: Use clutter_actor_set_position() and
7932 * clutter_actor_set_size() instead.
7935 clutter_actor_set_geometry (ClutterActor *self,
7936 const ClutterGeometry *geometry)
7938 g_object_freeze_notify (G_OBJECT (self));
7940 clutter_actor_set_position (self, geometry->x, geometry->y);
7941 clutter_actor_set_size (self, geometry->width, geometry->height);
7943 g_object_thaw_notify (G_OBJECT (self));
7947 * clutter_actor_get_geometry:
7948 * @self: A #ClutterActor
7949 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
7951 * Gets the size and position of an actor relative to its parent
7952 * actor. This is the same as calling clutter_actor_get_position() and
7953 * clutter_actor_get_size(). It tries to "do what you mean" and get the
7954 * requested size and position if the actor's allocation is invalid.
7956 * Deprecated: 1.10: Use clutter_actor_get_position() and
7957 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
7961 clutter_actor_get_geometry (ClutterActor *self,
7962 ClutterGeometry *geometry)
7964 gfloat x, y, width, height;
7966 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7967 g_return_if_fail (geometry != NULL);
7969 clutter_actor_get_position (self, &x, &y);
7970 clutter_actor_get_size (self, &width, &height);
7972 geometry->x = (int) x;
7973 geometry->y = (int) y;
7974 geometry->width = (int) width;
7975 geometry->height = (int) height;
7979 * clutter_actor_set_position:
7980 * @self: A #ClutterActor
7981 * @x: New left position of actor in pixels.
7982 * @y: New top position of actor in pixels.
7984 * Sets the actor's fixed position in pixels relative to any parent
7987 * If a layout manager is in use, this position will override the
7988 * layout manager and force a fixed position.
7991 clutter_actor_set_position (ClutterActor *self,
7995 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7997 g_object_freeze_notify (G_OBJECT (self));
7999 clutter_actor_set_x (self, x);
8000 clutter_actor_set_y (self, y);
8002 g_object_thaw_notify (G_OBJECT (self));
8006 * clutter_actor_get_fixed_position_set:
8007 * @self: A #ClutterActor
8009 * Checks whether an actor has a fixed position set (and will thus be
8010 * unaffected by any layout manager).
8012 * Return value: %TRUE if the fixed position is set on the actor
8017 clutter_actor_get_fixed_position_set (ClutterActor *self)
8019 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8021 return self->priv->position_set;
8025 * clutter_actor_set_fixed_position_set:
8026 * @self: A #ClutterActor
8027 * @is_set: whether to use fixed position
8029 * Sets whether an actor has a fixed position set (and will thus be
8030 * unaffected by any layout manager).
8035 clutter_actor_set_fixed_position_set (ClutterActor *self,
8038 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8040 if (self->priv->position_set == (is_set != FALSE))
8043 self->priv->position_set = is_set != FALSE;
8044 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8046 clutter_actor_queue_relayout (self);
8050 * clutter_actor_move_by:
8051 * @self: A #ClutterActor
8052 * @dx: Distance to move Actor on X axis.
8053 * @dy: Distance to move Actor on Y axis.
8055 * Moves an actor by the specified distance relative to its current
8056 * position in pixels.
8058 * This function modifies the fixed position of an actor and thus removes
8059 * it from any layout management. Another way to move an actor is with an
8060 * anchor point, see clutter_actor_set_anchor_point().
8065 clutter_actor_move_by (ClutterActor *self,
8069 const ClutterLayoutInfo *info;
8072 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8074 info = _clutter_actor_get_layout_info_or_defaults (self);
8078 clutter_actor_set_position (self, x + dx, y + dy);
8082 clutter_actor_set_min_width (ClutterActor *self,
8085 ClutterActorPrivate *priv = self->priv;
8086 ClutterActorBox old = { 0, };
8087 ClutterLayoutInfo *info;
8089 /* if we are setting the size on a top-level actor and the
8090 * backend only supports static top-levels (e.g. framebuffers)
8091 * then we ignore the passed value and we override it with
8092 * the stage implementation's preferred size.
8094 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8095 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8098 info = _clutter_actor_get_layout_info (self);
8100 if (priv->min_width_set && min_width == info->min_width)
8103 g_object_freeze_notify (G_OBJECT (self));
8105 clutter_actor_store_old_geometry (self, &old);
8107 info->min_width = min_width;
8108 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8109 clutter_actor_set_min_width_set (self, TRUE);
8111 clutter_actor_notify_if_geometry_changed (self, &old);
8113 g_object_thaw_notify (G_OBJECT (self));
8115 clutter_actor_queue_relayout (self);
8119 clutter_actor_set_min_height (ClutterActor *self,
8123 ClutterActorPrivate *priv = self->priv;
8124 ClutterActorBox old = { 0, };
8125 ClutterLayoutInfo *info;
8127 /* if we are setting the size on a top-level actor and the
8128 * backend only supports static top-levels (e.g. framebuffers)
8129 * then we ignore the passed value and we override it with
8130 * the stage implementation's preferred size.
8132 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8133 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8136 info = _clutter_actor_get_layout_info (self);
8138 if (priv->min_height_set && min_height == info->min_height)
8141 g_object_freeze_notify (G_OBJECT (self));
8143 clutter_actor_store_old_geometry (self, &old);
8145 info->min_height = min_height;
8146 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8147 clutter_actor_set_min_height_set (self, TRUE);
8149 clutter_actor_notify_if_geometry_changed (self, &old);
8151 g_object_thaw_notify (G_OBJECT (self));
8153 clutter_actor_queue_relayout (self);
8157 clutter_actor_set_natural_width (ClutterActor *self,
8158 gfloat natural_width)
8160 ClutterActorPrivate *priv = self->priv;
8161 ClutterActorBox old = { 0, };
8162 ClutterLayoutInfo *info;
8164 /* if we are setting the size on a top-level actor and the
8165 * backend only supports static top-levels (e.g. framebuffers)
8166 * then we ignore the passed value and we override it with
8167 * the stage implementation's preferred size.
8169 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8170 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8173 info = _clutter_actor_get_layout_info (self);
8175 if (priv->natural_width_set && natural_width == info->natural_width)
8178 g_object_freeze_notify (G_OBJECT (self));
8180 clutter_actor_store_old_geometry (self, &old);
8182 info->natural_width = natural_width;
8183 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8184 clutter_actor_set_natural_width_set (self, TRUE);
8186 clutter_actor_notify_if_geometry_changed (self, &old);
8188 g_object_thaw_notify (G_OBJECT (self));
8190 clutter_actor_queue_relayout (self);
8194 clutter_actor_set_natural_height (ClutterActor *self,
8195 gfloat natural_height)
8197 ClutterActorPrivate *priv = self->priv;
8198 ClutterActorBox old = { 0, };
8199 ClutterLayoutInfo *info;
8201 /* if we are setting the size on a top-level actor and the
8202 * backend only supports static top-levels (e.g. framebuffers)
8203 * then we ignore the passed value and we override it with
8204 * the stage implementation's preferred size.
8206 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8207 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8210 info = _clutter_actor_get_layout_info (self);
8212 if (priv->natural_height_set && natural_height == info->natural_height)
8215 g_object_freeze_notify (G_OBJECT (self));
8217 clutter_actor_store_old_geometry (self, &old);
8219 info->natural_height = natural_height;
8220 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8221 clutter_actor_set_natural_height_set (self, TRUE);
8223 clutter_actor_notify_if_geometry_changed (self, &old);
8225 g_object_thaw_notify (G_OBJECT (self));
8227 clutter_actor_queue_relayout (self);
8231 clutter_actor_set_min_width_set (ClutterActor *self,
8232 gboolean use_min_width)
8234 ClutterActorPrivate *priv = self->priv;
8235 ClutterActorBox old = { 0, };
8237 if (priv->min_width_set == (use_min_width != FALSE))
8240 clutter_actor_store_old_geometry (self, &old);
8242 priv->min_width_set = use_min_width != FALSE;
8243 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8245 clutter_actor_notify_if_geometry_changed (self, &old);
8247 clutter_actor_queue_relayout (self);
8251 clutter_actor_set_min_height_set (ClutterActor *self,
8252 gboolean use_min_height)
8254 ClutterActorPrivate *priv = self->priv;
8255 ClutterActorBox old = { 0, };
8257 if (priv->min_height_set == (use_min_height != FALSE))
8260 clutter_actor_store_old_geometry (self, &old);
8262 priv->min_height_set = use_min_height != FALSE;
8263 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8265 clutter_actor_notify_if_geometry_changed (self, &old);
8267 clutter_actor_queue_relayout (self);
8271 clutter_actor_set_natural_width_set (ClutterActor *self,
8272 gboolean use_natural_width)
8274 ClutterActorPrivate *priv = self->priv;
8275 ClutterActorBox old = { 0, };
8277 if (priv->natural_width_set == (use_natural_width != FALSE))
8280 clutter_actor_store_old_geometry (self, &old);
8282 priv->natural_width_set = use_natural_width != FALSE;
8283 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8285 clutter_actor_notify_if_geometry_changed (self, &old);
8287 clutter_actor_queue_relayout (self);
8291 clutter_actor_set_natural_height_set (ClutterActor *self,
8292 gboolean use_natural_height)
8294 ClutterActorPrivate *priv = self->priv;
8295 ClutterActorBox old = { 0, };
8297 if (priv->natural_height_set == (use_natural_height != FALSE))
8300 clutter_actor_store_old_geometry (self, &old);
8302 priv->natural_height_set = use_natural_height != FALSE;
8303 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8305 clutter_actor_notify_if_geometry_changed (self, &old);
8307 clutter_actor_queue_relayout (self);
8311 * clutter_actor_set_request_mode:
8312 * @self: a #ClutterActor
8313 * @mode: the request mode
8315 * Sets the geometry request mode of @self.
8317 * The @mode determines the order for invoking
8318 * clutter_actor_get_preferred_width() and
8319 * clutter_actor_get_preferred_height()
8324 clutter_actor_set_request_mode (ClutterActor *self,
8325 ClutterRequestMode mode)
8327 ClutterActorPrivate *priv;
8329 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8333 if (priv->request_mode == mode)
8336 priv->request_mode = mode;
8338 priv->needs_width_request = TRUE;
8339 priv->needs_height_request = TRUE;
8341 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8343 clutter_actor_queue_relayout (self);
8347 * clutter_actor_get_request_mode:
8348 * @self: a #ClutterActor
8350 * Retrieves the geometry request mode of @self
8352 * Return value: the request mode for the actor
8357 clutter_actor_get_request_mode (ClutterActor *self)
8359 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8360 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8362 return self->priv->request_mode;
8365 /* variant of set_width() without checks and without notification
8366 * freeze+thaw, for internal usage only
8369 clutter_actor_set_width_internal (ClutterActor *self,
8374 /* the Stage will use the :min-width to control the minimum
8375 * width to be resized to, so we should not be setting it
8376 * along with the :natural-width
8378 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8379 clutter_actor_set_min_width (self, width);
8381 clutter_actor_set_natural_width (self, width);
8385 /* we only unset the :natural-width for the Stage */
8386 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8387 clutter_actor_set_min_width_set (self, FALSE);
8389 clutter_actor_set_natural_width_set (self, FALSE);
8393 /* variant of set_height() without checks and without notification
8394 * freeze+thaw, for internal usage only
8397 clutter_actor_set_height_internal (ClutterActor *self,
8402 /* see the comment above in set_width_internal() */
8403 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8404 clutter_actor_set_min_height (self, height);
8406 clutter_actor_set_natural_height (self, height);
8410 /* see the comment above in set_width_internal() */
8411 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8412 clutter_actor_set_min_height_set (self, FALSE);
8414 clutter_actor_set_natural_height_set (self, FALSE);
8419 * clutter_actor_set_size:
8420 * @self: A #ClutterActor
8421 * @width: New width of actor in pixels, or -1
8422 * @height: New height of actor in pixels, or -1
8424 * Sets the actor's size request in pixels. This overrides any
8425 * "normal" size request the actor would have. For example
8426 * a text actor might normally request the size of the text;
8427 * this function would force a specific size instead.
8429 * If @width and/or @height are -1 the actor will use its
8430 * "normal" size request instead of overriding it, i.e.
8431 * you can "unset" the size with -1.
8433 * This function sets or unsets both the minimum and natural size.
8436 clutter_actor_set_size (ClutterActor *self,
8440 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8442 g_object_freeze_notify (G_OBJECT (self));
8444 clutter_actor_set_width_internal (self, width);
8445 clutter_actor_set_height_internal (self, height);
8447 g_object_thaw_notify (G_OBJECT (self));
8451 * clutter_actor_get_size:
8452 * @self: A #ClutterActor
8453 * @width: (out) (allow-none): return location for the width, or %NULL.
8454 * @height: (out) (allow-none): return location for the height, or %NULL.
8456 * This function tries to "do what you mean" and return
8457 * the size an actor will have. If the actor has a valid
8458 * allocation, the allocation will be returned; otherwise,
8459 * the actors natural size request will be returned.
8461 * If you care whether you get the request vs. the allocation, you
8462 * should probably call a different function like
8463 * clutter_actor_get_allocation_box() or
8464 * clutter_actor_get_preferred_width().
8469 clutter_actor_get_size (ClutterActor *self,
8473 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8476 *width = clutter_actor_get_width (self);
8479 *height = clutter_actor_get_height (self);
8483 * clutter_actor_get_position:
8484 * @self: a #ClutterActor
8485 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8486 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8488 * This function tries to "do what you mean" and tell you where the
8489 * actor is, prior to any transformations. Retrieves the fixed
8490 * position of an actor in pixels, if one has been set; otherwise, if
8491 * the allocation is valid, returns the actor's allocated position;
8492 * otherwise, returns 0,0.
8494 * The returned position is in pixels.
8499 clutter_actor_get_position (ClutterActor *self,
8503 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8506 *x = clutter_actor_get_x (self);
8509 *y = clutter_actor_get_y (self);
8513 * clutter_actor_get_transformed_position:
8514 * @self: A #ClutterActor
8515 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8516 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8518 * Gets the absolute position of an actor, in pixels relative to the stage.
8523 clutter_actor_get_transformed_position (ClutterActor *self,
8530 v1.x = v1.y = v1.z = 0;
8531 clutter_actor_apply_transform_to_point (self, &v1, &v2);
8541 * clutter_actor_get_transformed_size:
8542 * @self: A #ClutterActor
8543 * @width: (out) (allow-none): return location for the width, or %NULL
8544 * @height: (out) (allow-none): return location for the height, or %NULL
8546 * Gets the absolute size of an actor in pixels, taking into account the
8549 * If the actor has a valid allocation, the allocated size will be used.
8550 * If the actor has not a valid allocation then the preferred size will
8551 * be transformed and returned.
8553 * If you want the transformed allocation, see
8554 * clutter_actor_get_abs_allocation_vertices() instead.
8556 * <note>When the actor (or one of its ancestors) is rotated around the
8557 * X or Y axis, it no longer appears as on the stage as a rectangle, but
8558 * as a generic quadrangle; in that case this function returns the size
8559 * of the smallest rectangle that encapsulates the entire quad. Please
8560 * note that in this case no assumptions can be made about the relative
8561 * position of this envelope to the absolute position of the actor, as
8562 * returned by clutter_actor_get_transformed_position(); if you need this
8563 * information, you need to use clutter_actor_get_abs_allocation_vertices()
8564 * to get the coords of the actual quadrangle.</note>
8569 clutter_actor_get_transformed_size (ClutterActor *self,
8573 ClutterActorPrivate *priv;
8575 gfloat x_min, x_max, y_min, y_max;
8578 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8582 /* if the actor hasn't been allocated yet, get the preferred
8583 * size and transform that
8585 if (priv->needs_allocation)
8587 gfloat natural_width, natural_height;
8588 ClutterActorBox box;
8590 /* Make a fake allocation to transform.
8592 * NB: _clutter_actor_transform_and_project_box expects a box in
8593 * the actor's coordinate space... */
8598 natural_width = natural_height = 0;
8599 clutter_actor_get_preferred_size (self, NULL, NULL,
8603 box.x2 = natural_width;
8604 box.y2 = natural_height;
8606 _clutter_actor_transform_and_project_box (self, &box, v);
8609 clutter_actor_get_abs_allocation_vertices (self, v);
8611 x_min = x_max = v[0].x;
8612 y_min = y_max = v[0].y;
8614 for (i = 1; i < G_N_ELEMENTS (v); ++i)
8630 *width = x_max - x_min;
8633 *height = y_max - y_min;
8637 * clutter_actor_get_width:
8638 * @self: A #ClutterActor
8640 * Retrieves the width of a #ClutterActor.
8642 * If the actor has a valid allocation, this function will return the
8643 * width of the allocated area given to the actor.
8645 * If the actor does not have a valid allocation, this function will
8646 * return the actor's natural width, that is the preferred width of
8649 * If you care whether you get the preferred width or the width that
8650 * has been assigned to the actor, you should probably call a different
8651 * function like clutter_actor_get_allocation_box() to retrieve the
8652 * allocated size or clutter_actor_get_preferred_width() to retrieve the
8655 * If an actor has a fixed width, for instance a width that has been
8656 * assigned using clutter_actor_set_width(), the width returned will
8657 * be the same value.
8659 * Return value: the width of the actor, in pixels
8662 clutter_actor_get_width (ClutterActor *self)
8664 ClutterActorPrivate *priv;
8666 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8670 if (priv->needs_allocation)
8672 gfloat natural_width = 0;
8674 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8675 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8678 gfloat natural_height = 0;
8680 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8681 clutter_actor_get_preferred_width (self, natural_height,
8686 return natural_width;
8689 return priv->allocation.x2 - priv->allocation.x1;
8693 * clutter_actor_get_height:
8694 * @self: A #ClutterActor
8696 * Retrieves the height of a #ClutterActor.
8698 * If the actor has a valid allocation, this function will return the
8699 * height of the allocated area given to the actor.
8701 * If the actor does not have a valid allocation, this function will
8702 * return the actor's natural height, that is the preferred height of
8705 * If you care whether you get the preferred height or the height that
8706 * has been assigned to the actor, you should probably call a different
8707 * function like clutter_actor_get_allocation_box() to retrieve the
8708 * allocated size or clutter_actor_get_preferred_height() to retrieve the
8711 * If an actor has a fixed height, for instance a height that has been
8712 * assigned using clutter_actor_set_height(), the height returned will
8713 * be the same value.
8715 * Return value: the height of the actor, in pixels
8718 clutter_actor_get_height (ClutterActor *self)
8720 ClutterActorPrivate *priv;
8722 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8726 if (priv->needs_allocation)
8728 gfloat natural_height = 0;
8730 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8732 gfloat natural_width = 0;
8734 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8735 clutter_actor_get_preferred_height (self, natural_width,
8736 NULL, &natural_height);
8739 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8741 return natural_height;
8744 return priv->allocation.y2 - priv->allocation.y1;
8748 * clutter_actor_set_width:
8749 * @self: A #ClutterActor
8750 * @width: Requested new width for the actor, in pixels, or -1
8752 * Forces a width on an actor, causing the actor's preferred width
8753 * and height (if any) to be ignored.
8755 * If @width is -1 the actor will use its preferred width request
8756 * instead of overriding it, i.e. you can "unset" the width with -1.
8758 * This function sets both the minimum and natural size of the actor.
8763 clutter_actor_set_width (ClutterActor *self,
8766 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8768 g_object_freeze_notify (G_OBJECT (self));
8770 clutter_actor_set_width_internal (self, width);
8772 g_object_thaw_notify (G_OBJECT (self));
8776 * clutter_actor_set_height:
8777 * @self: A #ClutterActor
8778 * @height: Requested new height for the actor, in pixels, or -1
8780 * Forces a height on an actor, causing the actor's preferred width
8781 * and height (if any) to be ignored.
8783 * If @height is -1 the actor will use its preferred height instead of
8784 * overriding it, i.e. you can "unset" the height with -1.
8786 * This function sets both the minimum and natural size of the actor.
8791 clutter_actor_set_height (ClutterActor *self,
8794 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8796 g_object_freeze_notify (G_OBJECT (self));
8798 clutter_actor_set_height_internal (self, height);
8800 g_object_thaw_notify (G_OBJECT (self));
8804 * clutter_actor_set_x:
8805 * @self: a #ClutterActor
8806 * @x: the actor's position on the X axis
8808 * Sets the actor's X coordinate, relative to its parent, in pixels.
8810 * Overrides any layout manager and forces a fixed position for
8816 clutter_actor_set_x (ClutterActor *self,
8819 ClutterActorBox old = { 0, };
8820 ClutterActorPrivate *priv;
8821 ClutterLayoutInfo *info;
8823 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8827 info = _clutter_actor_get_layout_info (self);
8829 if (priv->position_set && info->fixed_x == x)
8832 clutter_actor_store_old_geometry (self, &old);
8835 clutter_actor_set_fixed_position_set (self, TRUE);
8837 clutter_actor_notify_if_geometry_changed (self, &old);
8839 clutter_actor_queue_relayout (self);
8843 * clutter_actor_set_y:
8844 * @self: a #ClutterActor
8845 * @y: the actor's position on the Y axis
8847 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8849 * Overrides any layout manager and forces a fixed position for
8855 clutter_actor_set_y (ClutterActor *self,
8858 ClutterActorBox old = { 0, };
8859 ClutterActorPrivate *priv;
8860 ClutterLayoutInfo *info;
8862 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8866 info = _clutter_actor_get_layout_info (self);
8868 if (priv->position_set && info->fixed_y == y)
8871 clutter_actor_store_old_geometry (self, &old);
8874 clutter_actor_set_fixed_position_set (self, TRUE);
8876 clutter_actor_notify_if_geometry_changed (self, &old);
8878 clutter_actor_queue_relayout (self);
8882 * clutter_actor_get_x:
8883 * @self: A #ClutterActor
8885 * Retrieves the X coordinate of a #ClutterActor.
8887 * This function tries to "do what you mean", by returning the
8888 * correct value depending on the actor's state.
8890 * If the actor has a valid allocation, this function will return
8891 * the X coordinate of the origin of the allocation box.
8893 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8894 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8895 * function will return that coordinate.
8897 * If both the allocation and a fixed position are missing, this function
8900 * Return value: the X coordinate, in pixels, ignoring any
8901 * transformation (i.e. scaling, rotation)
8904 clutter_actor_get_x (ClutterActor *self)
8906 ClutterActorPrivate *priv;
8908 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8912 if (priv->needs_allocation)
8914 if (priv->position_set)
8916 const ClutterLayoutInfo *info;
8918 info = _clutter_actor_get_layout_info_or_defaults (self);
8920 return info->fixed_x;
8926 return priv->allocation.x1;
8930 * clutter_actor_get_y:
8931 * @self: A #ClutterActor
8933 * Retrieves the Y coordinate of a #ClutterActor.
8935 * This function tries to "do what you mean", by returning the
8936 * correct value depending on the actor's state.
8938 * If the actor has a valid allocation, this function will return
8939 * the Y coordinate of the origin of the allocation box.
8941 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
8942 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8943 * function will return that coordinate.
8945 * If both the allocation and a fixed position are missing, this function
8948 * Return value: the Y coordinate, in pixels, ignoring any
8949 * transformation (i.e. scaling, rotation)
8952 clutter_actor_get_y (ClutterActor *self)
8954 ClutterActorPrivate *priv;
8956 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8960 if (priv->needs_allocation)
8962 if (priv->position_set)
8964 const ClutterLayoutInfo *info;
8966 info = _clutter_actor_get_layout_info_or_defaults (self);
8968 return info->fixed_y;
8974 return priv->allocation.y1;
8978 * clutter_actor_set_scale:
8979 * @self: A #ClutterActor
8980 * @scale_x: double factor to scale actor by horizontally.
8981 * @scale_y: double factor to scale actor by vertically.
8983 * Scales an actor with the given factors. The scaling is relative to
8984 * the scale center and the anchor point. The scale center is
8985 * unchanged by this function and defaults to 0,0.
8990 clutter_actor_set_scale (ClutterActor *self,
8994 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8996 g_object_freeze_notify (G_OBJECT (self));
8998 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
8999 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9001 g_object_thaw_notify (G_OBJECT (self));
9005 * clutter_actor_set_scale_full:
9006 * @self: A #ClutterActor
9007 * @scale_x: double factor to scale actor by horizontally.
9008 * @scale_y: double factor to scale actor by vertically.
9009 * @center_x: X coordinate of the center of the scale.
9010 * @center_y: Y coordinate of the center of the scale
9012 * Scales an actor with the given factors around the given center
9013 * point. The center point is specified in pixels relative to the
9014 * anchor point (usually the top left corner of the actor).
9019 clutter_actor_set_scale_full (ClutterActor *self,
9025 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9027 g_object_freeze_notify (G_OBJECT (self));
9029 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9030 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9031 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9032 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9034 g_object_thaw_notify (G_OBJECT (self));
9038 * clutter_actor_set_scale_with_gravity:
9039 * @self: A #ClutterActor
9040 * @scale_x: double factor to scale actor by horizontally.
9041 * @scale_y: double factor to scale actor by vertically.
9042 * @gravity: the location of the scale center expressed as a compass
9045 * Scales an actor with the given factors around the given
9046 * center point. The center point is specified as one of the compass
9047 * directions in #ClutterGravity. For example, setting it to north
9048 * will cause the top of the actor to remain unchanged and the rest of
9049 * the actor to expand left, right and downwards.
9054 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9057 ClutterGravity gravity)
9059 ClutterTransformInfo *info;
9062 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9064 obj = G_OBJECT (self);
9066 g_object_freeze_notify (obj);
9068 info = _clutter_actor_get_transform_info (self);
9069 info->scale_x = scale_x;
9070 info->scale_y = scale_y;
9072 if (gravity == CLUTTER_GRAVITY_NONE)
9073 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9075 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9077 self->priv->transform_valid = FALSE;
9079 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9080 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9081 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9082 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9083 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9085 clutter_actor_queue_redraw (self);
9087 g_object_thaw_notify (obj);
9091 * clutter_actor_get_scale:
9092 * @self: A #ClutterActor
9093 * @scale_x: (out) (allow-none): Location to store horizonal
9094 * scale factor, or %NULL.
9095 * @scale_y: (out) (allow-none): Location to store vertical
9096 * scale factor, or %NULL.
9098 * Retrieves an actors scale factors.
9103 clutter_actor_get_scale (ClutterActor *self,
9107 const ClutterTransformInfo *info;
9109 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9111 info = _clutter_actor_get_transform_info_or_defaults (self);
9114 *scale_x = info->scale_x;
9117 *scale_y = info->scale_y;
9121 * clutter_actor_get_scale_center:
9122 * @self: A #ClutterActor
9123 * @center_x: (out) (allow-none): Location to store the X position
9124 * of the scale center, or %NULL.
9125 * @center_y: (out) (allow-none): Location to store the Y position
9126 * of the scale center, or %NULL.
9128 * Retrieves the scale center coordinate in pixels relative to the top
9129 * left corner of the actor. If the scale center was specified using a
9130 * #ClutterGravity this will calculate the pixel offset using the
9131 * current size of the actor.
9136 clutter_actor_get_scale_center (ClutterActor *self,
9140 const ClutterTransformInfo *info;
9142 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9144 info = _clutter_actor_get_transform_info_or_defaults (self);
9146 clutter_anchor_coord_get_units (self, &info->scale_center,
9153 * clutter_actor_get_scale_gravity:
9154 * @self: A #ClutterActor
9156 * Retrieves the scale center as a compass direction. If the scale
9157 * center was specified in pixels or units this will return
9158 * %CLUTTER_GRAVITY_NONE.
9160 * Return value: the scale gravity
9165 clutter_actor_get_scale_gravity (ClutterActor *self)
9167 const ClutterTransformInfo *info;
9169 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9171 info = _clutter_actor_get_transform_info_or_defaults (self);
9173 return clutter_anchor_coord_get_gravity (&info->scale_center);
9177 * clutter_actor_set_opacity:
9178 * @self: A #ClutterActor
9179 * @opacity: New opacity value for the actor.
9181 * Sets the actor's opacity, with zero being completely transparent and
9182 * 255 (0xff) being fully opaque.
9185 clutter_actor_set_opacity (ClutterActor *self,
9188 ClutterActorPrivate *priv;
9190 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9194 if (priv->opacity != opacity)
9196 priv->opacity = opacity;
9198 /* Queue a redraw from the flatten effect so that it can use
9199 its cached image if available instead of having to redraw the
9200 actual actor. If it doesn't end up using the FBO then the
9201 effect is still able to continue the paint anyway. If there
9202 is no flatten effect yet then this is equivalent to queueing
9204 _clutter_actor_queue_redraw_full (self,
9207 priv->flatten_effect);
9209 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9214 * clutter_actor_get_paint_opacity_internal:
9215 * @self: a #ClutterActor
9217 * Retrieves the absolute opacity of the actor, as it appears on the stage
9219 * This function does not do type checks
9221 * Return value: the absolute opacity of the actor
9224 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9226 ClutterActorPrivate *priv = self->priv;
9227 ClutterActor *parent;
9229 /* override the top-level opacity to always be 255; even in
9230 * case of ClutterStage:use-alpha being TRUE we want the rest
9231 * of the scene to be painted
9233 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9236 if (priv->opacity_override >= 0)
9237 return priv->opacity_override;
9239 parent = priv->parent;
9241 /* Factor in the actual actors opacity with parents */
9244 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9246 if (opacity != 0xff)
9247 return (opacity * priv->opacity) / 0xff;
9250 return priv->opacity;
9255 * clutter_actor_get_paint_opacity:
9256 * @self: A #ClutterActor
9258 * Retrieves the absolute opacity of the actor, as it appears on the stage.
9260 * This function traverses the hierarchy chain and composites the opacity of
9261 * the actor with that of its parents.
9263 * This function is intended for subclasses to use in the paint virtual
9264 * function, to paint themselves with the correct opacity.
9266 * Return value: The actor opacity value.
9271 clutter_actor_get_paint_opacity (ClutterActor *self)
9273 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9275 return clutter_actor_get_paint_opacity_internal (self);
9279 * clutter_actor_get_opacity:
9280 * @self: a #ClutterActor
9282 * Retrieves the opacity value of an actor, as set by
9283 * clutter_actor_set_opacity().
9285 * For retrieving the absolute opacity of the actor inside a paint
9286 * virtual function, see clutter_actor_get_paint_opacity().
9288 * Return value: the opacity of the actor
9291 clutter_actor_get_opacity (ClutterActor *self)
9293 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9295 return self->priv->opacity;
9299 * clutter_actor_set_offscreen_redirect:
9300 * @self: A #ClutterActor
9301 * @redirect: New offscreen redirect flags for the actor.
9303 * Defines the circumstances where the actor should be redirected into
9304 * an offscreen image. The offscreen image is used to flatten the
9305 * actor into a single image while painting for two main reasons.
9306 * Firstly, when the actor is painted a second time without any of its
9307 * contents changing it can simply repaint the cached image without
9308 * descending further down the actor hierarchy. Secondly, it will make
9309 * the opacity look correct even if there are overlapping primitives
9312 * Caching the actor could in some cases be a performance win and in
9313 * some cases be a performance lose so it is important to determine
9314 * which value is right for an actor before modifying this value. For
9315 * example, there is never any reason to flatten an actor that is just
9316 * a single texture (such as a #ClutterTexture) because it is
9317 * effectively already cached in an image so the offscreen would be
9318 * redundant. Also if the actor contains primitives that are far apart
9319 * with a large transparent area in the middle (such as a large
9320 * CluterGroup with a small actor in the top left and a small actor in
9321 * the bottom right) then the cached image will contain the entire
9322 * image of the large area and the paint will waste time blending all
9323 * of the transparent pixels in the middle.
9325 * The default method of implementing opacity on a container simply
9326 * forwards on the opacity to all of the children. If the children are
9327 * overlapping then it will appear as if they are two separate glassy
9328 * objects and there will be a break in the color where they
9329 * overlap. By redirecting to an offscreen buffer it will be as if the
9330 * two opaque objects are combined into one and then made transparent
9331 * which is usually what is expected.
9333 * The image below demonstrates the difference between redirecting and
9334 * not. The image shows two Clutter groups, each containing a red and
9335 * a green rectangle which overlap. The opacity on the group is set to
9336 * 128 (which is 50%). When the offscreen redirect is not used, the
9337 * red rectangle can be seen through the blue rectangle as if the two
9338 * rectangles were separately transparent. When the redirect is used
9339 * the group as a whole is transparent instead so the red rectangle is
9340 * not visible where they overlap.
9342 * <figure id="offscreen-redirect">
9343 * <title>Sample of using an offscreen redirect for transparency</title>
9344 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
9347 * The default value for this property is 0, so we effectively will
9348 * never redirect an actor offscreen by default. This means that there
9349 * are times that transparent actors may look glassy as described
9350 * above. The reason this is the default is because there is a
9351 * performance trade off between quality and performance here. In many
9352 * cases the default form of glassy opacity looks good enough, but if
9353 * it's not you will need to set the
9354 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9355 * redirection for opacity.
9357 * Custom actors that don't contain any overlapping primitives are
9358 * recommended to override the has_overlaps() virtual to return %FALSE
9359 * for maximum efficiency.
9364 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9365 ClutterOffscreenRedirect redirect)
9367 ClutterActorPrivate *priv;
9369 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9373 if (priv->offscreen_redirect != redirect)
9375 priv->offscreen_redirect = redirect;
9377 /* Queue a redraw from the effect so that it can use its cached
9378 image if available instead of having to redraw the actual
9379 actor. If it doesn't end up using the FBO then the effect is
9380 still able to continue the paint anyway. If there is no
9381 effect then this is equivalent to queuing a full redraw */
9382 _clutter_actor_queue_redraw_full (self,
9385 priv->flatten_effect);
9387 g_object_notify_by_pspec (G_OBJECT (self),
9388 obj_props[PROP_OFFSCREEN_REDIRECT]);
9393 * clutter_actor_get_offscreen_redirect:
9394 * @self: a #ClutterActor
9396 * Retrieves whether to redirect the actor to an offscreen buffer, as
9397 * set by clutter_actor_set_offscreen_redirect().
9399 * Return value: the value of the offscreen-redirect property of the actor
9403 ClutterOffscreenRedirect
9404 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9406 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9408 return self->priv->offscreen_redirect;
9412 * clutter_actor_set_name:
9413 * @self: A #ClutterActor
9414 * @name: Textual tag to apply to actor
9416 * Sets the given name to @self. The name can be used to identify
9420 clutter_actor_set_name (ClutterActor *self,
9423 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9425 g_free (self->priv->name);
9426 self->priv->name = g_strdup (name);
9428 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9432 * clutter_actor_get_name:
9433 * @self: A #ClutterActor
9435 * Retrieves the name of @self.
9437 * Return value: the name of the actor, or %NULL. The returned string is
9438 * owned by the actor and should not be modified or freed.
9441 clutter_actor_get_name (ClutterActor *self)
9443 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9445 return self->priv->name;
9449 * clutter_actor_get_gid:
9450 * @self: A #ClutterActor
9452 * Retrieves the unique id for @self.
9454 * Return value: Globally unique value for this object instance.
9458 * Deprecated: 1.8: The id is not used any longer.
9461 clutter_actor_get_gid (ClutterActor *self)
9463 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9465 return self->priv->id;
9469 * clutter_actor_set_depth:
9470 * @self: a #ClutterActor
9473 * Sets the Z coordinate of @self to @depth.
9475 * The unit used by @depth is dependant on the perspective setup. See
9476 * also clutter_stage_set_perspective().
9479 clutter_actor_set_depth (ClutterActor *self,
9482 ClutterActorPrivate *priv;
9484 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9488 if (priv->z != depth)
9490 /* Sets Z value - XXX 2.0: should we invert? */
9493 priv->transform_valid = FALSE;
9495 /* FIXME - remove this crap; sadly, there are still containers
9496 * in Clutter that depend on this utter brain damage
9498 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9500 clutter_actor_queue_redraw (self);
9502 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9507 * clutter_actor_get_depth:
9508 * @self: a #ClutterActor
9510 * Retrieves the depth of @self.
9512 * Return value: the depth of the actor
9515 clutter_actor_get_depth (ClutterActor *self)
9517 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9519 return self->priv->z;
9523 * clutter_actor_set_rotation:
9524 * @self: a #ClutterActor
9525 * @axis: the axis of rotation
9526 * @angle: the angle of rotation
9527 * @x: X coordinate of the rotation center
9528 * @y: Y coordinate of the rotation center
9529 * @z: Z coordinate of the rotation center
9531 * Sets the rotation angle of @self around the given axis.
9533 * The rotation center coordinates used depend on the value of @axis:
9535 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9536 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9537 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9540 * The rotation coordinates are relative to the anchor point of the
9541 * actor, set using clutter_actor_set_anchor_point(). If no anchor
9542 * point is set, the upper left corner is assumed as the origin.
9547 clutter_actor_set_rotation (ClutterActor *self,
9548 ClutterRotateAxis axis,
9556 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9562 g_object_freeze_notify (G_OBJECT (self));
9564 clutter_actor_set_rotation_angle_internal (self, axis, angle);
9565 clutter_actor_set_rotation_center_internal (self, axis, &v);
9567 g_object_thaw_notify (G_OBJECT (self));
9571 * clutter_actor_set_z_rotation_from_gravity:
9572 * @self: a #ClutterActor
9573 * @angle: the angle of rotation
9574 * @gravity: the center point of the rotation
9576 * Sets the rotation angle of @self around the Z axis using the center
9577 * point specified as a compass point. For example to rotate such that
9578 * the center of the actor remains static you can use
9579 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9580 * will move accordingly.
9585 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
9587 ClutterGravity gravity)
9589 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9591 if (gravity == CLUTTER_GRAVITY_NONE)
9592 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9595 GObject *obj = G_OBJECT (self);
9596 ClutterTransformInfo *info;
9598 info = _clutter_actor_get_transform_info (self);
9600 g_object_freeze_notify (obj);
9602 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9604 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9605 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9606 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9608 g_object_thaw_notify (obj);
9613 * clutter_actor_get_rotation:
9614 * @self: a #ClutterActor
9615 * @axis: the axis of rotation
9616 * @x: (out): return value for the X coordinate of the center of rotation
9617 * @y: (out): return value for the Y coordinate of the center of rotation
9618 * @z: (out): return value for the Z coordinate of the center of rotation
9620 * Retrieves the angle and center of rotation on the given axis,
9621 * set using clutter_actor_set_rotation().
9623 * Return value: the angle of rotation
9628 clutter_actor_get_rotation (ClutterActor *self,
9629 ClutterRotateAxis axis,
9634 const ClutterTransformInfo *info;
9635 const AnchorCoord *anchor_coord;
9638 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9640 info = _clutter_actor_get_transform_info_or_defaults (self);
9644 case CLUTTER_X_AXIS:
9645 anchor_coord = &info->rx_center;
9646 retval = info->rx_angle;
9649 case CLUTTER_Y_AXIS:
9650 anchor_coord = &info->ry_center;
9651 retval = info->ry_angle;
9654 case CLUTTER_Z_AXIS:
9655 anchor_coord = &info->rz_center;
9656 retval = info->rz_angle;
9660 anchor_coord = NULL;
9665 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9671 * clutter_actor_get_z_rotation_gravity:
9672 * @self: A #ClutterActor
9674 * Retrieves the center for the rotation around the Z axis as a
9675 * compass direction. If the center was specified in pixels or units
9676 * this will return %CLUTTER_GRAVITY_NONE.
9678 * Return value: the Z rotation center
9683 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9685 const ClutterTransformInfo *info;
9687 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9689 info = _clutter_actor_get_transform_info_or_defaults (self);
9691 return clutter_anchor_coord_get_gravity (&info->rz_center);
9695 * clutter_actor_set_clip:
9696 * @self: A #ClutterActor
9697 * @xoff: X offset of the clip rectangle
9698 * @yoff: Y offset of the clip rectangle
9699 * @width: Width of the clip rectangle
9700 * @height: Height of the clip rectangle
9702 * Sets clip area for @self. The clip area is always computed from the
9703 * upper left corner of the actor, even if the anchor point is set
9709 clutter_actor_set_clip (ClutterActor *self,
9715 ClutterActorPrivate *priv;
9717 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9721 if (priv->has_clip &&
9722 priv->clip.x == xoff &&
9723 priv->clip.y == yoff &&
9724 priv->clip.width == width &&
9725 priv->clip.height == height)
9728 priv->clip.x = xoff;
9729 priv->clip.y = yoff;
9730 priv->clip.width = width;
9731 priv->clip.height = height;
9733 priv->has_clip = TRUE;
9735 clutter_actor_queue_redraw (self);
9737 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9738 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9742 * clutter_actor_remove_clip:
9743 * @self: A #ClutterActor
9745 * Removes clip area from @self.
9748 clutter_actor_remove_clip (ClutterActor *self)
9750 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9752 if (!self->priv->has_clip)
9755 self->priv->has_clip = FALSE;
9757 clutter_actor_queue_redraw (self);
9759 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9763 * clutter_actor_has_clip:
9764 * @self: a #ClutterActor
9766 * Determines whether the actor has a clip area set or not.
9768 * Return value: %TRUE if the actor has a clip area set.
9773 clutter_actor_has_clip (ClutterActor *self)
9775 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9777 return self->priv->has_clip;
9781 * clutter_actor_get_clip:
9782 * @self: a #ClutterActor
9783 * @xoff: (out) (allow-none): return location for the X offset of
9784 * the clip rectangle, or %NULL
9785 * @yoff: (out) (allow-none): return location for the Y offset of
9786 * the clip rectangle, or %NULL
9787 * @width: (out) (allow-none): return location for the width of
9788 * the clip rectangle, or %NULL
9789 * @height: (out) (allow-none): return location for the height of
9790 * the clip rectangle, or %NULL
9792 * Gets the clip area for @self, if any is set
9797 clutter_actor_get_clip (ClutterActor *self,
9803 ClutterActorPrivate *priv;
9805 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9809 if (!priv->has_clip)
9813 *xoff = priv->clip.x;
9816 *yoff = priv->clip.y;
9819 *width = priv->clip.width;
9822 *height = priv->clip.height;
9826 * clutter_actor_get_children:
9827 * @self: a #ClutterActor
9829 * Retrieves the list of children of @self.
9831 * Return value: (transfer container) (element-type ClutterActor): A newly
9832 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9838 clutter_actor_get_children (ClutterActor *self)
9843 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9845 /* we walk the list backward so that we can use prepend(),
9848 for (iter = self->priv->last_child, res = NULL;
9850 iter = iter->priv->prev_sibling)
9852 res = g_list_prepend (res, iter);
9859 * insert_child_at_depth:
9860 * @self: a #ClutterActor
9861 * @child: a #ClutterActor
9863 * Inserts @child inside the list of children held by @self, using
9864 * the depth as the insertion criteria.
9866 * This sadly makes the insertion not O(1), but we can keep the
9867 * list sorted so that the painters algorithm we use for painting
9868 * the children will work correctly.
9871 insert_child_at_depth (ClutterActor *self,
9872 ClutterActor *child,
9873 gpointer dummy G_GNUC_UNUSED)
9877 child->priv->parent = self;
9879 /* special-case the first child */
9880 if (self->priv->n_children == 0)
9882 self->priv->first_child = child;
9883 self->priv->last_child = child;
9885 child->priv->next_sibling = NULL;
9886 child->priv->prev_sibling = NULL;
9891 /* Find the right place to insert the child so that it will still be
9892 sorted and the child will be after all of the actors at the same
9894 for (iter = self->priv->first_child;
9896 iter = iter->priv->next_sibling)
9898 if (iter->priv->z > child->priv->z)
9904 ClutterActor *tmp = iter->priv->prev_sibling;
9907 tmp->priv->next_sibling = child;
9909 /* Insert the node before the found one */
9910 child->priv->prev_sibling = iter->priv->prev_sibling;
9911 child->priv->next_sibling = iter;
9912 iter->priv->prev_sibling = child;
9916 ClutterActor *tmp = self->priv->last_child;
9919 tmp->priv->next_sibling = child;
9921 /* insert the node at the end of the list */
9922 child->priv->prev_sibling = self->priv->last_child;
9923 child->priv->next_sibling = NULL;
9926 if (child->priv->prev_sibling == NULL)
9927 self->priv->first_child = child;
9929 if (child->priv->next_sibling == NULL)
9930 self->priv->last_child = child;
9934 insert_child_at_index (ClutterActor *self,
9935 ClutterActor *child,
9938 gint index_ = GPOINTER_TO_INT (data_);
9940 child->priv->parent = self;
9944 ClutterActor *tmp = self->priv->first_child;
9947 tmp->priv->prev_sibling = child;
9949 child->priv->prev_sibling = NULL;
9950 child->priv->next_sibling = tmp;
9952 else if (index_ < 0 || index_ >= self->priv->n_children)
9954 ClutterActor *tmp = self->priv->last_child;
9957 tmp->priv->next_sibling = child;
9959 child->priv->prev_sibling = tmp;
9960 child->priv->next_sibling = NULL;
9967 for (iter = self->priv->first_child, i = 0;
9969 iter = iter->priv->next_sibling, i += 1)
9973 ClutterActor *tmp = iter->priv->prev_sibling;
9975 child->priv->prev_sibling = tmp;
9976 child->priv->next_sibling = iter;
9978 iter->priv->prev_sibling = child;
9981 tmp->priv->next_sibling = child;
9988 if (child->priv->prev_sibling == NULL)
9989 self->priv->first_child = child;
9991 if (child->priv->next_sibling == NULL)
9992 self->priv->last_child = child;
9996 insert_child_above (ClutterActor *self,
9997 ClutterActor *child,
10000 ClutterActor *sibling = data;
10002 child->priv->parent = self;
10004 if (sibling == NULL)
10005 sibling = self->priv->last_child;
10007 child->priv->prev_sibling = sibling;
10009 if (sibling != NULL)
10011 ClutterActor *tmp = sibling->priv->next_sibling;
10013 child->priv->next_sibling = tmp;
10016 tmp->priv->prev_sibling = child;
10018 sibling->priv->next_sibling = child;
10021 child->priv->next_sibling = NULL;
10023 if (child->priv->prev_sibling == NULL)
10024 self->priv->first_child = child;
10026 if (child->priv->next_sibling == NULL)
10027 self->priv->last_child = child;
10031 insert_child_below (ClutterActor *self,
10032 ClutterActor *child,
10035 ClutterActor *sibling = data;
10037 child->priv->parent = self;
10039 if (sibling == NULL)
10040 sibling = self->priv->first_child;
10042 child->priv->next_sibling = sibling;
10044 if (sibling != NULL)
10046 ClutterActor *tmp = sibling->priv->prev_sibling;
10048 child->priv->prev_sibling = tmp;
10051 tmp->priv->next_sibling = child;
10053 sibling->priv->prev_sibling = child;
10056 child->priv->prev_sibling = NULL;
10058 if (child->priv->prev_sibling == NULL)
10059 self->priv->first_child = child;
10061 if (child->priv->next_sibling == NULL)
10062 self->priv->last_child = child;
10065 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10066 ClutterActor *child,
10070 ADD_CHILD_CREATE_META = 1 << 0,
10071 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10072 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10073 ADD_CHILD_CHECK_STATE = 1 << 3,
10074 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10076 /* default flags for public API */
10077 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10078 ADD_CHILD_EMIT_PARENT_SET |
10079 ADD_CHILD_EMIT_ACTOR_ADDED |
10080 ADD_CHILD_CHECK_STATE |
10081 ADD_CHILD_NOTIFY_FIRST_LAST,
10083 /* flags for legacy/deprecated API */
10084 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10085 ADD_CHILD_CHECK_STATE |
10086 ADD_CHILD_NOTIFY_FIRST_LAST
10087 } ClutterActorAddChildFlags;
10090 * clutter_actor_add_child_internal:
10091 * @self: a #ClutterActor
10092 * @child: a #ClutterActor
10093 * @flags: control flags for actions
10094 * @add_func: delegate function
10095 * @data: (closure): data to pass to @add_func
10097 * Adds @child to the list of children of @self.
10099 * The actual insertion inside the list is delegated to @add_func: this
10100 * function will just set up the state, perform basic checks, and emit
10103 * The @flags argument is used to perform additional operations.
10106 clutter_actor_add_child_internal (ClutterActor *self,
10107 ClutterActor *child,
10108 ClutterActorAddChildFlags flags,
10109 ClutterActorAddChildFunc add_func,
10112 ClutterTextDirection text_dir;
10113 gboolean create_meta;
10114 gboolean emit_parent_set, emit_actor_added;
10115 gboolean check_state;
10116 gboolean notify_first_last;
10117 ClutterActor *old_first_child, *old_last_child;
10119 if (child->priv->parent != NULL)
10121 g_warning ("Cannot set a parent on an actor which has a parent. "
10122 "You must use clutter_actor_remove_child() first.");
10126 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10128 g_warning ("Cannot set a parent on a toplevel actor\n");
10132 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10134 g_warning ("Cannot set a parent currently being destroyed");
10138 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10139 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10140 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10141 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10142 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10144 old_first_child = self->priv->first_child;
10145 old_last_child = self->priv->last_child;
10147 g_object_freeze_notify (G_OBJECT (self));
10150 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10152 g_object_ref_sink (child);
10153 child->priv->parent = NULL;
10154 child->priv->next_sibling = NULL;
10155 child->priv->prev_sibling = NULL;
10157 /* delegate the actual insertion */
10158 add_func (self, child, data);
10160 g_assert (child->priv->parent == self);
10162 self->priv->n_children += 1;
10164 self->priv->age += 1;
10166 /* if push_internal() has been called then we automatically set
10167 * the flag on the actor
10169 if (self->priv->internal_child)
10170 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10172 /* clutter_actor_reparent() will emit ::parent-set for us */
10173 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10174 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10178 /* If parent is mapped or realized, we need to also be mapped or
10179 * realized once we're inside the parent.
10181 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10183 /* propagate the parent's text direction to the child */
10184 text_dir = clutter_actor_get_text_direction (self);
10185 clutter_actor_set_text_direction (child, text_dir);
10188 if (child->priv->show_on_set_parent)
10189 clutter_actor_show (child);
10191 if (CLUTTER_ACTOR_IS_MAPPED (child))
10192 clutter_actor_queue_redraw (child);
10194 /* maintain the invariant that if an actor needs layout,
10195 * its parents do as well
10197 if (child->priv->needs_width_request ||
10198 child->priv->needs_height_request ||
10199 child->priv->needs_allocation)
10201 /* we work around the short-circuiting we do
10202 * in clutter_actor_queue_relayout() since we
10203 * want to force a relayout
10205 child->priv->needs_width_request = TRUE;
10206 child->priv->needs_height_request = TRUE;
10207 child->priv->needs_allocation = TRUE;
10209 clutter_actor_queue_relayout (child->priv->parent);
10212 if (emit_actor_added)
10213 g_signal_emit_by_name (self, "actor-added", child);
10215 if (notify_first_last)
10217 if (old_first_child != self->priv->first_child)
10218 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10220 if (old_last_child != self->priv->last_child)
10221 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10224 g_object_thaw_notify (G_OBJECT (self));
10228 * clutter_actor_add_child:
10229 * @self: a #ClutterActor
10230 * @child: a #ClutterActor
10232 * Adds @child to the children of @self.
10234 * This function will acquire a reference on @child that will only
10235 * be released when calling clutter_actor_remove_child().
10237 * This function will take into consideration the #ClutterActor:depth
10238 * of @child, and will keep the list of children sorted.
10240 * This function will emit the #ClutterContainer::actor-added signal
10246 clutter_actor_add_child (ClutterActor *self,
10247 ClutterActor *child)
10249 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10250 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10251 g_return_if_fail (self != child);
10252 g_return_if_fail (child->priv->parent == NULL);
10254 clutter_actor_add_child_internal (self, child,
10255 ADD_CHILD_DEFAULT_FLAGS,
10256 insert_child_at_depth,
10261 * clutter_actor_insert_child_at_index:
10262 * @self: a #ClutterActor
10263 * @child: a #ClutterActor
10264 * @index_: the index
10266 * Inserts @child into the list of children of @self, using the
10267 * given @index_. If @index_ is greater than the number of children
10268 * in @self, or is less than 0, then the new child is added at the end.
10270 * This function will acquire a reference on @child that will only
10271 * be released when calling clutter_actor_remove_child().
10273 * This function will not take into consideration the #ClutterActor:depth
10276 * This function will emit the #ClutterContainer::actor-added signal
10282 clutter_actor_insert_child_at_index (ClutterActor *self,
10283 ClutterActor *child,
10286 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10287 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10288 g_return_if_fail (self != child);
10289 g_return_if_fail (child->priv->parent == NULL);
10291 clutter_actor_add_child_internal (self, child,
10292 ADD_CHILD_DEFAULT_FLAGS,
10293 insert_child_at_index,
10294 GINT_TO_POINTER (index_));
10298 * clutter_actor_insert_child_above:
10299 * @self: a #ClutterActor
10300 * @child: a #ClutterActor
10301 * @sibling: (allow-none): a child of @self, or %NULL
10303 * Inserts @child into the list of children of @self, above another
10304 * child of @self or, if @sibling is %NULL, above all the children
10307 * This function will acquire a reference on @child that will only
10308 * be released when calling clutter_actor_remove_child().
10310 * This function will not take into consideration the #ClutterActor:depth
10313 * This function will emit the #ClutterContainer::actor-added signal
10319 clutter_actor_insert_child_above (ClutterActor *self,
10320 ClutterActor *child,
10321 ClutterActor *sibling)
10323 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10324 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10325 g_return_if_fail (self != child);
10326 g_return_if_fail (child != sibling);
10327 g_return_if_fail (child->priv->parent == NULL);
10328 g_return_if_fail (sibling == NULL ||
10329 (CLUTTER_IS_ACTOR (sibling) &&
10330 sibling->priv->parent == self));
10332 clutter_actor_add_child_internal (self, child,
10333 ADD_CHILD_DEFAULT_FLAGS,
10334 insert_child_above,
10339 * clutter_actor_insert_child_below:
10340 * @self: a #ClutterActor
10341 * @child: a #ClutterActor
10342 * @sibling: (allow-none): a child of @self, or %NULL
10344 * Inserts @child into the list of children of @self, below another
10345 * child of @self or, if @sibling is %NULL, below all the children
10348 * This function will acquire a reference on @child that will only
10349 * be released when calling clutter_actor_remove_child().
10351 * This function will not take into consideration the #ClutterActor:depth
10354 * This function will emit the #ClutterContainer::actor-added signal
10360 clutter_actor_insert_child_below (ClutterActor *self,
10361 ClutterActor *child,
10362 ClutterActor *sibling)
10364 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10365 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10366 g_return_if_fail (self != child);
10367 g_return_if_fail (child != sibling);
10368 g_return_if_fail (child->priv->parent == NULL);
10369 g_return_if_fail (sibling == NULL ||
10370 (CLUTTER_IS_ACTOR (sibling) &&
10371 sibling->priv->parent == self));
10373 clutter_actor_add_child_internal (self, child,
10374 ADD_CHILD_DEFAULT_FLAGS,
10375 insert_child_below,
10380 * clutter_actor_set_parent:
10381 * @self: A #ClutterActor
10382 * @parent: A new #ClutterActor parent
10384 * Sets the parent of @self to @parent.
10386 * This function will result in @parent acquiring a reference on @self,
10387 * eventually by sinking its floating reference first. The reference
10388 * will be released by clutter_actor_unparent().
10390 * This function should only be called by legacy #ClutterActor<!-- -->s
10391 * implementing the #ClutterContainer interface.
10393 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10396 clutter_actor_set_parent (ClutterActor *self,
10397 ClutterActor *parent)
10399 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10400 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10401 g_return_if_fail (self != parent);
10402 g_return_if_fail (self->priv->parent == NULL);
10404 /* as this function will be called inside ClutterContainer::add
10405 * implementations or when building up a composite actor, we have
10406 * to preserve the old behaviour, and not create child meta or
10407 * emit the ::actor-added signal, to avoid recursion or double
10410 clutter_actor_add_child_internal (parent, self,
10411 ADD_CHILD_LEGACY_FLAGS,
10412 insert_child_at_depth,
10417 * clutter_actor_get_parent:
10418 * @self: A #ClutterActor
10420 * Retrieves the parent of @self.
10422 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10423 * if no parent is set
10426 clutter_actor_get_parent (ClutterActor *self)
10428 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10430 return self->priv->parent;
10434 * clutter_actor_get_paint_visibility:
10435 * @self: A #ClutterActor
10437 * Retrieves the 'paint' visibility of an actor recursively checking for non
10440 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10442 * Return Value: %TRUE if the actor is visibile and will be painted.
10447 clutter_actor_get_paint_visibility (ClutterActor *actor)
10449 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10451 return CLUTTER_ACTOR_IS_MAPPED (actor);
10455 * clutter_actor_remove_child:
10456 * @self: a #ClutterActor
10457 * @child: a #ClutterActor
10459 * Removes @child from the children of @self.
10461 * This function will release the reference added by
10462 * clutter_actor_add_child(), so if you want to keep using @child
10463 * you will have to acquire a referenced on it before calling this
10466 * This function will emit the #ClutterContainer::actor-removed
10472 clutter_actor_remove_child (ClutterActor *self,
10473 ClutterActor *child)
10475 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10476 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10477 g_return_if_fail (self != child);
10478 g_return_if_fail (child->priv->parent != NULL);
10479 g_return_if_fail (child->priv->parent == self);
10481 clutter_actor_remove_child_internal (self, child,
10482 REMOVE_CHILD_DEFAULT_FLAGS);
10486 * clutter_actor_remove_all_children:
10487 * @self: a #ClutterActor
10489 * Removes all children of @self.
10491 * This function releases the reference added by inserting a child actor
10492 * in the list of children of @self.
10494 * If the reference count of a child drops to zero, the child will be
10495 * destroyed. If you want to ensure the destruction of all the children
10496 * of @self, use clutter_actor_destroy_all_children().
10501 clutter_actor_remove_all_children (ClutterActor *self)
10503 ClutterActorIter iter;
10505 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10507 if (self->priv->n_children == 0)
10510 g_object_freeze_notify (G_OBJECT (self));
10512 clutter_actor_iter_init (&iter, self);
10513 while (clutter_actor_iter_next (&iter, NULL))
10514 clutter_actor_iter_remove (&iter);
10516 g_object_thaw_notify (G_OBJECT (self));
10519 g_assert (self->priv->first_child == NULL);
10520 g_assert (self->priv->last_child == NULL);
10521 g_assert (self->priv->n_children == 0);
10525 * clutter_actor_destroy_all_children:
10526 * @self: a #ClutterActor
10528 * Destroys all children of @self.
10530 * This function releases the reference added by inserting a child
10531 * actor in the list of children of @self, and ensures that the
10532 * #ClutterActor::destroy signal is emitted on each child of the
10535 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
10536 * when its reference count drops to 0; the default handler of the
10537 * #ClutterActor::destroy signal will destroy all the children of an
10538 * actor. This function ensures that all children are destroyed, instead
10539 * of just removed from @self, unlike clutter_actor_remove_all_children()
10540 * which will merely release the reference and remove each child.
10542 * Unless you acquired an additional reference on each child of @self
10543 * prior to calling clutter_actor_remove_all_children() and want to reuse
10544 * the actors, you should use clutter_actor_destroy_all_children() in
10545 * order to make sure that children are destroyed and signal handlers
10546 * are disconnected even in cases where circular references prevent this
10547 * from automatically happening through reference counting alone.
10552 clutter_actor_destroy_all_children (ClutterActor *self)
10554 ClutterActorIter iter;
10556 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10558 if (self->priv->n_children == 0)
10561 g_object_freeze_notify (G_OBJECT (self));
10563 clutter_actor_iter_init (&iter, self);
10564 while (clutter_actor_iter_next (&iter, NULL))
10565 clutter_actor_iter_destroy (&iter);
10567 g_object_thaw_notify (G_OBJECT (self));
10570 g_assert (self->priv->first_child == NULL);
10571 g_assert (self->priv->last_child == NULL);
10572 g_assert (self->priv->n_children == 0);
10575 typedef struct _InsertBetweenData {
10576 ClutterActor *prev_sibling;
10577 ClutterActor *next_sibling;
10578 } InsertBetweenData;
10581 insert_child_between (ClutterActor *self,
10582 ClutterActor *child,
10585 InsertBetweenData *data = data_;
10586 ClutterActor *prev_sibling = data->prev_sibling;
10587 ClutterActor *next_sibling = data->next_sibling;
10589 child->priv->parent = self;
10590 child->priv->prev_sibling = prev_sibling;
10591 child->priv->next_sibling = next_sibling;
10593 if (prev_sibling != NULL)
10594 prev_sibling->priv->next_sibling = child;
10596 if (next_sibling != NULL)
10597 next_sibling->priv->prev_sibling = child;
10599 if (child->priv->prev_sibling == NULL)
10600 self->priv->first_child = child;
10602 if (child->priv->next_sibling == NULL)
10603 self->priv->last_child = child;
10607 * clutter_actor_replace_child:
10608 * @self: a #ClutterActor
10609 * @old_child: the child of @self to replace
10610 * @new_child: the #ClutterActor to replace @old_child
10612 * Replaces @old_child with @new_child in the list of children of @self.
10617 clutter_actor_replace_child (ClutterActor *self,
10618 ClutterActor *old_child,
10619 ClutterActor *new_child)
10621 ClutterActor *prev_sibling, *next_sibling;
10622 InsertBetweenData clos;
10624 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10625 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10626 g_return_if_fail (old_child->priv->parent == self);
10627 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10628 g_return_if_fail (old_child != new_child);
10629 g_return_if_fail (new_child != self);
10630 g_return_if_fail (new_child->priv->parent == NULL);
10632 prev_sibling = old_child->priv->prev_sibling;
10633 next_sibling = old_child->priv->next_sibling;
10634 clutter_actor_remove_child_internal (self, old_child,
10635 REMOVE_CHILD_DEFAULT_FLAGS);
10637 clos.prev_sibling = prev_sibling;
10638 clos.next_sibling = next_sibling;
10639 clutter_actor_add_child_internal (self, new_child,
10640 ADD_CHILD_DEFAULT_FLAGS,
10641 insert_child_between,
10646 * clutter_actor_unparent:
10647 * @self: a #ClutterActor
10649 * Removes the parent of @self.
10651 * This will cause the parent of @self to release the reference
10652 * acquired when calling clutter_actor_set_parent(), so if you
10653 * want to keep @self you will have to acquire a reference of
10654 * your own, through g_object_ref().
10656 * This function should only be called by legacy #ClutterActor<!-- -->s
10657 * implementing the #ClutterContainer interface.
10661 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10664 clutter_actor_unparent (ClutterActor *self)
10666 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10668 if (self->priv->parent == NULL)
10671 clutter_actor_remove_child_internal (self->priv->parent, self,
10672 REMOVE_CHILD_LEGACY_FLAGS);
10676 * clutter_actor_reparent:
10677 * @self: a #ClutterActor
10678 * @new_parent: the new #ClutterActor parent
10680 * Resets the parent actor of @self.
10682 * This function is logically equivalent to calling clutter_actor_unparent()
10683 * and clutter_actor_set_parent(), but more efficiently implemented, as it
10684 * ensures the child is not finalized when unparented, and emits the
10685 * #ClutterActor::parent-set signal only once.
10687 * In reality, calling this function is less useful than it sounds, as some
10688 * application code may rely on changes in the intermediate state between
10689 * removal and addition of the actor from its old parent to the @new_parent.
10690 * Thus, it is strongly encouraged to avoid using this function in application
10695 * Deprecated: 1.10: Use clutter_actor_remove_child() and
10696 * clutter_actor_add_child() instead; remember to take a reference on
10697 * the actor being removed before calling clutter_actor_remove_child()
10698 * to avoid the reference count dropping to zero and the actor being
10702 clutter_actor_reparent (ClutterActor *self,
10703 ClutterActor *new_parent)
10705 ClutterActorPrivate *priv;
10707 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10708 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10709 g_return_if_fail (self != new_parent);
10711 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10713 g_warning ("Cannot set a parent on a toplevel actor");
10717 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10719 g_warning ("Cannot set a parent currently being destroyed");
10725 if (priv->parent != new_parent)
10727 ClutterActor *old_parent;
10729 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10731 old_parent = priv->parent;
10733 g_object_ref (self);
10735 if (old_parent != NULL)
10737 /* go through the Container implementation if this is a regular
10738 * child and not an internal one
10740 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10742 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10744 /* this will have to call unparent() */
10745 clutter_container_remove_actor (parent, self);
10748 clutter_actor_remove_child_internal (old_parent, self,
10749 REMOVE_CHILD_LEGACY_FLAGS);
10752 /* Note, will call set_parent() */
10753 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10754 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10756 clutter_actor_add_child_internal (new_parent, self,
10757 ADD_CHILD_LEGACY_FLAGS,
10758 insert_child_at_depth,
10761 /* we emit the ::parent-set signal once */
10762 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10764 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10766 /* the IN_REPARENT flag suspends state updates */
10767 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10769 g_object_unref (self);
10774 * clutter_actor_contains:
10775 * @self: A #ClutterActor
10776 * @descendant: A #ClutterActor, possibly contained in @self
10778 * Determines if @descendant is contained inside @self (either as an
10779 * immediate child, or as a deeper descendant). If @self and
10780 * @descendant point to the same actor then it will also return %TRUE.
10782 * Return value: whether @descendent is contained within @self
10787 clutter_actor_contains (ClutterActor *self,
10788 ClutterActor *descendant)
10790 ClutterActor *actor;
10792 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10793 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10795 for (actor = descendant; actor; actor = actor->priv->parent)
10803 * clutter_actor_set_child_above_sibling:
10804 * @self: a #ClutterActor
10805 * @child: a #ClutterActor child of @self
10806 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10808 * Sets @child to be above @sibling in the list of children of @self.
10810 * If @sibling is %NULL, @child will be the new last child of @self.
10812 * This function is logically equivalent to removing @child and using
10813 * clutter_actor_insert_child_above(), but it will not emit signals
10814 * or change state on @child.
10819 clutter_actor_set_child_above_sibling (ClutterActor *self,
10820 ClutterActor *child,
10821 ClutterActor *sibling)
10823 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10824 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10825 g_return_if_fail (child->priv->parent == self);
10826 g_return_if_fail (child != sibling);
10827 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10829 if (sibling != NULL)
10830 g_return_if_fail (sibling->priv->parent == self);
10832 /* we don't want to change the state of child, or emit signals, or
10833 * regenerate ChildMeta instances here, but we still want to follow
10834 * the correct sequence of steps encoded in remove_child() and
10835 * add_child(), so that correctness is ensured, and we only go
10836 * through one known code path.
10838 g_object_ref (child);
10839 clutter_actor_remove_child_internal (self, child, 0);
10840 clutter_actor_add_child_internal (self, child,
10841 ADD_CHILD_NOTIFY_FIRST_LAST,
10842 insert_child_above,
10845 clutter_actor_queue_relayout (self);
10849 * clutter_actor_set_child_below_sibling:
10850 * @self: a #ClutterActor
10851 * @child: a #ClutterActor child of @self
10852 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10854 * Sets @child to be below @sibling in the list of children of @self.
10856 * If @sibling is %NULL, @child will be the new first child of @self.
10858 * This function is logically equivalent to removing @self and using
10859 * clutter_actor_insert_child_below(), but it will not emit signals
10860 * or change state on @child.
10865 clutter_actor_set_child_below_sibling (ClutterActor *self,
10866 ClutterActor *child,
10867 ClutterActor *sibling)
10869 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10870 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10871 g_return_if_fail (child->priv->parent == self);
10872 g_return_if_fail (child != sibling);
10873 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10875 if (sibling != NULL)
10876 g_return_if_fail (sibling->priv->parent == self);
10878 /* see the comment in set_child_above_sibling() */
10879 g_object_ref (child);
10880 clutter_actor_remove_child_internal (self, child, 0);
10881 clutter_actor_add_child_internal (self, child,
10882 ADD_CHILD_NOTIFY_FIRST_LAST,
10883 insert_child_below,
10886 clutter_actor_queue_relayout (self);
10890 * clutter_actor_set_child_at_index:
10891 * @self: a #ClutterActor
10892 * @child: a #ClutterActor child of @self
10893 * @index_: the new index for @child
10895 * Changes the index of @child in the list of children of @self.
10897 * This function is logically equivalent to removing @child and
10898 * calling clutter_actor_insert_child_at_index(), but it will not
10899 * emit signals or change state on @child.
10904 clutter_actor_set_child_at_index (ClutterActor *self,
10905 ClutterActor *child,
10908 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10909 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10910 g_return_if_fail (child->priv->parent == self);
10911 g_return_if_fail (index_ <= self->priv->n_children);
10913 g_object_ref (child);
10914 clutter_actor_remove_child_internal (self, child, 0);
10915 clutter_actor_add_child_internal (self, child,
10916 ADD_CHILD_NOTIFY_FIRST_LAST,
10917 insert_child_at_index,
10918 GINT_TO_POINTER (index_));
10920 clutter_actor_queue_relayout (self);
10924 * clutter_actor_raise:
10925 * @self: A #ClutterActor
10926 * @below: (allow-none): A #ClutterActor to raise above.
10928 * Puts @self above @below.
10930 * Both actors must have the same parent, and the parent must implement
10931 * the #ClutterContainer interface
10933 * This function calls clutter_container_raise_child() internally.
10935 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
10938 clutter_actor_raise (ClutterActor *self,
10939 ClutterActor *below)
10941 ClutterActor *parent;
10943 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10945 parent = clutter_actor_get_parent (self);
10946 if (parent == NULL)
10948 g_warning ("%s: Actor '%s' is not inside a container",
10950 _clutter_actor_get_debug_name (self));
10956 if (parent != clutter_actor_get_parent (below))
10958 g_warning ("%s Actor '%s' is not in the same container as "
10961 _clutter_actor_get_debug_name (self),
10962 _clutter_actor_get_debug_name (below));
10967 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
10971 * clutter_actor_lower:
10972 * @self: A #ClutterActor
10973 * @above: (allow-none): A #ClutterActor to lower below
10975 * Puts @self below @above.
10977 * Both actors must have the same parent, and the parent must implement
10978 * the #ClutterContainer interface.
10980 * This function calls clutter_container_lower_child() internally.
10982 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
10985 clutter_actor_lower (ClutterActor *self,
10986 ClutterActor *above)
10988 ClutterActor *parent;
10990 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10992 parent = clutter_actor_get_parent (self);
10993 if (parent == NULL)
10995 g_warning ("%s: Actor of type %s is not inside a container",
10997 _clutter_actor_get_debug_name (self));
11003 if (parent != clutter_actor_get_parent (above))
11005 g_warning ("%s: Actor '%s' is not in the same container as "
11008 _clutter_actor_get_debug_name (self),
11009 _clutter_actor_get_debug_name (above));
11014 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11018 * clutter_actor_raise_top:
11019 * @self: A #ClutterActor
11021 * Raises @self to the top.
11023 * This function calls clutter_actor_raise() internally.
11025 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11026 * a %NULL sibling, instead.
11029 clutter_actor_raise_top (ClutterActor *self)
11031 clutter_actor_raise (self, NULL);
11035 * clutter_actor_lower_bottom:
11036 * @self: A #ClutterActor
11038 * Lowers @self to the bottom.
11040 * This function calls clutter_actor_lower() internally.
11042 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11043 * a %NULL sibling, instead.
11046 clutter_actor_lower_bottom (ClutterActor *self)
11048 clutter_actor_lower (self, NULL);
11056 * clutter_actor_event:
11057 * @actor: a #ClutterActor
11058 * @event: a #ClutterEvent
11059 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11061 * This function is used to emit an event on the main stage.
11062 * You should rarely need to use this function, except for
11063 * synthetising events.
11065 * Return value: the return value from the signal emission: %TRUE
11066 * if the actor handled the event, or %FALSE if the event was
11072 clutter_actor_event (ClutterActor *actor,
11073 ClutterEvent *event,
11076 gboolean retval = FALSE;
11077 gint signal_num = -1;
11079 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11080 g_return_val_if_fail (event != NULL, FALSE);
11082 g_object_ref (actor);
11086 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11092 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11096 switch (event->type)
11098 case CLUTTER_NOTHING:
11100 case CLUTTER_BUTTON_PRESS:
11101 signal_num = BUTTON_PRESS_EVENT;
11103 case CLUTTER_BUTTON_RELEASE:
11104 signal_num = BUTTON_RELEASE_EVENT;
11106 case CLUTTER_SCROLL:
11107 signal_num = SCROLL_EVENT;
11109 case CLUTTER_KEY_PRESS:
11110 signal_num = KEY_PRESS_EVENT;
11112 case CLUTTER_KEY_RELEASE:
11113 signal_num = KEY_RELEASE_EVENT;
11115 case CLUTTER_MOTION:
11116 signal_num = MOTION_EVENT;
11118 case CLUTTER_ENTER:
11119 signal_num = ENTER_EVENT;
11121 case CLUTTER_LEAVE:
11122 signal_num = LEAVE_EVENT;
11124 case CLUTTER_DELETE:
11125 case CLUTTER_DESTROY_NOTIFY:
11126 case CLUTTER_CLIENT_MESSAGE:
11132 if (signal_num != -1)
11133 g_signal_emit (actor, actor_signals[signal_num], 0,
11138 g_object_unref (actor);
11144 * clutter_actor_set_reactive:
11145 * @actor: a #ClutterActor
11146 * @reactive: whether the actor should be reactive to events
11148 * Sets @actor as reactive. Reactive actors will receive events.
11153 clutter_actor_set_reactive (ClutterActor *actor,
11156 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11158 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11162 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11164 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11166 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11170 * clutter_actor_get_reactive:
11171 * @actor: a #ClutterActor
11173 * Checks whether @actor is marked as reactive.
11175 * Return value: %TRUE if the actor is reactive
11180 clutter_actor_get_reactive (ClutterActor *actor)
11182 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11184 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11188 * clutter_actor_get_anchor_point:
11189 * @self: a #ClutterActor
11190 * @anchor_x: (out): return location for the X coordinate of the anchor point
11191 * @anchor_y: (out): return location for the Y coordinate of the anchor point
11193 * Gets the current anchor point of the @actor in pixels.
11198 clutter_actor_get_anchor_point (ClutterActor *self,
11202 const ClutterTransformInfo *info;
11204 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11206 info = _clutter_actor_get_transform_info_or_defaults (self);
11207 clutter_anchor_coord_get_units (self, &info->anchor,
11214 * clutter_actor_set_anchor_point:
11215 * @self: a #ClutterActor
11216 * @anchor_x: X coordinate of the anchor point
11217 * @anchor_y: Y coordinate of the anchor point
11219 * Sets an anchor point for @self. The anchor point is a point in the
11220 * coordinate space of an actor to which the actor position within its
11221 * parent is relative; the default is (0, 0), i.e. the top-left corner
11227 clutter_actor_set_anchor_point (ClutterActor *self,
11231 ClutterTransformInfo *info;
11232 ClutterActorPrivate *priv;
11233 gboolean changed = FALSE;
11234 gfloat old_anchor_x, old_anchor_y;
11237 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11239 obj = G_OBJECT (self);
11241 info = _clutter_actor_get_transform_info (self);
11243 g_object_freeze_notify (obj);
11245 clutter_anchor_coord_get_units (self, &info->anchor,
11250 if (info->anchor.is_fractional)
11251 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11253 if (old_anchor_x != anchor_x)
11255 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11259 if (old_anchor_y != anchor_y)
11261 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11265 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11269 priv->transform_valid = FALSE;
11270 clutter_actor_queue_redraw (self);
11273 g_object_thaw_notify (obj);
11277 * clutter_actor_get_anchor_point_gravity:
11278 * @self: a #ClutterActor
11280 * Retrieves the anchor position expressed as a #ClutterGravity. If
11281 * the anchor point was specified using pixels or units this will
11282 * return %CLUTTER_GRAVITY_NONE.
11284 * Return value: the #ClutterGravity used by the anchor point
11289 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11291 const ClutterTransformInfo *info;
11293 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11295 info = _clutter_actor_get_transform_info_or_defaults (self);
11297 return clutter_anchor_coord_get_gravity (&info->anchor);
11301 * clutter_actor_move_anchor_point:
11302 * @self: a #ClutterActor
11303 * @anchor_x: X coordinate of the anchor point
11304 * @anchor_y: Y coordinate of the anchor point
11306 * Sets an anchor point for the actor, and adjusts the actor postion so that
11307 * the relative position of the actor toward its parent remains the same.
11312 clutter_actor_move_anchor_point (ClutterActor *self,
11316 gfloat old_anchor_x, old_anchor_y;
11317 const ClutterTransformInfo *info;
11319 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11321 info = _clutter_actor_get_transform_info (self);
11322 clutter_anchor_coord_get_units (self, &info->anchor,
11327 g_object_freeze_notify (G_OBJECT (self));
11329 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11331 if (self->priv->position_set)
11332 clutter_actor_move_by (self,
11333 anchor_x - old_anchor_x,
11334 anchor_y - old_anchor_y);
11336 g_object_thaw_notify (G_OBJECT (self));
11340 * clutter_actor_move_anchor_point_from_gravity:
11341 * @self: a #ClutterActor
11342 * @gravity: #ClutterGravity.
11344 * Sets an anchor point on the actor based on the given gravity, adjusting the
11345 * actor postion so that its relative position within its parent remains
11348 * Since version 1.0 the anchor point will be stored as a gravity so
11349 * that if the actor changes size then the anchor point will move. For
11350 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11351 * and later double the size of the actor, the anchor point will move
11352 * to the bottom right.
11357 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
11358 ClutterGravity gravity)
11360 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11361 const ClutterTransformInfo *info;
11362 ClutterActorPrivate *priv;
11364 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11367 info = _clutter_actor_get_transform_info (self);
11369 g_object_freeze_notify (G_OBJECT (self));
11371 clutter_anchor_coord_get_units (self, &info->anchor,
11375 clutter_actor_set_anchor_point_from_gravity (self, gravity);
11376 clutter_anchor_coord_get_units (self, &info->anchor,
11381 if (priv->position_set)
11382 clutter_actor_move_by (self,
11383 new_anchor_x - old_anchor_x,
11384 new_anchor_y - old_anchor_y);
11386 g_object_thaw_notify (G_OBJECT (self));
11390 * clutter_actor_set_anchor_point_from_gravity:
11391 * @self: a #ClutterActor
11392 * @gravity: #ClutterGravity.
11394 * Sets an anchor point on the actor, based on the given gravity (this is a
11395 * convenience function wrapping clutter_actor_set_anchor_point()).
11397 * Since version 1.0 the anchor point will be stored as a gravity so
11398 * that if the actor changes size then the anchor point will move. For
11399 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11400 * and later double the size of the actor, the anchor point will move
11401 * to the bottom right.
11406 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
11407 ClutterGravity gravity)
11409 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11411 if (gravity == CLUTTER_GRAVITY_NONE)
11412 clutter_actor_set_anchor_point (self, 0, 0);
11415 GObject *obj = G_OBJECT (self);
11416 ClutterTransformInfo *info;
11418 g_object_freeze_notify (obj);
11420 info = _clutter_actor_get_transform_info (self);
11421 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11423 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11424 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11425 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11427 self->priv->transform_valid = FALSE;
11429 clutter_actor_queue_redraw (self);
11431 g_object_thaw_notify (obj);
11436 clutter_container_iface_init (ClutterContainerIface *iface)
11438 /* we don't override anything, as ClutterContainer already has a default
11439 * implementation that we can use, and which calls into our own API.
11454 parse_units (ClutterActor *self,
11455 ParseDimension dimension,
11458 GValue value = { 0, };
11461 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11464 json_node_get_value (node, &value);
11466 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11468 retval = (gfloat) g_value_get_int64 (&value);
11470 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11472 retval = g_value_get_double (&value);
11474 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11476 ClutterUnits units;
11479 res = clutter_units_from_string (&units, g_value_get_string (&value));
11481 retval = clutter_units_to_pixels (&units);
11484 g_warning ("Invalid value '%s': integers, strings or floating point "
11485 "values can be used for the x, y, width and height "
11486 "properties. Valid modifiers for strings are 'px', 'mm', "
11488 g_value_get_string (&value));
11494 g_warning ("Invalid value of type '%s': integers, strings of floating "
11495 "point values can be used for the x, y, width, height "
11496 "anchor-x and anchor-y properties.",
11497 g_type_name (G_VALUE_TYPE (&value)));
11500 g_value_unset (&value);
11506 ClutterRotateAxis axis;
11515 static inline gboolean
11516 parse_rotation_array (ClutterActor *actor,
11518 RotationInfo *info)
11522 if (json_array_get_length (array) != 2)
11526 element = json_array_get_element (array, 0);
11527 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11528 info->angle = json_node_get_double (element);
11533 element = json_array_get_element (array, 1);
11534 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11536 JsonArray *center = json_node_get_array (element);
11538 if (json_array_get_length (center) != 2)
11541 switch (info->axis)
11543 case CLUTTER_X_AXIS:
11544 info->center_y = parse_units (actor, PARSE_Y,
11545 json_array_get_element (center, 0));
11546 info->center_z = parse_units (actor, PARSE_Y,
11547 json_array_get_element (center, 1));
11550 case CLUTTER_Y_AXIS:
11551 info->center_x = parse_units (actor, PARSE_X,
11552 json_array_get_element (center, 0));
11553 info->center_z = parse_units (actor, PARSE_X,
11554 json_array_get_element (center, 1));
11557 case CLUTTER_Z_AXIS:
11558 info->center_x = parse_units (actor, PARSE_X,
11559 json_array_get_element (center, 0));
11560 info->center_y = parse_units (actor, PARSE_Y,
11561 json_array_get_element (center, 1));
11570 parse_rotation (ClutterActor *actor,
11572 RotationInfo *info)
11576 gboolean retval = FALSE;
11578 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11580 g_warning ("Invalid node of type '%s' found, expecting an array",
11581 json_node_type_name (node));
11585 array = json_node_get_array (node);
11586 len = json_array_get_length (array);
11588 for (i = 0; i < len; i++)
11590 JsonNode *element = json_array_get_element (array, i);
11591 JsonObject *object;
11594 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11596 g_warning ("Invalid node of type '%s' found, expecting an object",
11597 json_node_type_name (element));
11601 object = json_node_get_object (element);
11603 if (json_object_has_member (object, "x-axis"))
11605 member = json_object_get_member (object, "x-axis");
11607 info->axis = CLUTTER_X_AXIS;
11609 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11611 info->angle = json_node_get_double (member);
11614 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11615 retval = parse_rotation_array (actor,
11616 json_node_get_array (member),
11621 else if (json_object_has_member (object, "y-axis"))
11623 member = json_object_get_member (object, "y-axis");
11625 info->axis = CLUTTER_Y_AXIS;
11627 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11629 info->angle = json_node_get_double (member);
11632 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11633 retval = parse_rotation_array (actor,
11634 json_node_get_array (member),
11639 else if (json_object_has_member (object, "z-axis"))
11641 member = json_object_get_member (object, "z-axis");
11643 info->axis = CLUTTER_Z_AXIS;
11645 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11647 info->angle = json_node_get_double (member);
11650 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11651 retval = parse_rotation_array (actor,
11652 json_node_get_array (member),
11663 parse_actor_metas (ClutterScript *script,
11664 ClutterActor *actor,
11667 GList *elements, *l;
11668 GSList *retval = NULL;
11670 if (!JSON_NODE_HOLDS_ARRAY (node))
11673 elements = json_array_get_elements (json_node_get_array (node));
11675 for (l = elements; l != NULL; l = l->next)
11677 JsonNode *element = l->data;
11678 const gchar *id_ = _clutter_script_get_id_from_node (element);
11681 if (id_ == NULL || *id_ == '\0')
11684 meta = clutter_script_get_object (script, id_);
11688 retval = g_slist_prepend (retval, meta);
11691 g_list_free (elements);
11693 return g_slist_reverse (retval);
11697 parse_behaviours (ClutterScript *script,
11698 ClutterActor *actor,
11701 GList *elements, *l;
11702 GSList *retval = NULL;
11704 if (!JSON_NODE_HOLDS_ARRAY (node))
11707 elements = json_array_get_elements (json_node_get_array (node));
11709 for (l = elements; l != NULL; l = l->next)
11711 JsonNode *element = l->data;
11712 const gchar *id_ = _clutter_script_get_id_from_node (element);
11713 GObject *behaviour;
11715 if (id_ == NULL || *id_ == '\0')
11718 behaviour = clutter_script_get_object (script, id_);
11719 if (behaviour == NULL)
11722 retval = g_slist_prepend (retval, behaviour);
11725 g_list_free (elements);
11727 return g_slist_reverse (retval);
11731 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11732 ClutterScript *script,
11737 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11738 gboolean retval = FALSE;
11740 if ((name[0] == 'x' && name[1] == '\0') ||
11741 (name[0] == 'y' && name[1] == '\0') ||
11742 (strcmp (name, "width") == 0) ||
11743 (strcmp (name, "height") == 0) ||
11744 (strcmp (name, "anchor_x") == 0) ||
11745 (strcmp (name, "anchor_y") == 0))
11747 ParseDimension dimension;
11750 if (name[0] == 'x')
11751 dimension = PARSE_X;
11752 else if (name[0] == 'y')
11753 dimension = PARSE_Y;
11754 else if (name[0] == 'w')
11755 dimension = PARSE_WIDTH;
11756 else if (name[0] == 'h')
11757 dimension = PARSE_HEIGHT;
11758 else if (name[0] == 'a' && name[7] == 'x')
11759 dimension = PARSE_ANCHOR_X;
11760 else if (name[0] == 'a' && name[7] == 'y')
11761 dimension = PARSE_ANCHOR_Y;
11765 units = parse_units (actor, dimension, node);
11767 /* convert back to pixels: all properties are pixel-based */
11768 g_value_init (value, G_TYPE_FLOAT);
11769 g_value_set_float (value, units);
11773 else if (strcmp (name, "rotation") == 0)
11775 RotationInfo *info;
11777 info = g_slice_new0 (RotationInfo);
11778 retval = parse_rotation (actor, node, info);
11782 g_value_init (value, G_TYPE_POINTER);
11783 g_value_set_pointer (value, info);
11786 g_slice_free (RotationInfo, info);
11788 else if (strcmp (name, "behaviours") == 0)
11792 #ifdef CLUTTER_ENABLE_DEBUG
11793 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11794 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11795 "and it should not be used in newly "
11796 "written ClutterScript definitions.");
11799 l = parse_behaviours (script, actor, node);
11801 g_value_init (value, G_TYPE_POINTER);
11802 g_value_set_pointer (value, l);
11806 else if (strcmp (name, "actions") == 0 ||
11807 strcmp (name, "constraints") == 0 ||
11808 strcmp (name, "effects") == 0)
11812 l = parse_actor_metas (script, actor, node);
11814 g_value_init (value, G_TYPE_POINTER);
11815 g_value_set_pointer (value, l);
11824 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11825 ClutterScript *script,
11827 const GValue *value)
11829 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11831 #ifdef CLUTTER_ENABLE_DEBUG
11832 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11834 gchar *tmp = g_strdup_value_contents (value);
11836 CLUTTER_NOTE (SCRIPT,
11837 "in ClutterActor::set_custom_property('%s') = %s",
11843 #endif /* CLUTTER_ENABLE_DEBUG */
11845 if (strcmp (name, "rotation") == 0)
11847 RotationInfo *info;
11849 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11852 info = g_value_get_pointer (value);
11854 clutter_actor_set_rotation (actor,
11855 info->axis, info->angle,
11860 g_slice_free (RotationInfo, info);
11865 if (strcmp (name, "behaviours") == 0)
11867 GSList *behaviours, *l;
11869 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11872 behaviours = g_value_get_pointer (value);
11873 for (l = behaviours; l != NULL; l = l->next)
11875 ClutterBehaviour *behaviour = l->data;
11877 clutter_behaviour_apply (behaviour, actor);
11880 g_slist_free (behaviours);
11885 if (strcmp (name, "actions") == 0 ||
11886 strcmp (name, "constraints") == 0 ||
11887 strcmp (name, "effects") == 0)
11891 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11894 metas = g_value_get_pointer (value);
11895 for (l = metas; l != NULL; l = l->next)
11897 if (name[0] == 'a')
11898 clutter_actor_add_action (actor, l->data);
11900 if (name[0] == 'c')
11901 clutter_actor_add_constraint (actor, l->data);
11903 if (name[0] == 'e')
11904 clutter_actor_add_effect (actor, l->data);
11907 g_slist_free (metas);
11912 g_object_set_property (G_OBJECT (scriptable), name, value);
11916 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
11918 iface->parse_custom_node = clutter_actor_parse_custom_node;
11919 iface->set_custom_property = clutter_actor_set_custom_property;
11922 static ClutterActorMeta *
11923 get_meta_from_animation_property (ClutterActor *actor,
11927 ClutterActorPrivate *priv = actor->priv;
11928 ClutterActorMeta *meta = NULL;
11931 /* if this is not a special property, fall through */
11932 if (name[0] != '@')
11935 /* detect the properties named using the following spec:
11937 * @<section>.<meta-name>.<property-name>
11939 * where <section> can be one of the following:
11945 * and <meta-name> is the name set on a specific ActorMeta
11948 tokens = g_strsplit (name + 1, ".", -1);
11949 if (tokens == NULL || g_strv_length (tokens) != 3)
11951 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
11953 g_strfreev (tokens);
11957 if (strcmp (tokens[0], "actions") == 0)
11958 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
11960 if (strcmp (tokens[0], "constraints") == 0)
11961 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
11963 if (strcmp (tokens[0], "effects") == 0)
11964 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
11966 if (name_p != NULL)
11967 *name_p = g_strdup (tokens[2]);
11969 CLUTTER_NOTE (ANIMATION,
11970 "Looking for property '%s' of object '%s' in section '%s'",
11975 g_strfreev (tokens);
11980 static GParamSpec *
11981 clutter_actor_find_property (ClutterAnimatable *animatable,
11982 const gchar *property_name)
11984 ClutterActorMeta *meta = NULL;
11985 GObjectClass *klass = NULL;
11986 GParamSpec *pspec = NULL;
11987 gchar *p_name = NULL;
11989 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
11995 klass = G_OBJECT_GET_CLASS (meta);
11997 pspec = g_object_class_find_property (klass, p_name);
12001 klass = G_OBJECT_GET_CLASS (animatable);
12003 pspec = g_object_class_find_property (klass, property_name);
12012 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12013 const gchar *property_name,
12016 ClutterActorMeta *meta = NULL;
12017 gchar *p_name = NULL;
12019 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12024 g_object_get_property (G_OBJECT (meta), p_name, initial);
12026 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12032 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12033 const gchar *property_name,
12034 const GValue *final)
12036 ClutterActorMeta *meta = NULL;
12037 gchar *p_name = NULL;
12039 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12043 g_object_set_property (G_OBJECT (meta), p_name, final);
12045 g_object_set_property (G_OBJECT (animatable), property_name, final);
12051 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12053 iface->find_property = clutter_actor_find_property;
12054 iface->get_initial_state = clutter_actor_get_initial_state;
12055 iface->set_final_state = clutter_actor_set_final_state;
12059 * clutter_actor_transform_stage_point:
12060 * @self: A #ClutterActor
12061 * @x: (in): x screen coordinate of the point to unproject
12062 * @y: (in): y screen coordinate of the point to unproject
12063 * @x_out: (out): return location for the unprojected x coordinance
12064 * @y_out: (out): return location for the unprojected y coordinance
12066 * This function translates screen coordinates (@x, @y) to
12067 * coordinates relative to the actor. For example, it can be used to translate
12068 * screen events from global screen coordinates into actor-local coordinates.
12070 * The conversion can fail, notably if the transform stack results in the
12071 * actor being projected on the screen as a mere line.
12073 * The conversion should not be expected to be pixel-perfect due to the
12074 * nature of the operation. In general the error grows when the skewing
12075 * of the actor rectangle on screen increases.
12077 * <note><para>This function can be computationally intensive.</para></note>
12079 * <note><para>This function only works when the allocation is up-to-date,
12080 * i.e. inside of paint().</para></note>
12082 * Return value: %TRUE if conversion was successful.
12087 clutter_actor_transform_stage_point (ClutterActor *self,
12093 ClutterVertex v[4];
12096 int du, dv, xi, yi;
12098 float xf, yf, wf, det;
12099 ClutterActorPrivate *priv;
12101 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12105 /* This implementation is based on the quad -> quad projection algorithm
12106 * described by Paul Heckbert in:
12108 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12110 * and the sample implementation at:
12112 * http://www.cs.cmu.edu/~ph/src/texfund/
12114 * Our texture is a rectangle with origin [0, 0], so we are mapping from
12115 * quad to rectangle only, which significantly simplifies things; the
12116 * function calls have been unrolled, and most of the math is done in fixed
12120 clutter_actor_get_abs_allocation_vertices (self, v);
12122 /* Keeping these as ints simplifies the multiplication (no significant
12123 * loss of precision here).
12125 du = (int) (priv->allocation.x2 - priv->allocation.x1);
12126 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12131 #define UX2FP(x) (x)
12132 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12134 /* First, find mapping from unit uv square to xy quadrilateral; this
12135 * equivalent to the pmap_square_quad() functions in the sample
12136 * implementation, which we can simplify, since our target is always
12139 px = v[0].x - v[1].x + v[3].x - v[2].x;
12140 py = v[0].y - v[1].y + v[3].y - v[2].y;
12144 /* affine transform */
12145 RQ[0][0] = UX2FP (v[1].x - v[0].x);
12146 RQ[1][0] = UX2FP (v[3].x - v[1].x);
12147 RQ[2][0] = UX2FP (v[0].x);
12148 RQ[0][1] = UX2FP (v[1].y - v[0].y);
12149 RQ[1][1] = UX2FP (v[3].y - v[1].y);
12150 RQ[2][1] = UX2FP (v[0].y);
12157 /* projective transform */
12158 double dx1, dx2, dy1, dy2, del;
12160 dx1 = UX2FP (v[1].x - v[3].x);
12161 dx2 = UX2FP (v[2].x - v[3].x);
12162 dy1 = UX2FP (v[1].y - v[3].y);
12163 dy2 = UX2FP (v[2].y - v[3].y);
12165 del = DET2FP (dx1, dx2, dy1, dy2);
12170 * The division here needs to be done in floating point for
12171 * precisions reasons.
12173 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12174 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12175 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12177 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12178 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12179 RQ[2][0] = UX2FP (v[0].x);
12180 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12181 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12182 RQ[2][1] = UX2FP (v[0].y);
12186 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12187 * square. Since our rectangle is based at 0,0 we only need to scale.
12197 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12200 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12201 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12202 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12203 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12204 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12205 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12206 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12207 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12208 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12211 * Check the resulting matrix is OK.
12213 det = (RQ[0][0] * ST[0][0])
12214 + (RQ[0][1] * ST[0][1])
12215 + (RQ[0][2] * ST[0][2]);
12220 * Now transform our point with the ST matrix; the notional w
12221 * coordinate is 1, hence the last part is simply added.
12226 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12227 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12228 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12246 static ClutterGeometry*
12247 clutter_geometry_copy (const ClutterGeometry *geometry)
12249 return g_slice_dup (ClutterGeometry, geometry);
12253 clutter_geometry_free (ClutterGeometry *geometry)
12255 if (G_LIKELY (geometry != NULL))
12256 g_slice_free (ClutterGeometry, geometry);
12260 * clutter_geometry_union:
12261 * @geometry_a: a #ClutterGeometry
12262 * @geometry_b: another #ClutterGeometry
12263 * @result: (out): location to store the result
12265 * Find the union of two rectangles represented as #ClutterGeometry.
12270 clutter_geometry_union (const ClutterGeometry *geometry_a,
12271 const ClutterGeometry *geometry_b,
12272 ClutterGeometry *result)
12274 /* We don't try to handle rectangles that can't be represented
12275 * as a signed integer box */
12276 gint x_1 = MIN (geometry_a->x, geometry_b->x);
12277 gint y_1 = MIN (geometry_a->y, geometry_b->y);
12278 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12279 geometry_b->x + (gint)geometry_b->width);
12280 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12281 geometry_b->y + (gint)geometry_b->height);
12284 result->width = x_2 - x_1;
12285 result->height = y_2 - y_1;
12289 * clutter_geometry_intersects:
12290 * @geometry0: The first geometry to test
12291 * @geometry1: The second geometry to test
12293 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12294 * they do else %FALSE.
12296 * Return value: %TRUE of @geometry0 and geometry1 intersect else
12302 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12303 const ClutterGeometry *geometry1)
12305 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12306 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12307 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12308 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12315 clutter_geometry_progress (const GValue *a,
12320 const ClutterGeometry *a_geom = g_value_get_boxed (a);
12321 const ClutterGeometry *b_geom = g_value_get_boxed (b);
12322 ClutterGeometry res = { 0, };
12323 gint a_width = a_geom->width;
12324 gint b_width = b_geom->width;
12325 gint a_height = a_geom->height;
12326 gint b_height = b_geom->height;
12328 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12329 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12331 res.width = a_width + (b_width - a_width) * progress;
12332 res.height = a_height + (b_height - a_height) * progress;
12334 g_value_set_boxed (retval, &res);
12339 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12340 clutter_geometry_copy,
12341 clutter_geometry_free,
12342 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12349 * clutter_vertex_new:
12354 * Creates a new #ClutterVertex for the point in 3D space
12355 * identified by the 3 coordinates @x, @y, @z
12357 * Return value: the newly allocate #ClutterVertex. Use
12358 * clutter_vertex_free() to free the resources
12363 clutter_vertex_new (gfloat x,
12367 ClutterVertex *vertex;
12369 vertex = g_slice_new (ClutterVertex);
12378 * clutter_vertex_copy:
12379 * @vertex: a #ClutterVertex
12383 * Return value: a newly allocated copy of #ClutterVertex. Use
12384 * clutter_vertex_free() to free the allocated resources
12389 clutter_vertex_copy (const ClutterVertex *vertex)
12391 if (G_LIKELY (vertex != NULL))
12392 return g_slice_dup (ClutterVertex, vertex);
12398 * clutter_vertex_free:
12399 * @vertex: a #ClutterVertex
12401 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12406 clutter_vertex_free (ClutterVertex *vertex)
12408 if (G_UNLIKELY (vertex != NULL))
12409 g_slice_free (ClutterVertex, vertex);
12413 * clutter_vertex_equal:
12414 * @vertex_a: a #ClutterVertex
12415 * @vertex_b: a #ClutterVertex
12417 * Compares @vertex_a and @vertex_b for equality
12419 * Return value: %TRUE if the passed #ClutterVertex are equal
12424 clutter_vertex_equal (const ClutterVertex *vertex_a,
12425 const ClutterVertex *vertex_b)
12427 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12429 if (vertex_a == vertex_b)
12432 return vertex_a->x == vertex_b->x &&
12433 vertex_a->y == vertex_b->y &&
12434 vertex_a->z == vertex_b->z;
12438 clutter_vertex_progress (const GValue *a,
12443 const ClutterVertex *av = g_value_get_boxed (a);
12444 const ClutterVertex *bv = g_value_get_boxed (b);
12445 ClutterVertex res = { 0, };
12447 res.x = av->x + (bv->x - av->x) * progress;
12448 res.y = av->y + (bv->y - av->y) * progress;
12449 res.z = av->z + (bv->z - av->z) * progress;
12451 g_value_set_boxed (retval, &res);
12456 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12457 clutter_vertex_copy,
12458 clutter_vertex_free,
12459 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12462 * clutter_actor_is_rotated:
12463 * @self: a #ClutterActor
12465 * Checks whether any rotation is applied to the actor.
12467 * Return value: %TRUE if the actor is rotated.
12472 clutter_actor_is_rotated (ClutterActor *self)
12474 const ClutterTransformInfo *info;
12476 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12478 info = _clutter_actor_get_transform_info_or_defaults (self);
12480 if (info->rx_angle || info->ry_angle || info->rz_angle)
12487 * clutter_actor_is_scaled:
12488 * @self: a #ClutterActor
12490 * Checks whether the actor is scaled in either dimension.
12492 * Return value: %TRUE if the actor is scaled.
12497 clutter_actor_is_scaled (ClutterActor *self)
12499 const ClutterTransformInfo *info;
12501 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12503 info = _clutter_actor_get_transform_info_or_defaults (self);
12505 if (info->scale_x != 1.0 || info->scale_y != 1.0)
12512 _clutter_actor_get_stage_internal (ClutterActor *actor)
12514 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12515 actor = actor->priv->parent;
12521 * clutter_actor_get_stage:
12522 * @actor: a #ClutterActor
12524 * Retrieves the #ClutterStage where @actor is contained.
12526 * Return value: (transfer none) (type Clutter.Stage): the stage
12527 * containing the actor, or %NULL
12532 clutter_actor_get_stage (ClutterActor *actor)
12534 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12536 return _clutter_actor_get_stage_internal (actor);
12540 * clutter_actor_allocate_available_size:
12541 * @self: a #ClutterActor
12542 * @x: the actor's X coordinate
12543 * @y: the actor's Y coordinate
12544 * @available_width: the maximum available width, or -1 to use the
12545 * actor's natural width
12546 * @available_height: the maximum available height, or -1 to use the
12547 * actor's natural height
12548 * @flags: flags controlling the allocation
12550 * Allocates @self taking into account the #ClutterActor<!-- -->'s
12551 * preferred size, but limiting it to the maximum available width
12552 * and height provided.
12554 * This function will do the right thing when dealing with the
12555 * actor's request mode.
12557 * The implementation of this function is equivalent to:
12560 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12562 * clutter_actor_get_preferred_width (self, available_height,
12564 * &natural_width);
12565 * width = CLAMP (natural_width, min_width, available_width);
12567 * clutter_actor_get_preferred_height (self, width,
12569 * &natural_height);
12570 * height = CLAMP (natural_height, min_height, available_height);
12574 * clutter_actor_get_preferred_height (self, available_width,
12576 * &natural_height);
12577 * height = CLAMP (natural_height, min_height, available_height);
12579 * clutter_actor_get_preferred_width (self, height,
12581 * &natural_width);
12582 * width = CLAMP (natural_width, min_width, available_width);
12585 * box.x1 = x; box.y1 = y;
12586 * box.x2 = box.x1 + available_width;
12587 * box.y2 = box.y1 + available_height;
12588 * clutter_actor_allocate (self, &box, flags);
12591 * This function can be used by fluid layout managers to allocate
12592 * an actor's preferred size without making it bigger than the area
12593 * available for the container.
12598 clutter_actor_allocate_available_size (ClutterActor *self,
12601 gfloat available_width,
12602 gfloat available_height,
12603 ClutterAllocationFlags flags)
12605 ClutterActorPrivate *priv;
12606 gfloat width, height;
12607 gfloat min_width, min_height;
12608 gfloat natural_width, natural_height;
12609 ClutterActorBox box;
12611 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12615 width = height = 0.0;
12617 switch (priv->request_mode)
12619 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12620 clutter_actor_get_preferred_width (self, available_height,
12623 width = CLAMP (natural_width, min_width, available_width);
12625 clutter_actor_get_preferred_height (self, width,
12628 height = CLAMP (natural_height, min_height, available_height);
12631 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12632 clutter_actor_get_preferred_height (self, available_width,
12635 height = CLAMP (natural_height, min_height, available_height);
12637 clutter_actor_get_preferred_width (self, height,
12640 width = CLAMP (natural_width, min_width, available_width);
12647 box.x2 = box.x1 + width;
12648 box.y2 = box.y1 + height;
12649 clutter_actor_allocate (self, &box, flags);
12653 * clutter_actor_allocate_preferred_size:
12654 * @self: a #ClutterActor
12655 * @flags: flags controlling the allocation
12657 * Allocates the natural size of @self.
12659 * This function is a utility call for #ClutterActor implementations
12660 * that allocates the actor's preferred natural size. It can be used
12661 * by fixed layout managers (like #ClutterGroup or so called
12662 * 'composite actors') inside the ClutterActor::allocate
12663 * implementation to give each child exactly how much space it
12666 * This function is not meant to be used by applications. It is also
12667 * not meant to be used outside the implementation of the
12668 * ClutterActor::allocate virtual function.
12673 clutter_actor_allocate_preferred_size (ClutterActor *self,
12674 ClutterAllocationFlags flags)
12676 gfloat actor_x, actor_y;
12677 gfloat natural_width, natural_height;
12678 ClutterActorBox actor_box;
12680 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12682 actor_x = clutter_actor_get_x (self);
12683 actor_y = clutter_actor_get_y (self);
12685 clutter_actor_get_preferred_size (self,
12690 actor_box.x1 = actor_x;
12691 actor_box.y1 = actor_y;
12692 actor_box.x2 = actor_box.x1 + natural_width;
12693 actor_box.y2 = actor_box.y1 + natural_height;
12695 clutter_actor_allocate (self, &actor_box, flags);
12699 * clutter_actor_allocate_align_fill:
12700 * @self: a #ClutterActor
12701 * @box: a #ClutterActorBox, containing the available width and height
12702 * @x_align: the horizontal alignment, between 0 and 1
12703 * @y_align: the vertical alignment, between 0 and 1
12704 * @x_fill: whether the actor should fill horizontally
12705 * @y_fill: whether the actor should fill vertically
12706 * @flags: allocation flags to be passed to clutter_actor_allocate()
12708 * Allocates @self by taking into consideration the available allocation
12709 * area; an alignment factor on either axis; and whether the actor should
12710 * fill the allocation on either axis.
12712 * The @box should contain the available allocation width and height;
12713 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12714 * allocation will be offset by their value.
12716 * This function takes into consideration the geometry request specified by
12717 * the #ClutterActor:request-mode property, and the text direction.
12719 * This function is useful for fluid layout managers, like #ClutterBinLayout
12720 * or #ClutterTableLayout
12725 clutter_actor_allocate_align_fill (ClutterActor *self,
12726 const ClutterActorBox *box,
12731 ClutterAllocationFlags flags)
12733 ClutterActorPrivate *priv;
12734 ClutterActorBox allocation = { 0, };
12735 gfloat x_offset, y_offset;
12736 gfloat available_width, available_height;
12737 gfloat child_width, child_height;
12739 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12740 g_return_if_fail (box != NULL);
12741 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12742 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12746 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12747 clutter_actor_box_get_size (box, &available_width, &available_height);
12749 if (available_width < 0)
12750 available_width = 0;
12752 if (available_height < 0)
12753 available_height = 0;
12757 allocation.x1 = x_offset;
12758 allocation.x2 = allocation.x1 + available_width;
12763 allocation.y1 = y_offset;
12764 allocation.y2 = allocation.y1 + available_height;
12767 /* if we are filling horizontally and vertically then we're done */
12768 if (x_fill && y_fill)
12771 child_width = child_height = 0.0f;
12773 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12775 gfloat min_width, natural_width;
12776 gfloat min_height, natural_height;
12778 clutter_actor_get_preferred_width (self, available_height,
12782 child_width = CLAMP (natural_width, min_width, available_width);
12786 clutter_actor_get_preferred_height (self, child_width,
12790 child_height = CLAMP (natural_height, min_height, available_height);
12795 gfloat min_width, natural_width;
12796 gfloat min_height, natural_height;
12798 clutter_actor_get_preferred_height (self, available_width,
12802 child_height = CLAMP (natural_height, min_height, available_height);
12806 clutter_actor_get_preferred_width (self, child_height,
12810 child_width = CLAMP (natural_width, min_width, available_width);
12814 /* invert the horizontal alignment for RTL languages */
12815 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12816 x_align = 1.0 - x_align;
12820 allocation.x1 = x_offset
12821 + ((available_width - child_width) * x_align);
12822 allocation.x2 = allocation.x1 + child_width;
12827 allocation.y1 = y_offset
12828 + ((available_height - child_height) * y_align);
12829 allocation.y2 = allocation.y1 + child_height;
12833 clutter_actor_box_clamp_to_pixel (&allocation);
12834 clutter_actor_allocate (self, &allocation, flags);
12838 * clutter_actor_grab_key_focus:
12839 * @self: a #ClutterActor
12841 * Sets the key focus of the #ClutterStage including @self
12842 * to this #ClutterActor.
12847 clutter_actor_grab_key_focus (ClutterActor *self)
12849 ClutterActor *stage;
12851 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12853 stage = _clutter_actor_get_stage_internal (self);
12855 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12859 * clutter_actor_get_pango_context:
12860 * @self: a #ClutterActor
12862 * Retrieves the #PangoContext for @self. The actor's #PangoContext
12863 * is already configured using the appropriate font map, resolution
12864 * and font options.
12866 * Unlike clutter_actor_create_pango_context(), this context is owend
12867 * by the #ClutterActor and it will be updated each time the options
12868 * stored by the #ClutterBackend change.
12870 * You can use the returned #PangoContext to create a #PangoLayout
12871 * and render text using cogl_pango_render_layout() to reuse the
12872 * glyphs cache also used by Clutter.
12874 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
12875 * The returned #PangoContext is owned by the actor and should not be
12876 * unreferenced by the application code
12881 clutter_actor_get_pango_context (ClutterActor *self)
12883 ClutterActorPrivate *priv;
12885 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12889 if (priv->pango_context != NULL)
12890 return priv->pango_context;
12892 priv->pango_context = _clutter_context_get_pango_context ();
12893 g_object_ref (priv->pango_context);
12895 return priv->pango_context;
12899 * clutter_actor_create_pango_context:
12900 * @self: a #ClutterActor
12902 * Creates a #PangoContext for the given actor. The #PangoContext
12903 * is already configured using the appropriate font map, resolution
12904 * and font options.
12906 * See also clutter_actor_get_pango_context().
12908 * Return value: (transfer full): the newly created #PangoContext.
12909 * Use g_object_unref() on the returned value to deallocate its
12915 clutter_actor_create_pango_context (ClutterActor *self)
12917 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12919 return _clutter_context_create_pango_context ();
12923 * clutter_actor_create_pango_layout:
12924 * @self: a #ClutterActor
12925 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
12927 * Creates a new #PangoLayout from the same #PangoContext used
12928 * by the #ClutterActor. The #PangoLayout is already configured
12929 * with the font map, resolution and font options, and the
12932 * If you want to keep around a #PangoLayout created by this
12933 * function you will have to connect to the #ClutterBackend::font-changed
12934 * and #ClutterBackend::resolution-changed signals, and call
12935 * pango_layout_context_changed() in response to them.
12937 * Return value: (transfer full): the newly created #PangoLayout.
12938 * Use g_object_unref() when done
12943 clutter_actor_create_pango_layout (ClutterActor *self,
12946 PangoContext *context;
12947 PangoLayout *layout;
12949 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12951 context = clutter_actor_get_pango_context (self);
12952 layout = pango_layout_new (context);
12955 pango_layout_set_text (layout, text, -1);
12960 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
12961 * ClutterOffscreenEffect.
12964 _clutter_actor_set_opacity_override (ClutterActor *self,
12967 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12969 self->priv->opacity_override = opacity;
12973 _clutter_actor_get_opacity_override (ClutterActor *self)
12975 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
12977 return self->priv->opacity_override;
12980 /* Allows you to disable applying the actors model view transform during
12981 * a paint. Used by ClutterClone. */
12983 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
12986 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12988 self->priv->enable_model_view_transform = enable;
12992 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
12995 ClutterActorPrivate *priv;
12997 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13001 priv->enable_paint_unmapped = enable;
13003 if (priv->enable_paint_unmapped)
13005 /* Make sure that the parents of the widget are realized first;
13006 * otherwise checks in clutter_actor_update_map_state() will
13009 clutter_actor_realize (self);
13011 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13015 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13020 clutter_anchor_coord_get_units (ClutterActor *self,
13021 const AnchorCoord *coord,
13026 if (coord->is_fractional)
13028 gfloat actor_width, actor_height;
13030 clutter_actor_get_size (self, &actor_width, &actor_height);
13033 *x = actor_width * coord->v.fraction.x;
13036 *y = actor_height * coord->v.fraction.y;
13044 *x = coord->v.units.x;
13047 *y = coord->v.units.y;
13050 *z = coord->v.units.z;
13055 clutter_anchor_coord_set_units (AnchorCoord *coord,
13060 coord->is_fractional = FALSE;
13061 coord->v.units.x = x;
13062 coord->v.units.y = y;
13063 coord->v.units.z = z;
13066 static ClutterGravity
13067 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13069 if (coord->is_fractional)
13071 if (coord->v.fraction.x == 0.0)
13073 if (coord->v.fraction.y == 0.0)
13074 return CLUTTER_GRAVITY_NORTH_WEST;
13075 else if (coord->v.fraction.y == 0.5)
13076 return CLUTTER_GRAVITY_WEST;
13077 else if (coord->v.fraction.y == 1.0)
13078 return CLUTTER_GRAVITY_SOUTH_WEST;
13080 return CLUTTER_GRAVITY_NONE;
13082 else if (coord->v.fraction.x == 0.5)
13084 if (coord->v.fraction.y == 0.0)
13085 return CLUTTER_GRAVITY_NORTH;
13086 else if (coord->v.fraction.y == 0.5)
13087 return CLUTTER_GRAVITY_CENTER;
13088 else if (coord->v.fraction.y == 1.0)
13089 return CLUTTER_GRAVITY_SOUTH;
13091 return CLUTTER_GRAVITY_NONE;
13093 else if (coord->v.fraction.x == 1.0)
13095 if (coord->v.fraction.y == 0.0)
13096 return CLUTTER_GRAVITY_NORTH_EAST;
13097 else if (coord->v.fraction.y == 0.5)
13098 return CLUTTER_GRAVITY_EAST;
13099 else if (coord->v.fraction.y == 1.0)
13100 return CLUTTER_GRAVITY_SOUTH_EAST;
13102 return CLUTTER_GRAVITY_NONE;
13105 return CLUTTER_GRAVITY_NONE;
13108 return CLUTTER_GRAVITY_NONE;
13112 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
13113 ClutterGravity gravity)
13117 case CLUTTER_GRAVITY_NORTH:
13118 coord->v.fraction.x = 0.5;
13119 coord->v.fraction.y = 0.0;
13122 case CLUTTER_GRAVITY_NORTH_EAST:
13123 coord->v.fraction.x = 1.0;
13124 coord->v.fraction.y = 0.0;
13127 case CLUTTER_GRAVITY_EAST:
13128 coord->v.fraction.x = 1.0;
13129 coord->v.fraction.y = 0.5;
13132 case CLUTTER_GRAVITY_SOUTH_EAST:
13133 coord->v.fraction.x = 1.0;
13134 coord->v.fraction.y = 1.0;
13137 case CLUTTER_GRAVITY_SOUTH:
13138 coord->v.fraction.x = 0.5;
13139 coord->v.fraction.y = 1.0;
13142 case CLUTTER_GRAVITY_SOUTH_WEST:
13143 coord->v.fraction.x = 0.0;
13144 coord->v.fraction.y = 1.0;
13147 case CLUTTER_GRAVITY_WEST:
13148 coord->v.fraction.x = 0.0;
13149 coord->v.fraction.y = 0.5;
13152 case CLUTTER_GRAVITY_NORTH_WEST:
13153 coord->v.fraction.x = 0.0;
13154 coord->v.fraction.y = 0.0;
13157 case CLUTTER_GRAVITY_CENTER:
13158 coord->v.fraction.x = 0.5;
13159 coord->v.fraction.y = 0.5;
13163 coord->v.fraction.x = 0.0;
13164 coord->v.fraction.y = 0.0;
13168 coord->is_fractional = TRUE;
13172 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13174 if (coord->is_fractional)
13175 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13177 return (coord->v.units.x == 0.0
13178 && coord->v.units.y == 0.0
13179 && coord->v.units.z == 0.0);
13183 * clutter_actor_get_flags:
13184 * @self: a #ClutterActor
13186 * Retrieves the flags set on @self
13188 * Return value: a bitwise or of #ClutterActorFlags or 0
13193 clutter_actor_get_flags (ClutterActor *self)
13195 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13197 return self->flags;
13201 * clutter_actor_set_flags:
13202 * @self: a #ClutterActor
13203 * @flags: the flags to set
13205 * Sets @flags on @self
13207 * This function will emit notifications for the changed properties
13212 clutter_actor_set_flags (ClutterActor *self,
13213 ClutterActorFlags flags)
13215 ClutterActorFlags old_flags;
13217 gboolean was_reactive_set, reactive_set;
13218 gboolean was_realized_set, realized_set;
13219 gboolean was_mapped_set, mapped_set;
13220 gboolean was_visible_set, visible_set;
13222 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13224 if (self->flags == flags)
13227 obj = G_OBJECT (self);
13228 g_object_ref (obj);
13229 g_object_freeze_notify (obj);
13231 old_flags = self->flags;
13233 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13234 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13235 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
13236 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
13238 self->flags |= flags;
13240 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13241 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13242 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
13243 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
13245 if (reactive_set != was_reactive_set)
13246 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13248 if (realized_set != was_realized_set)
13249 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13251 if (mapped_set != was_mapped_set)
13252 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13254 if (visible_set != was_visible_set)
13255 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13257 g_object_thaw_notify (obj);
13258 g_object_unref (obj);
13262 * clutter_actor_unset_flags:
13263 * @self: a #ClutterActor
13264 * @flags: the flags to unset
13266 * Unsets @flags on @self
13268 * This function will emit notifications for the changed properties
13273 clutter_actor_unset_flags (ClutterActor *self,
13274 ClutterActorFlags flags)
13276 ClutterActorFlags old_flags;
13278 gboolean was_reactive_set, reactive_set;
13279 gboolean was_realized_set, realized_set;
13280 gboolean was_mapped_set, mapped_set;
13281 gboolean was_visible_set, visible_set;
13283 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13285 obj = G_OBJECT (self);
13286 g_object_freeze_notify (obj);
13288 old_flags = self->flags;
13290 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13291 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13292 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
13293 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
13295 self->flags &= ~flags;
13297 if (self->flags == old_flags)
13300 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13301 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13302 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
13303 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
13305 if (reactive_set != was_reactive_set)
13306 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13308 if (realized_set != was_realized_set)
13309 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13311 if (mapped_set != was_mapped_set)
13312 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13314 if (visible_set != was_visible_set)
13315 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13317 g_object_thaw_notify (obj);
13321 * clutter_actor_get_transformation_matrix:
13322 * @self: a #ClutterActor
13323 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13325 * Retrieves the transformations applied to @self relative to its
13331 clutter_actor_get_transformation_matrix (ClutterActor *self,
13332 CoglMatrix *matrix)
13334 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13336 cogl_matrix_init_identity (matrix);
13338 _clutter_actor_apply_modelview_transform (self, matrix);
13342 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13343 gboolean is_in_clone_paint)
13345 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13346 self->priv->in_clone_paint = is_in_clone_paint;
13350 * clutter_actor_is_in_clone_paint:
13351 * @self: a #ClutterActor
13353 * Checks whether @self is being currently painted by a #ClutterClone
13355 * This function is useful only inside the ::paint virtual function
13356 * implementations or within handlers for the #ClutterActor::paint
13359 * This function should not be used by applications
13361 * Return value: %TRUE if the #ClutterActor is currently being painted
13362 * by a #ClutterClone, and %FALSE otherwise
13367 clutter_actor_is_in_clone_paint (ClutterActor *self)
13369 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13371 return self->priv->in_clone_paint;
13375 set_direction_recursive (ClutterActor *actor,
13376 gpointer user_data)
13378 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13380 clutter_actor_set_text_direction (actor, text_dir);
13386 * clutter_actor_set_text_direction:
13387 * @self: a #ClutterActor
13388 * @text_dir: the text direction for @self
13390 * Sets the #ClutterTextDirection for an actor
13392 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13394 * If @self implements #ClutterContainer then this function will recurse
13395 * inside all the children of @self (including the internal ones).
13397 * Composite actors not implementing #ClutterContainer, or actors requiring
13398 * special handling when the text direction changes, should connect to
13399 * the #GObject::notify signal for the #ClutterActor:text-direction property
13404 clutter_actor_set_text_direction (ClutterActor *self,
13405 ClutterTextDirection text_dir)
13407 ClutterActorPrivate *priv;
13409 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13410 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13414 if (priv->text_direction != text_dir)
13416 priv->text_direction = text_dir;
13418 /* we need to emit the notify::text-direction first, so that
13419 * the sub-classes can catch that and do specific handling of
13420 * the text direction; see clutter_text_direction_changed_cb()
13421 * inside clutter-text.c
13423 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13425 _clutter_actor_foreach_child (self, set_direction_recursive,
13426 GINT_TO_POINTER (text_dir));
13428 clutter_actor_queue_relayout (self);
13433 _clutter_actor_set_has_pointer (ClutterActor *self,
13434 gboolean has_pointer)
13436 ClutterActorPrivate *priv = self->priv;
13438 if (priv->has_pointer != has_pointer)
13440 priv->has_pointer = has_pointer;
13442 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13447 * clutter_actor_get_text_direction:
13448 * @self: a #ClutterActor
13450 * Retrieves the value set using clutter_actor_set_text_direction()
13452 * If no text direction has been previously set, the default text
13453 * direction, as returned by clutter_get_default_text_direction(), will
13454 * be returned instead
13456 * Return value: the #ClutterTextDirection for the actor
13460 ClutterTextDirection
13461 clutter_actor_get_text_direction (ClutterActor *self)
13463 ClutterActorPrivate *priv;
13465 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13466 CLUTTER_TEXT_DIRECTION_LTR);
13470 /* if no direction has been set yet use the default */
13471 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13472 priv->text_direction = clutter_get_default_text_direction ();
13474 return priv->text_direction;
13478 * clutter_actor_push_internal:
13479 * @self: a #ClutterActor
13481 * Should be used by actors implementing the #ClutterContainer and with
13482 * internal children added through clutter_actor_set_parent(), for instance:
13486 * my_actor_init (MyActor *self)
13488 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
13490 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
13492 * /* calling clutter_actor_set_parent() now will result in
13493 * * the internal flag being set on a child of MyActor
13496 * /* internal child - a background texture */
13497 * self->priv->background_tex = clutter_texture_new ();
13498 * clutter_actor_set_parent (self->priv->background_tex,
13499 * CLUTTER_ACTOR (self));
13501 * /* internal child - a label */
13502 * self->priv->label = clutter_text_new ();
13503 * clutter_actor_set_parent (self->priv->label,
13504 * CLUTTER_ACTOR (self));
13506 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13508 * /* calling clutter_actor_set_parent() now will not result in
13509 * * the internal flag being set on a child of MyActor
13514 * This function will be used by Clutter to toggle an "internal child"
13515 * flag whenever clutter_actor_set_parent() is called; internal children
13516 * are handled differently by Clutter, specifically when destroying their
13519 * Call clutter_actor_pop_internal() when you finished adding internal
13522 * Nested calls to clutter_actor_push_internal() are allowed, but each
13523 * one must by followed by a clutter_actor_pop_internal() call.
13527 * Deprecated: 1.10: All children of an actor are accessible through
13528 * the #ClutterActor API, and #ClutterActor implements the
13529 * #ClutterContainer interface, so this function is only useful
13530 * for legacy containers overriding the default implementation.
13533 clutter_actor_push_internal (ClutterActor *self)
13535 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13537 self->priv->internal_child += 1;
13541 * clutter_actor_pop_internal:
13542 * @self: a #ClutterActor
13544 * Disables the effects of clutter_actor_push_internal().
13548 * Deprecated: 1.10: All children of an actor are accessible through
13549 * the #ClutterActor API. This function is only useful for legacy
13550 * containers overriding the default implementation of the
13551 * #ClutterContainer interface.
13554 clutter_actor_pop_internal (ClutterActor *self)
13556 ClutterActorPrivate *priv;
13558 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13562 if (priv->internal_child == 0)
13564 g_warning ("Mismatched %s: you need to call "
13565 "clutter_actor_push_composite() at least once before "
13566 "calling this function", G_STRFUNC);
13570 priv->internal_child -= 1;
13574 * clutter_actor_has_pointer:
13575 * @self: a #ClutterActor
13577 * Checks whether an actor contains the pointer of a
13578 * #ClutterInputDevice
13580 * Return value: %TRUE if the actor contains the pointer, and
13586 clutter_actor_has_pointer (ClutterActor *self)
13588 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13590 return self->priv->has_pointer;
13593 /* XXX: This is a workaround for not being able to break the ABI of
13594 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
13595 * clutter_actor_queue_clipped_redraw() for details.
13597 ClutterPaintVolume *
13598 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13600 return g_object_get_data (G_OBJECT (self),
13601 "-clutter-actor-queue-redraw-clip");
13605 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
13606 ClutterPaintVolume *clip)
13608 g_object_set_data (G_OBJECT (self),
13609 "-clutter-actor-queue-redraw-clip",
13614 * clutter_actor_has_allocation:
13615 * @self: a #ClutterActor
13617 * Checks if the actor has an up-to-date allocation assigned to
13618 * it. This means that the actor should have an allocation: it's
13619 * visible and has a parent. It also means that there is no
13620 * outstanding relayout request in progress for the actor or its
13621 * children (There might be other outstanding layout requests in
13622 * progress that will cause the actor to get a new allocation
13623 * when the stage is laid out, however).
13625 * If this function returns %FALSE, then the actor will normally
13626 * be allocated before it is next drawn on the screen.
13628 * Return value: %TRUE if the actor has an up-to-date allocation
13633 clutter_actor_has_allocation (ClutterActor *self)
13635 ClutterActorPrivate *priv;
13637 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13641 return priv->parent != NULL &&
13642 CLUTTER_ACTOR_IS_VISIBLE (self) &&
13643 !priv->needs_allocation;
13647 * clutter_actor_add_action:
13648 * @self: a #ClutterActor
13649 * @action: a #ClutterAction
13651 * Adds @action to the list of actions applied to @self
13653 * A #ClutterAction can only belong to one actor at a time
13655 * The #ClutterActor will hold a reference on @action until either
13656 * clutter_actor_remove_action() or clutter_actor_clear_actions()
13662 clutter_actor_add_action (ClutterActor *self,
13663 ClutterAction *action)
13665 ClutterActorPrivate *priv;
13667 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13668 g_return_if_fail (CLUTTER_IS_ACTION (action));
13672 if (priv->actions == NULL)
13674 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13675 priv->actions->actor = self;
13678 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13680 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13684 * clutter_actor_add_action_with_name:
13685 * @self: a #ClutterActor
13686 * @name: the name to set on the action
13687 * @action: a #ClutterAction
13689 * A convenience function for setting the name of a #ClutterAction
13690 * while adding it to the list of actions applied to @self
13692 * This function is the logical equivalent of:
13695 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13696 * clutter_actor_add_action (self, action);
13702 clutter_actor_add_action_with_name (ClutterActor *self,
13704 ClutterAction *action)
13706 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13707 g_return_if_fail (name != NULL);
13708 g_return_if_fail (CLUTTER_IS_ACTION (action));
13710 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13711 clutter_actor_add_action (self, action);
13715 * clutter_actor_remove_action:
13716 * @self: a #ClutterActor
13717 * @action: a #ClutterAction
13719 * Removes @action from the list of actions applied to @self
13721 * The reference held by @self on the #ClutterAction will be released
13726 clutter_actor_remove_action (ClutterActor *self,
13727 ClutterAction *action)
13729 ClutterActorPrivate *priv;
13731 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13732 g_return_if_fail (CLUTTER_IS_ACTION (action));
13736 if (priv->actions == NULL)
13739 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13741 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13745 * clutter_actor_remove_action_by_name:
13746 * @self: a #ClutterActor
13747 * @name: the name of the action to remove
13749 * Removes the #ClutterAction with the given name from the list
13750 * of actions applied to @self
13755 clutter_actor_remove_action_by_name (ClutterActor *self,
13758 ClutterActorPrivate *priv;
13759 ClutterActorMeta *meta;
13761 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13762 g_return_if_fail (name != NULL);
13766 if (priv->actions == NULL)
13769 meta = _clutter_meta_group_get_meta (priv->actions, name);
13773 _clutter_meta_group_remove_meta (priv->actions, meta);
13775 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13779 * clutter_actor_get_actions:
13780 * @self: a #ClutterActor
13782 * Retrieves the list of actions applied to @self
13784 * Return value: (transfer container) (element-type Clutter.Action): a copy
13785 * of the list of #ClutterAction<!-- -->s. The contents of the list are
13786 * owned by the #ClutterActor. Use g_list_free() to free the resources
13787 * allocated by the returned #GList
13792 clutter_actor_get_actions (ClutterActor *self)
13794 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13796 if (self->priv->actions == NULL)
13799 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13803 * clutter_actor_get_action:
13804 * @self: a #ClutterActor
13805 * @name: the name of the action to retrieve
13807 * Retrieves the #ClutterAction with the given name in the list
13808 * of actions applied to @self
13810 * Return value: (transfer none): a #ClutterAction for the given
13811 * name, or %NULL. The returned #ClutterAction is owned by the
13812 * actor and it should not be unreferenced directly
13817 clutter_actor_get_action (ClutterActor *self,
13820 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13821 g_return_val_if_fail (name != NULL, NULL);
13823 if (self->priv->actions == NULL)
13826 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13830 * clutter_actor_clear_actions:
13831 * @self: a #ClutterActor
13833 * Clears the list of actions applied to @self
13838 clutter_actor_clear_actions (ClutterActor *self)
13840 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13842 if (self->priv->actions == NULL)
13845 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13849 * clutter_actor_add_constraint:
13850 * @self: a #ClutterActor
13851 * @constraint: a #ClutterConstraint
13853 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13856 * The #ClutterActor will hold a reference on the @constraint until
13857 * either clutter_actor_remove_constraint() or
13858 * clutter_actor_clear_constraints() is called.
13863 clutter_actor_add_constraint (ClutterActor *self,
13864 ClutterConstraint *constraint)
13866 ClutterActorPrivate *priv;
13868 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13869 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13873 if (priv->constraints == NULL)
13875 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13876 priv->constraints->actor = self;
13879 _clutter_meta_group_add_meta (priv->constraints,
13880 CLUTTER_ACTOR_META (constraint));
13881 clutter_actor_queue_relayout (self);
13883 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13887 * clutter_actor_add_constraint_with_name:
13888 * @self: a #ClutterActor
13889 * @name: the name to set on the constraint
13890 * @constraint: a #ClutterConstraint
13892 * A convenience function for setting the name of a #ClutterConstraint
13893 * while adding it to the list of constraints applied to @self
13895 * This function is the logical equivalent of:
13898 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13899 * clutter_actor_add_constraint (self, constraint);
13905 clutter_actor_add_constraint_with_name (ClutterActor *self,
13907 ClutterConstraint *constraint)
13909 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13910 g_return_if_fail (name != NULL);
13911 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13913 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13914 clutter_actor_add_constraint (self, constraint);
13918 * clutter_actor_remove_constraint:
13919 * @self: a #ClutterActor
13920 * @constraint: a #ClutterConstraint
13922 * Removes @constraint from the list of constraints applied to @self
13924 * The reference held by @self on the #ClutterConstraint will be released
13929 clutter_actor_remove_constraint (ClutterActor *self,
13930 ClutterConstraint *constraint)
13932 ClutterActorPrivate *priv;
13934 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13935 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13939 if (priv->constraints == NULL)
13942 _clutter_meta_group_remove_meta (priv->constraints,
13943 CLUTTER_ACTOR_META (constraint));
13944 clutter_actor_queue_relayout (self);
13946 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13950 * clutter_actor_remove_constraint_by_name:
13951 * @self: a #ClutterActor
13952 * @name: the name of the constraint to remove
13954 * Removes the #ClutterConstraint with the given name from the list
13955 * of constraints applied to @self
13960 clutter_actor_remove_constraint_by_name (ClutterActor *self,
13963 ClutterActorPrivate *priv;
13964 ClutterActorMeta *meta;
13966 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13967 g_return_if_fail (name != NULL);
13971 if (priv->constraints == NULL)
13974 meta = _clutter_meta_group_get_meta (priv->constraints, name);
13978 _clutter_meta_group_remove_meta (priv->constraints, meta);
13979 clutter_actor_queue_relayout (self);
13983 * clutter_actor_get_constraints:
13984 * @self: a #ClutterActor
13986 * Retrieves the list of constraints applied to @self
13988 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
13989 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
13990 * owned by the #ClutterActor. Use g_list_free() to free the resources
13991 * allocated by the returned #GList
13996 clutter_actor_get_constraints (ClutterActor *self)
13998 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14000 if (self->priv->constraints == NULL)
14003 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14007 * clutter_actor_get_constraint:
14008 * @self: a #ClutterActor
14009 * @name: the name of the constraint to retrieve
14011 * Retrieves the #ClutterConstraint with the given name in the list
14012 * of constraints applied to @self
14014 * Return value: (transfer none): a #ClutterConstraint for the given
14015 * name, or %NULL. The returned #ClutterConstraint is owned by the
14016 * actor and it should not be unreferenced directly
14020 ClutterConstraint *
14021 clutter_actor_get_constraint (ClutterActor *self,
14024 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14025 g_return_val_if_fail (name != NULL, NULL);
14027 if (self->priv->constraints == NULL)
14030 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14034 * clutter_actor_clear_constraints:
14035 * @self: a #ClutterActor
14037 * Clears the list of constraints applied to @self
14042 clutter_actor_clear_constraints (ClutterActor *self)
14044 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14046 if (self->priv->constraints == NULL)
14049 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14051 clutter_actor_queue_relayout (self);
14055 * clutter_actor_set_clip_to_allocation:
14056 * @self: a #ClutterActor
14057 * @clip_set: %TRUE to apply a clip tracking the allocation
14059 * Sets whether @self should be clipped to the same size as its
14065 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14068 ClutterActorPrivate *priv;
14070 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14072 clip_set = !!clip_set;
14076 if (priv->clip_to_allocation != clip_set)
14078 priv->clip_to_allocation = clip_set;
14080 clutter_actor_queue_redraw (self);
14082 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14087 * clutter_actor_get_clip_to_allocation:
14088 * @self: a #ClutterActor
14090 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14092 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14097 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14099 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14101 return self->priv->clip_to_allocation;
14105 * clutter_actor_add_effect:
14106 * @self: a #ClutterActor
14107 * @effect: a #ClutterEffect
14109 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14111 * The #ClutterActor will hold a reference on the @effect until either
14112 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14118 clutter_actor_add_effect (ClutterActor *self,
14119 ClutterEffect *effect)
14121 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14122 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14124 _clutter_actor_add_effect_internal (self, effect);
14126 clutter_actor_queue_redraw (self);
14128 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14132 * clutter_actor_add_effect_with_name:
14133 * @self: a #ClutterActor
14134 * @name: the name to set on the effect
14135 * @effect: a #ClutterEffect
14137 * A convenience function for setting the name of a #ClutterEffect
14138 * while adding it to the list of effectss applied to @self
14140 * This function is the logical equivalent of:
14143 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14144 * clutter_actor_add_effect (self, effect);
14150 clutter_actor_add_effect_with_name (ClutterActor *self,
14152 ClutterEffect *effect)
14154 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14155 g_return_if_fail (name != NULL);
14156 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14158 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14159 clutter_actor_add_effect (self, effect);
14163 * clutter_actor_remove_effect:
14164 * @self: a #ClutterActor
14165 * @effect: a #ClutterEffect
14167 * Removes @effect from the list of effects applied to @self
14169 * The reference held by @self on the #ClutterEffect will be released
14174 clutter_actor_remove_effect (ClutterActor *self,
14175 ClutterEffect *effect)
14177 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14178 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14180 _clutter_actor_remove_effect_internal (self, effect);
14182 clutter_actor_queue_redraw (self);
14184 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14188 * clutter_actor_remove_effect_by_name:
14189 * @self: a #ClutterActor
14190 * @name: the name of the effect to remove
14192 * Removes the #ClutterEffect with the given name from the list
14193 * of effects applied to @self
14198 clutter_actor_remove_effect_by_name (ClutterActor *self,
14201 ClutterActorPrivate *priv;
14202 ClutterActorMeta *meta;
14204 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14205 g_return_if_fail (name != NULL);
14209 if (priv->effects == NULL)
14212 meta = _clutter_meta_group_get_meta (priv->effects, name);
14216 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14220 * clutter_actor_get_effects:
14221 * @self: a #ClutterActor
14223 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14225 * Return value: (transfer container) (element-type Clutter.Effect): a list
14226 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14227 * list are owned by Clutter and they should not be freed. You should
14228 * free the returned list using g_list_free() when done
14233 clutter_actor_get_effects (ClutterActor *self)
14235 ClutterActorPrivate *priv;
14237 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14241 if (priv->effects == NULL)
14244 return _clutter_meta_group_get_metas_no_internal (priv->effects);
14248 * clutter_actor_get_effect:
14249 * @self: a #ClutterActor
14250 * @name: the name of the effect to retrieve
14252 * Retrieves the #ClutterEffect with the given name in the list
14253 * of effects applied to @self
14255 * Return value: (transfer none): a #ClutterEffect for the given
14256 * name, or %NULL. The returned #ClutterEffect is owned by the
14257 * actor and it should not be unreferenced directly
14262 clutter_actor_get_effect (ClutterActor *self,
14265 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14266 g_return_val_if_fail (name != NULL, NULL);
14268 if (self->priv->effects == NULL)
14271 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14275 * clutter_actor_clear_effects:
14276 * @self: a #ClutterActor
14278 * Clears the list of effects applied to @self
14283 clutter_actor_clear_effects (ClutterActor *self)
14285 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14287 if (self->priv->effects == NULL)
14290 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14292 clutter_actor_queue_redraw (self);
14296 * clutter_actor_has_key_focus:
14297 * @self: a #ClutterActor
14299 * Checks whether @self is the #ClutterActor that has key focus
14301 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14306 clutter_actor_has_key_focus (ClutterActor *self)
14308 ClutterActor *stage;
14310 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14312 stage = _clutter_actor_get_stage_internal (self);
14316 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14320 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14321 ClutterPaintVolume *pv)
14323 ClutterActorPrivate *priv = self->priv;
14325 /* Actors are only expected to report a valid paint volume
14326 * while they have a valid allocation. */
14327 if (G_UNLIKELY (priv->needs_allocation))
14329 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14330 "Actor needs allocation",
14331 _clutter_actor_get_debug_name (self));
14335 /* Check if there are any handlers connected to the paint
14336 * signal. If there are then all bets are off for what the paint
14337 * volume for this actor might possibly be!
14339 * XXX: It's expected that this is going to end up being quite a
14340 * costly check to have to do here, but we haven't come up with
14341 * another solution that can reliably catch paint signal handlers at
14342 * the right time to either avoid artefacts due to invalid stage
14343 * clipping or due to incorrect culling.
14345 * Previously we checked in clutter_actor_paint(), but at that time
14346 * we may already be using a stage clip that could be derived from
14347 * an invalid paint-volume. We used to try and handle that by
14348 * queuing a follow up, unclipped, redraw but still the previous
14349 * checking wasn't enough to catch invalid volumes involved in
14350 * culling (considering that containers may derive their volume from
14351 * children that haven't yet been painted)
14353 * Longer term, improved solutions could be:
14354 * - Disallow painting in the paint signal, only allow using it
14355 * for tracking when paints happen. We can add another API that
14356 * allows monkey patching the paint of arbitrary actors but in a
14357 * more controlled way and that also supports modifying the
14359 * - If we could be notified somehow when signal handlers are
14360 * connected we wouldn't have to poll for handlers like this.
14362 if (g_signal_has_handler_pending (self,
14363 actor_signals[PAINT],
14367 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14368 "Actor has \"paint\" signal handlers",
14369 _clutter_actor_get_debug_name (self));
14373 _clutter_paint_volume_init_static (pv, self);
14375 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14377 clutter_paint_volume_free (pv);
14378 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14379 "Actor failed to report a volume",
14380 _clutter_actor_get_debug_name (self));
14384 /* since effects can modify the paint volume, we allow them to actually
14385 * do this by making get_paint_volume() "context sensitive"
14387 if (priv->effects != NULL)
14389 if (priv->current_effect != NULL)
14391 const GList *effects, *l;
14393 /* if we are being called from within the paint sequence of
14394 * an actor, get the paint volume up to the current effect
14396 effects = _clutter_meta_group_peek_metas (priv->effects);
14398 l != NULL || (l != NULL && l->data != priv->current_effect);
14401 if (!_clutter_effect_get_paint_volume (l->data, pv))
14403 clutter_paint_volume_free (pv);
14404 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14405 "Effect (%s) failed to report a volume",
14406 _clutter_actor_get_debug_name (self),
14407 _clutter_actor_meta_get_debug_name (l->data));
14414 const GList *effects, *l;
14416 /* otherwise, get the cumulative volume */
14417 effects = _clutter_meta_group_peek_metas (priv->effects);
14418 for (l = effects; l != NULL; l = l->next)
14419 if (!_clutter_effect_get_paint_volume (l->data, pv))
14421 clutter_paint_volume_free (pv);
14422 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14423 "Effect (%s) failed to report a volume",
14424 _clutter_actor_get_debug_name (self),
14425 _clutter_actor_meta_get_debug_name (l->data));
14434 /* The public clutter_actor_get_paint_volume API returns a const
14435 * pointer since we return a pointer directly to the cached
14436 * PaintVolume associated with the actor and don't want the user to
14437 * inadvertently modify it, but for internal uses we sometimes need
14438 * access to the same PaintVolume but need to apply some book-keeping
14439 * modifications to it so we don't want a const pointer.
14441 static ClutterPaintVolume *
14442 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14444 ClutterActorPrivate *priv;
14448 if (priv->paint_volume_valid)
14449 clutter_paint_volume_free (&priv->paint_volume);
14451 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14453 priv->paint_volume_valid = TRUE;
14454 return &priv->paint_volume;
14458 priv->paint_volume_valid = FALSE;
14464 * clutter_actor_get_paint_volume:
14465 * @self: a #ClutterActor
14467 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14468 * when a paint volume can't be determined.
14470 * The paint volume is defined as the 3D space occupied by an actor
14471 * when being painted.
14473 * This function will call the <function>get_paint_volume()</function>
14474 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14475 * should not usually care about overriding the default implementation,
14476 * unless they are, for instance: painting outside their allocation, or
14477 * actors with a depth factor (not in terms of #ClutterActor:depth but real
14480 * <note>2D actors overriding <function>get_paint_volume()</function>
14481 * ensure their volume has a depth of 0. (This will be true so long as
14482 * you don't call clutter_paint_volume_set_depth().)</note>
14484 * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14485 * or %NULL if no volume could be determined.
14489 const ClutterPaintVolume *
14490 clutter_actor_get_paint_volume (ClutterActor *self)
14492 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14494 return _clutter_actor_get_paint_volume_mutable (self);
14498 * clutter_actor_get_transformed_paint_volume:
14499 * @self: a #ClutterActor
14500 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14501 * (or %NULL for the stage)
14503 * Retrieves the 3D paint volume of an actor like
14504 * clutter_actor_get_paint_volume() does (Please refer to the
14505 * documentation of clutter_actor_get_paint_volume() for more
14506 * details.) and it additionally transforms the paint volume into the
14507 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14508 * is passed for @relative_to_ancestor)
14510 * This can be used by containers that base their paint volume on
14511 * the volume of their children. Such containers can query the
14512 * transformed paint volume of all of its children and union them
14513 * together using clutter_paint_volume_union().
14515 * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14516 * or %NULL if no volume could be determined.
14520 const ClutterPaintVolume *
14521 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14522 ClutterActor *relative_to_ancestor)
14524 const ClutterPaintVolume *volume;
14525 ClutterActor *stage;
14526 ClutterPaintVolume *transformed_volume;
14528 stage = _clutter_actor_get_stage_internal (self);
14529 if (G_UNLIKELY (stage == NULL))
14532 if (relative_to_ancestor == NULL)
14533 relative_to_ancestor = stage;
14535 volume = clutter_actor_get_paint_volume (self);
14536 if (volume == NULL)
14539 transformed_volume =
14540 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14542 _clutter_paint_volume_copy_static (volume, transformed_volume);
14544 _clutter_paint_volume_transform_relative (transformed_volume,
14545 relative_to_ancestor);
14547 return transformed_volume;
14551 * clutter_actor_get_paint_box:
14552 * @self: a #ClutterActor
14553 * @box: (out): return location for a #ClutterActorBox
14555 * Retrieves the paint volume of the passed #ClutterActor, and
14556 * transforms it into a 2D bounding box in stage coordinates.
14558 * This function is useful to determine the on screen area occupied by
14559 * the actor. The box is only an approximation and may often be
14560 * considerably larger due to the optimizations used to calculate the
14561 * box. The box is never smaller though, so it can reliably be used
14564 * There are times when a 2D paint box can't be determined, e.g.
14565 * because the actor isn't yet parented under a stage or because
14566 * the actor is unable to determine a paint volume.
14568 * Return value: %TRUE if a 2D paint box could be determined, else
14574 clutter_actor_get_paint_box (ClutterActor *self,
14575 ClutterActorBox *box)
14577 ClutterActor *stage;
14578 ClutterPaintVolume *pv;
14580 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14581 g_return_val_if_fail (box != NULL, FALSE);
14583 stage = _clutter_actor_get_stage_internal (self);
14584 if (G_UNLIKELY (!stage))
14587 pv = _clutter_actor_get_paint_volume_mutable (self);
14588 if (G_UNLIKELY (!pv))
14591 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14597 * clutter_actor_has_overlaps:
14598 * @self: A #ClutterActor
14600 * Asks the actor's implementation whether it may contain overlapping
14603 * For example; Clutter may use this to determine whether the painting
14604 * should be redirected to an offscreen buffer to correctly implement
14605 * the opacity property.
14607 * Custom actors can override the default response by implementing the
14608 * #ClutterActor <function>has_overlaps</function> virtual function. See
14609 * clutter_actor_set_offscreen_redirect() for more information.
14611 * Return value: %TRUE if the actor may have overlapping primitives, and
14617 clutter_actor_has_overlaps (ClutterActor *self)
14619 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14621 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14625 * clutter_actor_has_effects:
14626 * @self: A #ClutterActor
14628 * Returns whether the actor has any effects applied.
14630 * Return value: %TRUE if the actor has any effects,
14636 clutter_actor_has_effects (ClutterActor *self)
14638 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14640 if (self->priv->effects == NULL)
14643 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14647 * clutter_actor_has_constraints:
14648 * @self: A #ClutterActor
14650 * Returns whether the actor has any constraints applied.
14652 * Return value: %TRUE if the actor has any constraints,
14658 clutter_actor_has_constraints (ClutterActor *self)
14660 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14662 return self->priv->constraints != NULL;
14666 * clutter_actor_has_actions:
14667 * @self: A #ClutterActor
14669 * Returns whether the actor has any actions applied.
14671 * Return value: %TRUE if the actor has any actions,
14677 clutter_actor_has_actions (ClutterActor *self)
14679 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14681 return self->priv->actions != NULL;
14685 * clutter_actor_get_n_children:
14686 * @self: a #ClutterActor
14688 * Retrieves the number of children of @self.
14690 * Return value: the number of children of an actor
14695 clutter_actor_get_n_children (ClutterActor *self)
14697 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14699 return self->priv->n_children;
14703 * clutter_actor_get_child_at_index:
14704 * @self: a #ClutterActor
14705 * @index_: the position in the list of children
14707 * Retrieves the actor at the given @index_ inside the list of
14708 * children of @self.
14710 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14715 clutter_actor_get_child_at_index (ClutterActor *self,
14718 ClutterActor *iter;
14721 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14722 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14724 for (iter = self->priv->first_child, i = 0;
14725 iter != NULL && i < index_;
14726 iter = iter->priv->next_sibling, i += 1)
14733 * _clutter_actor_foreach_child:
14734 * @actor: The actor whos children you want to iterate
14735 * @callback: The function to call for each child
14736 * @user_data: Private data to pass to @callback
14738 * Calls a given @callback once for each child of the specified @actor and
14739 * passing the @user_data pointer each time.
14741 * Return value: returns %TRUE if all children were iterated, else
14742 * %FALSE if a callback broke out of iteration early.
14745 _clutter_actor_foreach_child (ClutterActor *self,
14746 ClutterForeachCallback callback,
14747 gpointer user_data)
14749 ClutterActorPrivate *priv = self->priv;
14750 ClutterActor *iter;
14753 for (cont = TRUE, iter = priv->first_child;
14754 cont && iter != NULL;
14755 iter = iter->priv->next_sibling)
14757 cont = callback (iter, user_data);
14763 /* For debugging purposes this gives us a simple way to print out
14764 * the scenegraph e.g in gdb using:
14766 * _clutter_actor_traverse (stage,
14768 * _clutter_debug_print_actor_cb,
14773 ClutterActorTraverseVisitFlags
14774 _clutter_debug_print_actor_cb (ClutterActor *actor,
14778 g_print ("%*s%s:%p\n",
14780 _clutter_actor_get_debug_name (actor),
14783 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14787 _clutter_actor_traverse_breadth (ClutterActor *actor,
14788 ClutterTraverseCallback callback,
14789 gpointer user_data)
14791 GQueue *queue = g_queue_new ();
14792 ClutterActor dummy;
14793 int current_depth = 0;
14795 g_queue_push_tail (queue, actor);
14796 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14798 while ((actor = g_queue_pop_head (queue)))
14800 ClutterActorTraverseVisitFlags flags;
14802 if (actor == &dummy)
14805 g_queue_push_tail (queue, &dummy);
14809 flags = callback (actor, current_depth, user_data);
14810 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14812 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14814 ClutterActor *iter;
14816 for (iter = actor->priv->first_child;
14818 iter = iter->priv->next_sibling)
14820 g_queue_push_tail (queue, iter);
14825 g_queue_free (queue);
14828 static ClutterActorTraverseVisitFlags
14829 _clutter_actor_traverse_depth (ClutterActor *actor,
14830 ClutterTraverseCallback before_children_callback,
14831 ClutterTraverseCallback after_children_callback,
14833 gpointer user_data)
14835 ClutterActorTraverseVisitFlags flags;
14837 flags = before_children_callback (actor, current_depth, user_data);
14838 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14839 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14841 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14843 ClutterActor *iter;
14845 for (iter = actor->priv->first_child;
14847 iter = iter->priv->next_sibling)
14849 flags = _clutter_actor_traverse_depth (iter,
14850 before_children_callback,
14851 after_children_callback,
14855 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14856 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14860 if (after_children_callback)
14861 return after_children_callback (actor, current_depth, user_data);
14863 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14866 /* _clutter_actor_traverse:
14867 * @actor: The actor to start traversing the graph from
14868 * @flags: These flags may affect how the traversal is done
14869 * @before_children_callback: A function to call before visiting the
14870 * children of the current actor.
14871 * @after_children_callback: A function to call after visiting the
14872 * children of the current actor. (Ignored if
14873 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
14874 * @user_data: The private data to pass to the callbacks
14876 * Traverses the scenegraph starting at the specified @actor and
14877 * descending through all its children and its children's children.
14878 * For each actor traversed @before_children_callback and
14879 * @after_children_callback are called with the specified
14880 * @user_data, before and after visiting that actor's children.
14882 * The callbacks can return flags that affect the ongoing traversal
14883 * such as by skipping over an actors children or bailing out of
14884 * any further traversing.
14887 _clutter_actor_traverse (ClutterActor *actor,
14888 ClutterActorTraverseFlags flags,
14889 ClutterTraverseCallback before_children_callback,
14890 ClutterTraverseCallback after_children_callback,
14891 gpointer user_data)
14893 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
14894 _clutter_actor_traverse_breadth (actor,
14895 before_children_callback,
14897 else /* DEPTH_FIRST */
14898 _clutter_actor_traverse_depth (actor,
14899 before_children_callback,
14900 after_children_callback,
14901 0, /* start depth */
14906 on_layout_manager_changed (ClutterLayoutManager *manager,
14907 ClutterActor *self)
14909 clutter_actor_queue_relayout (self);
14913 * clutter_actor_set_layout_manager:
14914 * @self: a #ClutterActor
14915 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
14917 * Sets the #ClutterLayoutManager delegate object that will be used to
14918 * lay out the children of @self.
14920 * The #ClutterActor will take a reference on the passed @manager which
14921 * will be released either when the layout manager is removed, or when
14922 * the actor is destroyed.
14927 clutter_actor_set_layout_manager (ClutterActor *self,
14928 ClutterLayoutManager *manager)
14930 ClutterActorPrivate *priv;
14932 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14933 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
14937 if (priv->layout_manager != NULL)
14939 g_signal_handlers_disconnect_by_func (priv->layout_manager,
14940 G_CALLBACK (on_layout_manager_changed),
14942 clutter_layout_manager_set_container (priv->layout_manager, NULL);
14943 g_object_unref (priv->layout_manager);
14946 priv->layout_manager = manager;
14948 if (priv->layout_manager != NULL)
14950 g_object_ref_sink (priv->layout_manager);
14951 clutter_layout_manager_set_container (priv->layout_manager,
14952 CLUTTER_CONTAINER (self));
14953 g_signal_connect (priv->layout_manager, "layout-changed",
14954 G_CALLBACK (on_layout_manager_changed),
14958 clutter_actor_queue_relayout (self);
14960 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
14964 * clutter_actor_get_layout_manager:
14965 * @self: a #ClutterActor
14967 * Retrieves the #ClutterLayoutManager used by @self.
14969 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
14974 ClutterLayoutManager *
14975 clutter_actor_get_layout_manager (ClutterActor *self)
14977 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14979 return self->priv->layout_manager;
14982 static const ClutterLayoutInfo default_layout_info = {
14985 { 0, 0, 0, 0 }, /* margin */
14986 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
14987 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
14988 0.f, 0.f, /* min_width, natural_width */
14989 0.f, 0.f, /* natual_width, natural_height */
14993 layout_info_free (gpointer data)
14995 if (G_LIKELY (data != NULL))
14996 g_slice_free (ClutterLayoutInfo, data);
15000 * _clutter_actor_get_layout_info:
15001 * @self: a #ClutterActor
15003 * Retrieves a pointer to the ClutterLayoutInfo structure.
15005 * If the actor does not have a ClutterLayoutInfo associated to it, one
15006 * will be created and initialized to the default values.
15008 * This function should be used for setters.
15010 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15013 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15015 ClutterLayoutInfo *
15016 _clutter_actor_get_layout_info (ClutterActor *self)
15018 ClutterLayoutInfo *retval;
15020 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15021 if (retval == NULL)
15023 retval = g_slice_new (ClutterLayoutInfo);
15025 *retval = default_layout_info;
15027 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15036 * _clutter_actor_get_layout_info_or_defaults:
15037 * @self: a #ClutterActor
15039 * Retrieves the ClutterLayoutInfo structure associated to an actor.
15041 * If the actor does not have a ClutterLayoutInfo structure associated to it,
15042 * then the default structure will be returned.
15044 * This function should only be used for getters.
15046 * Return value: a const pointer to the ClutterLayoutInfo structure
15048 const ClutterLayoutInfo *
15049 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15051 const ClutterLayoutInfo *info;
15053 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15055 return &default_layout_info;
15061 * clutter_actor_set_x_align:
15062 * @self: a #ClutterActor
15063 * @x_align: the horizontal alignment policy
15065 * Sets the horizontal alignment policy of a #ClutterActor, in case the
15066 * actor received extra horizontal space.
15068 * See also the #ClutterActor:x-align property.
15073 clutter_actor_set_x_align (ClutterActor *self,
15074 ClutterActorAlign x_align)
15076 ClutterLayoutInfo *info;
15078 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15080 info = _clutter_actor_get_layout_info (self);
15082 if (info->x_align != x_align)
15084 info->x_align = x_align;
15086 clutter_actor_queue_relayout (self);
15088 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15093 * clutter_actor_get_x_align:
15094 * @self: a #ClutterActor
15096 * Retrieves the horizontal alignment policy set using
15097 * clutter_actor_set_x_align().
15099 * Return value: the horizontal alignment policy.
15104 clutter_actor_get_x_align (ClutterActor *self)
15106 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15108 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15112 * clutter_actor_set_y_align:
15113 * @self: a #ClutterActor
15114 * @y_align: the vertical alignment policy
15116 * Sets the vertical alignment policy of a #ClutterActor, in case the
15117 * actor received extra vertical space.
15119 * See also the #ClutterActor:y-align property.
15124 clutter_actor_set_y_align (ClutterActor *self,
15125 ClutterActorAlign y_align)
15127 ClutterLayoutInfo *info;
15129 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15131 info = _clutter_actor_get_layout_info (self);
15133 if (info->y_align != y_align)
15135 info->y_align = y_align;
15137 clutter_actor_queue_relayout (self);
15139 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15144 * clutter_actor_get_y_align:
15145 * @self: a #ClutterActor
15147 * Retrieves the vertical alignment policy set using
15148 * clutter_actor_set_y_align().
15150 * Return value: the vertical alignment policy.
15155 clutter_actor_get_y_align (ClutterActor *self)
15157 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15159 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15164 * clutter_margin_new:
15166 * Creates a new #ClutterMargin.
15168 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15169 * clutter_margin_free() to free the resources associated with it when
15175 clutter_margin_new (void)
15177 return g_slice_new0 (ClutterMargin);
15181 * clutter_margin_copy:
15182 * @margin_: a #ClutterMargin
15184 * Creates a new #ClutterMargin and copies the contents of @margin_ into
15185 * the newly created structure.
15187 * Return value: (transfer full): a copy of the #ClutterMargin.
15192 clutter_margin_copy (const ClutterMargin *margin_)
15194 if (G_LIKELY (margin_ != NULL))
15195 return g_slice_dup (ClutterMargin, margin_);
15201 * clutter_margin_free:
15202 * @margin_: a #ClutterMargin
15204 * Frees the resources allocated by clutter_margin_new() and
15205 * clutter_margin_copy().
15210 clutter_margin_free (ClutterMargin *margin_)
15212 if (G_LIKELY (margin_ != NULL))
15213 g_slice_free (ClutterMargin, margin_);
15216 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15217 clutter_margin_copy,
15218 clutter_margin_free)
15221 * clutter_actor_set_margin:
15222 * @self: a #ClutterActor
15223 * @margin: a #ClutterMargin
15225 * Sets all the components of the margin of a #ClutterActor.
15230 clutter_actor_set_margin (ClutterActor *self,
15231 const ClutterMargin *margin)
15233 ClutterLayoutInfo *info;
15237 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15238 g_return_if_fail (margin != NULL);
15240 obj = G_OBJECT (self);
15243 g_object_freeze_notify (obj);
15245 info = _clutter_actor_get_layout_info (self);
15247 if (info->margin.top != margin->top)
15249 info->margin.top = margin->top;
15250 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15254 if (info->margin.right != margin->right)
15256 info->margin.right = margin->right;
15257 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15261 if (info->margin.bottom != margin->bottom)
15263 info->margin.bottom = margin->bottom;
15264 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15268 if (info->margin.left != margin->left)
15270 info->margin.left = margin->left;
15271 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15276 clutter_actor_queue_relayout (self);
15278 g_object_thaw_notify (obj);
15282 * clutter_actor_get_margin:
15283 * @self: a #ClutterActor
15284 * @margin: (out caller-allocates): return location for a #ClutterMargin
15286 * Retrieves all the components of the margin of a #ClutterActor.
15291 clutter_actor_get_margin (ClutterActor *self,
15292 ClutterMargin *margin)
15294 const ClutterLayoutInfo *info;
15296 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15297 g_return_if_fail (margin != NULL);
15299 info = _clutter_actor_get_layout_info_or_defaults (self);
15301 *margin = info->margin;
15305 * clutter_actor_set_margin_top:
15306 * @self: a #ClutterActor
15307 * @margin: the top margin
15309 * Sets the margin from the top of a #ClutterActor.
15314 clutter_actor_set_margin_top (ClutterActor *self,
15317 ClutterLayoutInfo *info;
15319 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15320 g_return_if_fail (margin >= 0.f);
15322 info = _clutter_actor_get_layout_info (self);
15324 if (info->margin.top == margin)
15327 info->margin.top = margin;
15329 clutter_actor_queue_relayout (self);
15331 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15335 * clutter_actor_get_margin_top:
15336 * @self: a #ClutterActor
15338 * Retrieves the top margin of a #ClutterActor.
15340 * Return value: the top margin
15345 clutter_actor_get_margin_top (ClutterActor *self)
15347 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15349 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15353 * clutter_actor_set_margin_bottom:
15354 * @self: a #ClutterActor
15355 * @margin: the bottom margin
15357 * Sets the margin from the bottom of a #ClutterActor.
15362 clutter_actor_set_margin_bottom (ClutterActor *self,
15365 ClutterLayoutInfo *info;
15367 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15368 g_return_if_fail (margin >= 0.f);
15370 info = _clutter_actor_get_layout_info (self);
15372 if (info->margin.bottom == margin)
15375 info->margin.bottom = margin;
15377 clutter_actor_queue_relayout (self);
15379 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15383 * clutter_actor_get_margin_bottom:
15384 * @self: a #ClutterActor
15386 * Retrieves the bottom margin of a #ClutterActor.
15388 * Return value: the bottom margin
15393 clutter_actor_get_margin_bottom (ClutterActor *self)
15395 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15397 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15401 * clutter_actor_set_margin_left:
15402 * @self: a #ClutterActor
15403 * @margin: the left margin
15405 * Sets the margin from the left of a #ClutterActor.
15410 clutter_actor_set_margin_left (ClutterActor *self,
15413 ClutterLayoutInfo *info;
15415 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15416 g_return_if_fail (margin >= 0.f);
15418 info = _clutter_actor_get_layout_info (self);
15420 if (info->margin.left == margin)
15423 info->margin.left = margin;
15425 clutter_actor_queue_relayout (self);
15427 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15431 * clutter_actor_get_margin_left:
15432 * @self: a #ClutterActor
15434 * Retrieves the left margin of a #ClutterActor.
15436 * Return value: the left margin
15441 clutter_actor_get_margin_left (ClutterActor *self)
15443 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15445 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15449 * clutter_actor_set_margin_right:
15450 * @self: a #ClutterActor
15451 * @margin: the right margin
15453 * Sets the margin from the right of a #ClutterActor.
15458 clutter_actor_set_margin_right (ClutterActor *self,
15461 ClutterLayoutInfo *info;
15463 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15464 g_return_if_fail (margin >= 0.f);
15466 info = _clutter_actor_get_layout_info (self);
15468 if (info->margin.right == margin)
15471 info->margin.right = margin;
15473 clutter_actor_queue_relayout (self);
15475 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15479 * clutter_actor_get_margin_right:
15480 * @self: a #ClutterActor
15482 * Retrieves the right margin of a #ClutterActor.
15484 * Return value: the right margin
15489 clutter_actor_get_margin_right (ClutterActor *self)
15491 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15493 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15497 * clutter_actor_set_background_color:
15498 * @self: a #ClutterActor
15499 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15502 * Sets the background color of a #ClutterActor.
15504 * The background color will be used to cover the whole allocation of the
15505 * actor. The default background color of an actor is transparent.
15507 * To check whether an actor has a background color, you can use the
15508 * #ClutterActor:background-color-set actor property.
15513 clutter_actor_set_background_color (ClutterActor *self,
15514 const ClutterColor *color)
15516 ClutterActorPrivate *priv;
15518 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15524 priv->bg_color_set = FALSE;
15525 g_object_notify_by_pspec (G_OBJECT (self),
15526 obj_props[PROP_BACKGROUND_COLOR_SET]);
15530 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15533 priv->bg_color = *color;
15534 priv->bg_color_set = TRUE;
15536 clutter_actor_queue_redraw (self);
15538 g_object_notify_by_pspec (G_OBJECT (self),
15539 obj_props[PROP_BACKGROUND_COLOR_SET]);
15540 g_object_notify_by_pspec (G_OBJECT (self),
15541 obj_props[PROP_BACKGROUND_COLOR]);
15545 * clutter_actor_get_background_color:
15546 * @self: a #ClutterActor
15547 * @color: (out caller-allocates): return location for a #ClutterColor
15549 * Retrieves the color set using clutter_actor_set_background_color().
15554 clutter_actor_get_background_color (ClutterActor *self,
15555 ClutterColor *color)
15557 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15558 g_return_if_fail (color != NULL);
15560 *color = self->priv->bg_color;
15564 * clutter_actor_get_previous_sibling:
15565 * @self: a #ClutterActor
15567 * Retrieves the sibling of @self that comes before it in the list
15568 * of children of @self's parent.
15570 * The returned pointer is only valid until the scene graph changes; it
15571 * is not safe to modify the list of children of @self while iterating
15574 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15579 clutter_actor_get_previous_sibling (ClutterActor *self)
15581 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15583 return self->priv->prev_sibling;
15587 * clutter_actor_get_next_sibling:
15588 * @self: a #ClutterActor
15590 * Retrieves the sibling of @self that comes after it in the list
15591 * of children of @self's parent.
15593 * The returned pointer is only valid until the scene graph changes; it
15594 * is not safe to modify the list of children of @self while iterating
15597 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15602 clutter_actor_get_next_sibling (ClutterActor *self)
15604 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15606 return self->priv->next_sibling;
15610 * clutter_actor_get_first_child:
15611 * @self: a #ClutterActor
15613 * Retrieves the first child of @self.
15615 * The returned pointer is only valid until the scene graph changes; it
15616 * is not safe to modify the list of children of @self while iterating
15619 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15624 clutter_actor_get_first_child (ClutterActor *self)
15626 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15628 return self->priv->first_child;
15632 * clutter_actor_get_last_child:
15633 * @self: a #ClutterActor
15635 * Retrieves the last child of @self.
15637 * The returned pointer is only valid until the scene graph changes; it
15638 * is not safe to modify the list of children of @self while iterating
15641 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15646 clutter_actor_get_last_child (ClutterActor *self)
15648 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15650 return self->priv->last_child;
15653 /* easy way to have properly named fields instead of the dummy ones
15654 * we use in the public structure
15656 typedef struct _RealActorIter
15658 ClutterActor *root; /* dummy1 */
15659 ClutterActor *current; /* dummy2 */
15660 gpointer padding_1; /* dummy3 */
15661 gint age; /* dummy4 */
15662 gpointer padding_2; /* dummy5 */
15666 * clutter_actor_iter_init:
15667 * @iter: a #ClutterActorIter
15668 * @root: a #ClutterActor
15670 * Initializes a #ClutterActorIter, which can then be used to iterate
15671 * efficiently over a section of the scene graph, and associates it
15674 * Modifying the scene graph section that contains @root will invalidate
15678 * ClutterActorIter iter;
15679 * ClutterActor *child;
15681 * clutter_actor_iter_init (&iter, container);
15682 * while (clutter_actor_iter_next (&iter, &child))
15684 * /* do something with child */
15691 clutter_actor_iter_init (ClutterActorIter *iter,
15692 ClutterActor *root)
15694 RealActorIter *ri = (RealActorIter *) iter;
15696 g_return_if_fail (iter != NULL);
15697 g_return_if_fail (CLUTTER_IS_ACTOR (root));
15700 ri->current = NULL;
15701 ri->age = root->priv->age;
15705 * clutter_actor_iter_next:
15706 * @iter: a #ClutterActorIter
15707 * @child: (out): return location for a #ClutterActor
15709 * Advances the @iter and retrieves the next child of the root #ClutterActor
15710 * that was used to initialize the #ClutterActorIterator.
15712 * If the iterator can advance, this function returns %TRUE and sets the
15715 * If the iterator cannot advance, this function returns %FALSE, and
15716 * the contents of @child are undefined.
15718 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15723 clutter_actor_iter_next (ClutterActorIter *iter,
15724 ClutterActor **child)
15726 RealActorIter *ri = (RealActorIter *) iter;
15728 g_return_val_if_fail (iter != NULL, FALSE);
15729 g_return_val_if_fail (ri->root != NULL, FALSE);
15730 #ifndef G_DISABLE_ASSERT
15731 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15734 if (ri->current == NULL)
15735 ri->current = ri->root->priv->first_child;
15737 ri->current = ri->current->priv->next_sibling;
15740 *child = ri->current;
15742 return ri->current != NULL;
15746 * clutter_actor_iter_prev:
15747 * @iter: a #ClutterActorIter
15748 * @child: (out): return location for a #ClutterActor
15750 * Advances the @iter and retrieves the previous child of the root
15751 * #ClutterActor that was used to initialize the #ClutterActorIterator.
15753 * If the iterator can advance, this function returns %TRUE and sets the
15756 * If the iterator cannot advance, this function returns %FALSE, and
15757 * the contents of @child are undefined.
15759 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15764 clutter_actor_iter_prev (ClutterActorIter *iter,
15765 ClutterActor **child)
15767 RealActorIter *ri = (RealActorIter *) iter;
15769 g_return_val_if_fail (iter != NULL, FALSE);
15770 g_return_val_if_fail (ri->root != NULL, FALSE);
15771 #ifndef G_DISABLE_ASSERT
15772 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15775 if (ri->current == NULL)
15776 ri->current = ri->root->priv->last_child;
15778 ri->current = ri->current->priv->prev_sibling;
15781 *child = ri->current;
15783 return ri->current != NULL;
15787 * clutter_actor_iter_remove:
15788 * @iter: a #ClutterActorIter
15790 * Safely removes the #ClutterActor currently pointer to by the iterator
15793 * This function can only be called after clutter_actor_iter_next() or
15794 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15795 * than once for the same actor.
15797 * This function will call clutter_actor_remove_child() internally.
15802 clutter_actor_iter_remove (ClutterActorIter *iter)
15804 RealActorIter *ri = (RealActorIter *) iter;
15807 g_return_if_fail (iter != NULL);
15808 g_return_if_fail (ri->root != NULL);
15809 #ifndef G_DISABLE_ASSERT
15810 g_return_if_fail (ri->age == ri->root->priv->age);
15812 g_return_if_fail (ri->current != NULL);
15818 ri->current = cur->priv->prev_sibling;
15820 clutter_actor_remove_child_internal (ri->root, cur,
15821 REMOVE_CHILD_DEFAULT_FLAGS);
15828 * clutter_actor_iter_destroy:
15829 * @iter: a #ClutterActorIter
15831 * Safely destroys the #ClutterActor currently pointer to by the iterator
15834 * This function can only be called after clutter_actor_iter_next() or
15835 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15836 * than once for the same actor.
15838 * This function will call clutter_actor_destroy() internally.
15843 clutter_actor_iter_destroy (ClutterActorIter *iter)
15845 RealActorIter *ri = (RealActorIter *) iter;
15848 g_return_if_fail (iter != NULL);
15849 g_return_if_fail (ri->root != NULL);
15850 #ifndef G_DISABLE_ASSERT
15851 g_return_if_fail (ri->age == ri->root->priv->age);
15853 g_return_if_fail (ri->current != NULL);
15859 ri->current = cur->priv->prev_sibling;
15861 clutter_actor_destroy (cur);