4 * An OpenGL based 'interactive canvas' library.
6 * Authored By Matthew Allum <mallum@openedhand.com>
8 * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9 * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
26 * SECTION:clutter-actor
27 * @short_description: The basic element of the scene graph
29 * The ClutterActor class is the basic element of the scene graph in Clutter,
30 * and it encapsulates the position, size, and transformations of a node in
33 * <refsect2 id="ClutterActor-transformations">
34 * <title>Actor transformations</title>
35 * <para>Each actor can be transformed using methods like
36 * clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37 * in which the transformations are applied is decided by Clutter and it is
38 * the following:</para>
40 * <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41 * <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42 * <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43 * <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44 * <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45 * <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46 * <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
50 * <refsect2 id="ClutterActor-geometry">
51 * <title>Modifying an actor's geometry</title>
52 * <para>Each actor has a bounding box, called #ClutterActor:allocation
53 * which is either set by its parent or explicitly through the
54 * clutter_actor_set_position() and clutter_actor_set_size() methods.
55 * Each actor also has an implicit preferred size.</para>
56 * <para>An actor’s preferred size can be defined by any subclass by
57 * overriding the #ClutterActorClass.get_preferred_width() and the
58 * #ClutterActorClass.get_preferred_height() virtual functions, or it can
59 * be explicitly set by using clutter_actor_set_width() and
60 * clutter_actor_set_height().</para>
61 * <para>An actor’s position can be set explicitly by using
62 * clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63 * relative to the origin of the actor’s parent.</para>
66 * <refsect2 id="ClutterActor-children">
67 * <title>Managing actor children</title>
68 * <para>Each actor can have multiple children, by calling
69 * clutter_actor_add_child() to add a new child actor, and
70 * clutter_actor_remove_child() to remove an existing child. #ClutterActor
71 * will hold a reference on each child actor, which will be released when
72 * the child is removed from its parent, or destroyed using
73 * clutter_actor_destroy().</para>
74 * <informalexample><programlisting>
75 * ClutterActor *actor = clutter_actor_new ();
77 * /* set the bounding box of the actor */
78 * clutter_actor_set_position (actor, 0, 0);
79 * clutter_actor_set_size (actor, 480, 640);
81 * /* set the background color of the actor */
82 * clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
84 * /* set the bounding box of the child, relative to the parent */
85 * ClutterActor *child = clutter_actor_new ();
86 * clutter_actor_set_position (child, 20, 20);
87 * clutter_actor_set_size (child, 80, 240);
89 * /* set the background color of the child */
90 * clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
92 * /* add the child to the actor */
93 * clutter_actor_add_child (actor, child);
94 * </programlisting></informalexample>
95 * <para>Children can be inserted at a given index, or above and below
96 * another child actor. The order of insertion determines the order of the
97 * children when iterating over them. Iterating over children is performed
98 * by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99 * clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100 * also possible to retrieve a list of children by using
101 * clutter_actor_get_children(), as well as retrieving a specific child at a
102 * given index by using clutter_actor_get_child_at_index().</para>
103 * <para>If you need to track additions of children to a #ClutterActor, use
104 * the #ClutterContainer::actor-added signal; similarly, to track removals
105 * of children from a ClutterActor, use the #ClutterContainer::actor-removed
107 * <informalexample><programlisting>
108 * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109 * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
111 * </programlisting></informalexample>
112 * <figure id="actor-example-image">
113 * <title>Actors</title>
114 * <graphic fileref="actor-example.png" format="PNG"/>
118 * <refsect2 id="ClutterActor-painting">
119 * <title>Painting an actor</title>
120 * <para>There are three ways to paint an actor:</para>
122 * <listitem><para>set a delegate #ClutterContent as the value for the
123 * #ClutterActor:content property of the actor;</para></listitem>
124 * <listitem><para>subclass #ClutterActor and override the
125 * #ClutterActorClass.paint_node() virtual function;</para></listitem>
126 * <listitem><para>subclass #ClutterActor and override the
127 * #ClutterActorClass.paint() virtual function.</para></listitem>
130 * <title>Setting the Content property</title>
131 * <para>A #ClutterContent is a delegate object that takes over the
132 * painting operation of one, or more actors. The #ClutterContent
133 * painting will be performed on top of the #ClutterActor:background-color
134 * of the actor, and before calling the #ClutterActorClass.paint_node()
135 * virtual function.</para>
136 * <informalexample><programlisting>
137 * ClutterActor *actor = clutter_actor_new ();
139 * /* set the bounding box */
140 * clutter_actor_set_position (actor, 50, 50);
141 * clutter_actor_set_size (actor, 100, 100);
143 * /* set the content; the image_content variable is set elsewhere */
144 * clutter_actor_set_content (actor, image_content);
145 * </programlisting></informalexample>
148 * <title>Overriding the paint_node virtual function</title>
149 * <para>The #ClutterActorClass.paint_node() virtual function is invoked
150 * whenever an actor needs to be painted. The implementation of the
151 * virtual function must only paint the contents of the actor itself,
152 * and not the contents of its children, if the actor has any.</para>
153 * <para>The #ClutterPaintNode passed to the virtual function is the
154 * local root of the render tree; any node added to it will be
155 * rendered at the correct position, as defined by the actor's
156 * #ClutterActor:allocation.</para>
157 * <informalexample><programlisting>
159 * my_actor_paint_node (ClutterActor *actor,
160 * ClutterPaintNode *root)
162 * ClutterPaintNode *node;
163 * ClutterActorBox box;
165 * /* where the content of the actor should be painted */
166 * clutter_actor_get_allocation_box (actor, &box);
168 * /* the cogl_texture variable is set elsewhere */
169 * node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170 * CLUTTER_SCALING_FILTER_TRILINEAR,
171 * CLUTTER_SCALING_FILTER_LINEAR);
173 * /* paint the content of the node using the allocation */
174 * clutter_paint_node_add_rectangle (node, &box);
176 * /* add the node, and transfer ownership */
177 * clutter_paint_node_add_child (root, node);
178 * clutter_paint_node_unref (node);
180 * </programlisting></informalexample>
183 * <title>Overriding the paint virtual function</title>
184 * <para>The #ClutterActorClass.paint() virtual function is invoked
185 * when the #ClutterActor::paint signal is emitted, and after the other
186 * signal handlers have been invoked. Overriding the paint virtual
187 * function gives total control to the paint sequence of the actor
188 * itself, including the children of the actor, if any.</para>
189 * <warning><para>It is strongly discouraged to override the
190 * #ClutterActorClass.paint() virtual function, as well as connecting
191 * to the #ClutterActor::paint signal. These hooks into the paint
192 * sequence are considered legacy, and will be removed when the Clutter
193 * API changes.</para></warning>
197 * <refsect2 id="ClutterActor-events">
198 * <title>Handling events on an actor</title>
199 * <para>A #ClutterActor can receive and handle input device events, for
200 * instance pointer events and key events, as long as its
201 * #ClutterActor:reactive property is set to %TRUE.</para>
202 * <para>Once an actor has been determined to be the source of an event,
203 * Clutter will traverse the scene graph from the top-level actor towards the
204 * event source, emitting the #ClutterActor::captured-event signal on each
205 * ancestor until it reaches the source; this phase is also called
206 * <emphasis>the capture phase</emphasis>. If the event propagation was not
207 * stopped, the graph is walked backwards, from the source actor to the
208 * top-level, and the #ClutterActor::event signal, along with other event
209 * signals if needed, is emitted; this phase is also called <emphasis>the
210 * bubble phase</emphasis>. At any point of the signal emission, signal
211 * handlers can stop the propagation through the scene graph by returning
212 * %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213 * returning %CLUTTER_EVENT_PROPAGATE.</para>
216 * <refsect2 id="ClutterActor-subclassing">
217 * <title>Implementing an actor</title>
218 * <para>Careful consideration should be given when deciding to implement
219 * a #ClutterActor sub-class. It is generally recommended to implement a
220 * sub-class of #ClutterActor only for actors that should be used as leaf
221 * nodes of a scene graph.</para>
222 * <para>If your actor should be painted in a custom way, you should
223 * override the #ClutterActor::paint signal class handler. You can either
224 * opt to chain up to the parent class implementation or decide to fully
225 * override the default paint implementation; Clutter will set up the
226 * transformations and clip regions prior to emitting the #ClutterActor::paint
228 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
229 * #ClutterActorClass.get_preferred_height() virtual functions it is
230 * possible to change or provide the preferred size of an actor; similarly,
231 * by overriding the #ClutterActorClass.allocate() virtual function it is
232 * possible to control the layout of the children of an actor. Make sure to
233 * always chain up to the parent implementation of the
234 * #ClutterActorClass.allocate() virtual function.</para>
235 * <para>In general, it is strongly encouraged to use delegation and
236 * composition instead of direct subclassing.</para>
239 * <refsect2 id="ClutterActor-script">
240 * <title>ClutterActor custom properties for #ClutterScript</title>
241 * <para>#ClutterActor defines a custom "rotation" property which
242 * allows a short-hand description of the rotations to be applied
243 * to an actor.</para>
244 * <para>The syntax of the "rotation" property is the following:</para>
248 * { "<axis>" : [ <angle>, [ <center> ] ] }
252 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
253 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
254 * floating point value representing the rotation angle on the given axis,
256 * <para>The <emphasis>center</emphasis> array is optional, and if present
257 * it must contain the center of rotation as described by two coordinates:
258 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
260 * <para>#ClutterActor will also parse every positional and dimensional
261 * property defined as a string through clutter_units_from_string(); you
262 * should read the documentation for the #ClutterUnits parser format for
263 * the valid units and syntax.</para>
266 * <refsect2 id="ClutterActor-animating">
267 * <title>Custom animatable properties</title>
268 * <para>#ClutterActor allows accessing properties of #ClutterAction
269 * and #ClutterConstraint instances associated to an actor instance
270 * for animation purposes.</para>
271 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
272 * property it is necessary to set the #ClutterActorMeta:name property on the
273 * given action or constraint.</para>
274 * <para>The property can be accessed using the following syntax:</para>
277 * @<section>.<meta-name>.<property-name>
280 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
281 * <para>The <emphasis>section</emphasis> fragment can be one between
282 * "actions", "constraints" and "effects".</para>
283 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
284 * action or constraint, as specified by the #ClutterActorMeta:name
286 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
287 * action or constraint property to be animated.</para>
288 * <para>The example below animates a #ClutterBindConstraint applied to an
289 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
290 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
291 * its initial state is fully transparent and overlapping the actor to
292 * which is bound to. </para>
293 * <informalexample><programlisting>
294 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
295 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
296 * clutter_actor_add_constraint (rect, constraint);
298 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
299 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
300 * clutter_actor_add_constraint (rect, constraint);
302 * clutter_actor_set_reactive (rect, TRUE);
303 * clutter_actor_set_opacity (rect, 0);
305 * g_signal_connect (rect, "button-press-event",
306 * G_CALLBACK (on_button_press),
308 * </programlisting></informalexample>
309 * <para>On button press, the rectangle "slides" from behind the actor to
310 * which is bound to, using the #ClutterBindConstraint:offset property and
311 * the #ClutterActor:opacity property.</para>
312 * <informalexample><programlisting>
313 * float new_offset = clutter_actor_get_width (origin) + h_padding;
315 * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
317 * "@constraints.bind-x.offset", new_offset,
319 * </programlisting></informalexample>
322 * <refsect2 id="ClutterActor-animatable-properties">
323 * <title>Animatable properties</title>
324 * <para>Certain properties on #ClutterActor are marked as "animatable";
325 * these properties will be automatically tweened between the current
326 * value and the new value when one is set.</para>
327 * <para>For backward compatibility, animatable properties will only be
328 * tweened if the easing duration is greater than 0, or if a new easing
329 * state is set, for instance the following example:</para>
330 * <informalexample><programlisting>
331 * clutter_actor_save_easing_state (actor);
332 * clutter_actor_set_position (actor, 200, 200);
333 * clutter_actor_restore_easing_state (actor);
334 * </programlisting></informalexample>
335 * <para>will tween the actor to the (200, 200) coordinates using the default
336 * easing mode and duration of a new easing state. The example above is
337 * equivalent to the following code:</para>
338 * <informalexample><programlisting>
339 * clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
340 * clutter_actor_set_easing_duration (actor, 250);
341 * clutter_actor_set_position (actor, 200, 200);
342 * clutter_actor_restore_easing_state (actor);
343 * </programlisting></informalexample>
344 * <para>It is possible to nest easing states to tween animatable
345 * properties using different modes and durations, for instance:</para>
346 * <informalexample><programlisting>
347 * clutter_actor_save_easing_state (actor); /* outer state */
349 * /* set the duration of the animation to 2 seconds and change position */
350 * clutter_actor_set_easing_duration (actor, 2000);
351 * clutter_actor_set_position (actor, 0, 0);
353 * clutter_actor_save_easing_state (actor); /* inner state */
355 * /* set the duration of the animation to 5 seconds and change depth and opacity */
356 * clutter_actor_set_easing_duration (actor, 5000);
357 * clutter_actor_set_depth (actor, 200);
358 * clutter_actor_set_opacity (actor, 0);
360 * clutter_actor_restore_easing_state (actor);
362 * clutter_actor_restore_easing_state (actor);
363 * </programlisting></informalexample>
368 * CLUTTER_ACTOR_IS_MAPPED:
369 * @a: a #ClutterActor
371 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
373 * The mapped state is set when the actor is visible and all its parents up
374 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
376 * This check can be used to see if an actor is going to be painted, as only
377 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
379 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
380 * not be checked directly; instead, the recommended usage is to connect a
381 * handler on the #GObject::notify signal for the #ClutterActor:mapped
382 * property of #ClutterActor, and check the presence of
383 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
385 * It is also important to note that Clutter may delay the changes of
386 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
387 * limitations, or during the reparenting of an actor, to optimize
388 * unnecessary (and potentially expensive) state changes.
394 * CLUTTER_ACTOR_IS_REALIZED:
395 * @a: a #ClutterActor
397 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
399 * The realized state has an actor-dependant interpretation. If an
400 * actor wants to delay allocating resources until it is attached to a
401 * stage, it may use the realize state to do so. However it is
402 * perfectly acceptable for an actor to allocate Cogl resources before
403 * being realized because there is only one drawing context used by Clutter
404 * so any resources will work on any stage. If an actor is mapped it
405 * must also be realized, but an actor can be realized and unmapped
406 * (this is so hiding an actor temporarily doesn't do an expensive
407 * unrealize/realize).
409 * To be realized an actor must be inside a stage, and all its parents
416 * CLUTTER_ACTOR_IS_VISIBLE:
417 * @a: a #ClutterActor
419 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
420 * Equivalent to the ClutterActor::visible object property.
422 * Note that an actor is only painted onscreen if it's mapped, which
423 * means it's visible, and all its parents are visible, and one of the
424 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
430 * CLUTTER_ACTOR_IS_REACTIVE:
431 * @a: a #ClutterActor
433 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
435 * Only reactive actors will receive event-related signals.
446 #include <gobject/gvaluecollector.h>
448 #include <cogl/cogl.h>
450 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
451 #define CLUTTER_ENABLE_EXPERIMENTAL_API
453 #include "clutter-actor-private.h"
455 #include "clutter-action.h"
456 #include "clutter-actor-meta-private.h"
457 #include "clutter-animatable.h"
458 #include "clutter-color-static.h"
459 #include "clutter-color.h"
460 #include "clutter-constraint.h"
461 #include "clutter-container.h"
462 #include "clutter-content-private.h"
463 #include "clutter-debug.h"
464 #include "clutter-effect-private.h"
465 #include "clutter-enum-types.h"
466 #include "clutter-fixed-layout.h"
467 #include "clutter-flatten-effect.h"
468 #include "clutter-interval.h"
469 #include "clutter-main.h"
470 #include "clutter-marshal.h"
471 #include "clutter-paint-nodes.h"
472 #include "clutter-paint-node-private.h"
473 #include "clutter-paint-volume-private.h"
474 #include "clutter-private.h"
475 #include "clutter-profile.h"
476 #include "clutter-property-transition.h"
477 #include "clutter-scriptable.h"
478 #include "clutter-script-private.h"
479 #include "clutter-stage-private.h"
480 #include "clutter-timeline.h"
481 #include "clutter-transition.h"
482 #include "clutter-units.h"
484 #include "deprecated/clutter-actor.h"
485 #include "deprecated/clutter-behaviour.h"
486 #include "deprecated/clutter-container.h"
488 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
489 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
491 /* Internal enum used to control mapped state update. This is a hint
492 * which indicates when to do something other than just enforce
496 MAP_STATE_CHECK, /* just enforce invariants. */
497 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
498 * used when about to unparent.
500 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
501 * used to set mapped on toplevels.
503 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
504 * used just before unmapping parent.
508 /* 3 entries should be a good compromise, few layout managers
509 * will ask for 3 different preferred size in each allocation cycle */
510 #define N_CACHED_SIZE_REQUESTS 3
512 struct _ClutterActorPrivate
515 ClutterRequestMode request_mode;
517 /* our cached size requests for different width / height */
518 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
519 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
521 /* An age of 0 means the entry is not set */
522 guint cached_height_age;
523 guint cached_width_age;
525 /* the bounding box of the actor, relative to the parent's
528 ClutterActorBox allocation;
529 ClutterAllocationFlags allocation_flags;
531 /* clip, in actor coordinates */
532 cairo_rectangle_t clip;
534 /* the cached transformation matrix; see apply_transform() */
535 CoglMatrix transform;
538 gint opacity_override;
540 ClutterOffscreenRedirect offscreen_redirect;
542 /* This is an internal effect used to implement the
543 offscreen-redirect property */
544 ClutterEffect *flatten_effect;
547 ClutterActor *parent;
548 ClutterActor *prev_sibling;
549 ClutterActor *next_sibling;
550 ClutterActor *first_child;
551 ClutterActor *last_child;
555 /* tracks whenever the children of an actor are changed; the
556 * age is incremented by 1 whenever an actor is added or
557 * removed. the age is not incremented when the first or the
558 * last child pointers are changed, or when grandchildren of
559 * an actor are changed.
563 gchar *name; /* a non-unique name, used for debugging */
564 guint32 id; /* unique id, used for backward compatibility */
566 gint32 pick_id; /* per-stage unique id, used for picking */
568 /* a back-pointer to the Pango context that we can use
569 * to create pre-configured PangoLayout
571 PangoContext *pango_context;
573 /* the text direction configured for this child - either by
574 * application code, or by the actor's parent
576 ClutterTextDirection text_direction;
578 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
582 ClutterMetaGroup *actions;
583 ClutterMetaGroup *constraints;
584 ClutterMetaGroup *effects;
586 /* delegate object used to allocate the children of this actor */
587 ClutterLayoutManager *layout_manager;
589 /* delegate object used to paint the contents of this actor */
590 ClutterContent *content;
592 ClutterContentGravity content_gravity;
593 ClutterScalingFilter min_filter;
594 ClutterScalingFilter mag_filter;
596 /* used when painting, to update the paint volume */
597 ClutterEffect *current_effect;
599 /* This is used to store an effect which needs to be redrawn. A
600 redraw can be queued to start from a particular effect. This is
601 used by parametrised effects that can cache an image of the
602 actor. If a parameter of the effect changes then it only needs to
603 redraw the cached image, not the actual actor. The pointer is
604 only valid if is_dirty == TRUE. If the pointer is NULL then the
605 whole actor is dirty. */
606 ClutterEffect *effect_to_redraw;
608 /* This is used when painting effects to implement the
609 clutter_actor_continue_paint() function. It points to the node in
610 the list of effects that is next in the chain */
611 const GList *next_effect_to_paint;
613 ClutterPaintVolume paint_volume;
615 /* NB: This volume isn't relative to this actor, it is in eye
616 * coordinates so that it can remain valid after the actor changes.
618 ClutterPaintVolume last_paint_volume;
620 ClutterStageQueueRedrawEntry *queue_redraw_entry;
622 ClutterColor bg_color;
626 /* fixed position and sizes */
627 guint position_set : 1;
628 guint min_width_set : 1;
629 guint min_height_set : 1;
630 guint natural_width_set : 1;
631 guint natural_height_set : 1;
632 /* cached request is invalid (implies allocation is too) */
633 guint needs_width_request : 1;
634 /* cached request is invalid (implies allocation is too) */
635 guint needs_height_request : 1;
636 /* cached allocation is invalid (request has changed, probably) */
637 guint needs_allocation : 1;
638 guint show_on_set_parent : 1;
640 guint clip_to_allocation : 1;
641 guint enable_model_view_transform : 1;
642 guint enable_paint_unmapped : 1;
643 guint has_pointer : 1;
644 guint propagated_one_redraw : 1;
645 guint paint_volume_valid : 1;
646 guint last_paint_volume_valid : 1;
647 guint in_clone_paint : 1;
648 guint transform_valid : 1;
649 /* This is TRUE if anything has queued a redraw since we were last
650 painted. In this case effect_to_redraw will point to an effect
651 the redraw was queued from or it will be NULL if the redraw was
652 queued without an effect. */
654 guint bg_color_set : 1;
663 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
664 * when set they force a size request, when gotten they
665 * get the allocation if the allocation is valid, and the
673 /* Then the rest of these size-related properties are the "actual"
674 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
679 PROP_FIXED_POSITION_SET,
688 PROP_NATURAL_WIDTH_SET,
691 PROP_NATURAL_HEIGHT_SET,
695 /* Allocation properties are read-only */
702 PROP_CLIP_TO_ALLOCATION,
706 PROP_OFFSCREEN_REDIRECT,
719 PROP_ROTATION_ANGLE_X,
720 PROP_ROTATION_ANGLE_Y,
721 PROP_ROTATION_ANGLE_Z,
722 PROP_ROTATION_CENTER_X,
723 PROP_ROTATION_CENTER_Y,
724 PROP_ROTATION_CENTER_Z,
725 /* This property only makes sense for the z rotation because the
726 others would depend on the actor having a size along the
728 PROP_ROTATION_CENTER_Z_GRAVITY,
734 PROP_SHOW_ON_SET_PARENT,
752 PROP_BACKGROUND_COLOR,
753 PROP_BACKGROUND_COLOR_SET,
759 PROP_CONTENT_GRAVITY,
761 PROP_MINIFICATION_FILTER,
762 PROP_MAGNIFICATION_FILTER,
767 static GParamSpec *obj_props[PROP_LAST];
786 BUTTON_RELEASE_EVENT,
794 TRANSITIONS_COMPLETED,
799 static guint actor_signals[LAST_SIGNAL] = { 0, };
801 static void clutter_container_iface_init (ClutterContainerIface *iface);
802 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
803 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
804 static void atk_implementor_iface_init (AtkImplementorIface *iface);
806 /* These setters are all static for now, maybe they should be in the
807 * public API, but they are perhaps obscure enough to leave only as
810 static void clutter_actor_set_min_width (ClutterActor *self,
812 static void clutter_actor_set_min_height (ClutterActor *self,
814 static void clutter_actor_set_natural_width (ClutterActor *self,
815 gfloat natural_width);
816 static void clutter_actor_set_natural_height (ClutterActor *self,
817 gfloat natural_height);
818 static void clutter_actor_set_min_width_set (ClutterActor *self,
819 gboolean use_min_width);
820 static void clutter_actor_set_min_height_set (ClutterActor *self,
821 gboolean use_min_height);
822 static void clutter_actor_set_natural_width_set (ClutterActor *self,
823 gboolean use_natural_width);
824 static void clutter_actor_set_natural_height_set (ClutterActor *self,
825 gboolean use_natural_height);
826 static void clutter_actor_update_map_state (ClutterActor *self,
827 MapStateChange change);
828 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
830 /* Helper routines for managing anchor coords */
831 static void clutter_anchor_coord_get_units (ClutterActor *self,
832 const AnchorCoord *coord,
836 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
841 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
842 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
843 ClutterGravity gravity);
845 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
847 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
849 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
850 ClutterActor *ancestor,
853 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
855 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
857 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
858 const ClutterColor *color);
860 static void on_layout_manager_changed (ClutterLayoutManager *manager,
863 /* Helper macro which translates by the anchor coord, applies the
864 given transformation and then translates back */
865 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
866 gfloat _tx, _ty, _tz; \
867 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
868 cogl_matrix_translate ((m), _tx, _ty, _tz); \
870 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
872 static GQuark quark_shader_data = 0;
873 static GQuark quark_actor_layout_info = 0;
874 static GQuark quark_actor_transform_info = 0;
875 static GQuark quark_actor_animation_info = 0;
877 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
879 G_TYPE_INITIALLY_UNOWNED,
880 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
881 clutter_container_iface_init)
882 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
883 clutter_scriptable_iface_init)
884 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
885 clutter_animatable_iface_init)
886 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
887 atk_implementor_iface_init));
890 * clutter_actor_get_debug_name:
891 * @actor: a #ClutterActor
893 * Retrieves a printable name of @actor for debugging messages
895 * Return value: a string with a printable name
898 _clutter_actor_get_debug_name (ClutterActor *actor)
900 return actor->priv->name != NULL ? actor->priv->name
901 : G_OBJECT_TYPE_NAME (actor);
904 #ifdef CLUTTER_ENABLE_DEBUG
905 /* XXX - this is for debugging only, remove once working (or leave
906 * in only in some debug mode). Should leave it for a little while
907 * until we're confident in the new map/realize/visible handling.
910 clutter_actor_verify_map_state (ClutterActor *self)
912 ClutterActorPrivate *priv = self->priv;
914 if (CLUTTER_ACTOR_IS_REALIZED (self))
916 /* all bets are off during reparent when we're potentially realized,
917 * but should not be according to invariants
919 if (!CLUTTER_ACTOR_IN_REPARENT (self))
921 if (priv->parent == NULL)
923 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
927 g_warning ("Realized non-toplevel actor '%s' should "
929 _clutter_actor_get_debug_name (self));
931 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
933 g_warning ("Realized actor %s has an unrealized parent %s",
934 _clutter_actor_get_debug_name (self),
935 _clutter_actor_get_debug_name (priv->parent));
940 if (CLUTTER_ACTOR_IS_MAPPED (self))
942 if (!CLUTTER_ACTOR_IS_REALIZED (self))
943 g_warning ("Actor '%s' is mapped but not realized",
944 _clutter_actor_get_debug_name (self));
946 /* remaining bets are off during reparent when we're potentially
947 * mapped, but should not be according to invariants
949 if (!CLUTTER_ACTOR_IN_REPARENT (self))
951 if (priv->parent == NULL)
953 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
955 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
956 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
958 g_warning ("Toplevel actor '%s' is mapped "
960 _clutter_actor_get_debug_name (self));
965 g_warning ("Mapped actor '%s' should have a parent",
966 _clutter_actor_get_debug_name (self));
971 ClutterActor *iter = self;
973 /* check for the enable_paint_unmapped flag on the actor
974 * and parents; if the flag is enabled at any point of this
975 * branch of the scene graph then all the later checks
980 if (iter->priv->enable_paint_unmapped)
983 iter = iter->priv->parent;
986 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
988 g_warning ("Actor '%s' should not be mapped if parent '%s'"
990 _clutter_actor_get_debug_name (self),
991 _clutter_actor_get_debug_name (priv->parent));
994 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
996 g_warning ("Actor '%s' should not be mapped if parent '%s'"
998 _clutter_actor_get_debug_name (self),
999 _clutter_actor_get_debug_name (priv->parent));
1002 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1004 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1005 g_warning ("Actor '%s' is mapped but its non-toplevel "
1006 "parent '%s' is not mapped",
1007 _clutter_actor_get_debug_name (self),
1008 _clutter_actor_get_debug_name (priv->parent));
1015 #endif /* CLUTTER_ENABLE_DEBUG */
1018 clutter_actor_set_mapped (ClutterActor *self,
1021 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1026 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1027 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1031 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1032 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1036 /* this function updates the mapped and realized states according to
1037 * invariants, in the appropriate order.
1040 clutter_actor_update_map_state (ClutterActor *self,
1041 MapStateChange change)
1043 gboolean was_mapped;
1045 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1047 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1049 /* the mapped flag on top-level actors must be set by the
1050 * per-backend implementation because it might be asynchronous.
1052 * That is, the MAPPED flag on toplevels currently tracks the X
1053 * server mapped-ness of the window, while the expected behavior
1054 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1055 * This creates some weird complexity by breaking the invariant
1056 * that if we're visible and all ancestors shown then we are
1057 * also mapped - instead, we are mapped if all ancestors
1058 * _possibly excepting_ the stage are mapped. The stage
1059 * will map/unmap for example when it is minimized or
1060 * moved to another workspace.
1062 * So, the only invariant on the stage is that if visible it
1063 * should be realized, and that it has to be visible to be
1066 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1067 clutter_actor_realize (self);
1071 case MAP_STATE_CHECK:
1074 case MAP_STATE_MAKE_MAPPED:
1075 g_assert (!was_mapped);
1076 clutter_actor_set_mapped (self, TRUE);
1079 case MAP_STATE_MAKE_UNMAPPED:
1080 g_assert (was_mapped);
1081 clutter_actor_set_mapped (self, FALSE);
1084 case MAP_STATE_MAKE_UNREALIZED:
1085 /* we only use MAKE_UNREALIZED in unparent,
1086 * and unparenting a stage isn't possible.
1087 * If someone wants to just unrealize a stage
1088 * then clutter_actor_unrealize() doesn't
1089 * go through this codepath.
1091 g_warning ("Trying to force unrealize stage is not allowed");
1095 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1096 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1097 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1099 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1100 "it is somehow still mapped",
1101 _clutter_actor_get_debug_name (self));
1106 ClutterActorPrivate *priv = self->priv;
1107 ClutterActor *parent = priv->parent;
1108 gboolean should_be_mapped;
1109 gboolean may_be_realized;
1110 gboolean must_be_realized;
1112 should_be_mapped = FALSE;
1113 may_be_realized = TRUE;
1114 must_be_realized = FALSE;
1116 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1118 may_be_realized = FALSE;
1122 /* Maintain invariant that if parent is mapped, and we are
1123 * visible, then we are mapped ... unless parent is a
1124 * stage, in which case we map regardless of parent's map
1125 * state but do require stage to be visible and realized.
1127 * If parent is realized, that does not force us to be
1128 * realized; but if parent is unrealized, that does force
1129 * us to be unrealized.
1131 * The reason we don't force children to realize with
1132 * parents is _clutter_actor_rerealize(); if we require that
1133 * a realized parent means children are realized, then to
1134 * unrealize an actor we would have to unrealize its
1135 * parents, which would end up meaning unrealizing and
1136 * hiding the entire stage. So we allow unrealizing a
1137 * child (as long as that child is not mapped) while that
1138 * child still has a realized parent.
1140 * Also, if we unrealize from leaf nodes to root, and
1141 * realize from root to leaf, the invariants are never
1142 * violated if we allow children to be unrealized
1143 * while parents are realized.
1145 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1146 * to force us to unmap, even though parent is still
1147 * mapped. This is because we're unmapping from leaf nodes
1150 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1151 change != MAP_STATE_MAKE_UNMAPPED)
1153 gboolean parent_is_visible_realized_toplevel;
1155 parent_is_visible_realized_toplevel =
1156 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1157 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1158 CLUTTER_ACTOR_IS_REALIZED (parent));
1160 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1161 parent_is_visible_realized_toplevel)
1163 must_be_realized = TRUE;
1164 should_be_mapped = TRUE;
1168 /* if the actor has been set to be painted even if unmapped
1169 * then we should map it and check for realization as well;
1170 * this is an override for the branch of the scene graph
1171 * which begins with this node
1173 if (priv->enable_paint_unmapped)
1175 if (priv->parent == NULL)
1176 g_warning ("Attempting to map an unparented actor '%s'",
1177 _clutter_actor_get_debug_name (self));
1179 should_be_mapped = TRUE;
1180 must_be_realized = TRUE;
1183 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1184 may_be_realized = FALSE;
1187 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1190 g_warning ("Attempting to map a child that does not "
1191 "meet the necessary invariants: the actor '%s' "
1193 _clutter_actor_get_debug_name (self));
1195 g_warning ("Attempting to map a child that does not "
1196 "meet the necessary invariants: the actor '%s' "
1197 "is parented to an unmapped actor '%s'",
1198 _clutter_actor_get_debug_name (self),
1199 _clutter_actor_get_debug_name (priv->parent));
1202 /* If in reparent, we temporarily suspend unmap and unrealize.
1204 * We want to go in the order "realize, map" and "unmap, unrealize"
1208 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1209 clutter_actor_set_mapped (self, FALSE);
1212 if (must_be_realized)
1213 clutter_actor_realize (self);
1215 /* if we must be realized then we may be, presumably */
1216 g_assert (!(must_be_realized && !may_be_realized));
1219 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1220 clutter_actor_unrealize_not_hiding (self);
1223 if (should_be_mapped)
1225 if (!must_be_realized)
1226 g_warning ("Somehow we think actor '%s' should be mapped but "
1227 "not realized, which isn't allowed",
1228 _clutter_actor_get_debug_name (self));
1230 /* realization is allowed to fail (though I don't know what
1231 * an app is supposed to do about that - shouldn't it just
1232 * be a g_error? anyway, we have to avoid mapping if this
1235 if (CLUTTER_ACTOR_IS_REALIZED (self))
1236 clutter_actor_set_mapped (self, TRUE);
1240 #ifdef CLUTTER_ENABLE_DEBUG
1241 /* check all invariants were kept */
1242 clutter_actor_verify_map_state (self);
1247 clutter_actor_real_map (ClutterActor *self)
1249 ClutterActorPrivate *priv = self->priv;
1250 ClutterActor *stage, *iter;
1252 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1254 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1255 _clutter_actor_get_debug_name (self));
1257 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1259 stage = _clutter_actor_get_stage_internal (self);
1260 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1262 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1264 _clutter_actor_get_debug_name (self));
1266 /* notify on parent mapped before potentially mapping
1267 * children, so apps see a top-down notification.
1269 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1271 for (iter = self->priv->first_child;
1273 iter = iter->priv->next_sibling)
1275 clutter_actor_map (iter);
1280 * clutter_actor_map:
1281 * @self: A #ClutterActor
1283 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1284 * and realizes its children if they are visible. Does nothing if the
1285 * actor is not visible.
1287 * Calling this function is strongly disencouraged: the default
1288 * implementation of #ClutterActorClass.map() will map all the children
1289 * of an actor when mapping its parent.
1291 * When overriding map, it is mandatory to chain up to the parent
1297 clutter_actor_map (ClutterActor *self)
1299 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1301 if (CLUTTER_ACTOR_IS_MAPPED (self))
1304 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1307 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1311 clutter_actor_real_unmap (ClutterActor *self)
1313 ClutterActorPrivate *priv = self->priv;
1316 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1318 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1319 _clutter_actor_get_debug_name (self));
1321 for (iter = self->priv->first_child;
1323 iter = iter->priv->next_sibling)
1325 clutter_actor_unmap (iter);
1328 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1330 /* clear the contents of the last paint volume, so that hiding + moving +
1331 * showing will not result in the wrong area being repainted
1333 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1334 priv->last_paint_volume_valid = TRUE;
1336 /* notify on parent mapped after potentially unmapping
1337 * children, so apps see a bottom-up notification.
1339 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1341 /* relinquish keyboard focus if we were unmapped while owning it */
1342 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1344 ClutterStage *stage;
1346 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1349 _clutter_stage_release_pick_id (stage, priv->pick_id);
1353 if (stage != NULL &&
1354 clutter_stage_get_key_focus (stage) == self)
1356 clutter_stage_set_key_focus (stage, NULL);
1362 * clutter_actor_unmap:
1363 * @self: A #ClutterActor
1365 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1366 * unmaps its children if they were mapped.
1368 * Calling this function is not encouraged: the default #ClutterActor
1369 * implementation of #ClutterActorClass.unmap() will also unmap any
1370 * eventual children by default when their parent is unmapped.
1372 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1373 * chain up to the parent implementation.
1375 * <note>It is important to note that the implementation of the
1376 * #ClutterActorClass.unmap() virtual function may be called after
1377 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1378 * implementation, but it is guaranteed to be called before the
1379 * #GObjectClass.finalize() implementation.</note>
1384 clutter_actor_unmap (ClutterActor *self)
1386 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1388 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1391 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1395 clutter_actor_real_show (ClutterActor *self)
1397 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1399 ClutterActorPrivate *priv = self->priv;
1401 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1403 /* we notify on the "visible" flag in the clutter_actor_show()
1404 * wrapper so the entire show signal emission completes first
1407 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1409 /* we queue a relayout unless the actor is inside a
1410 * container that explicitly told us not to
1412 if (priv->parent != NULL &&
1413 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1415 /* While an actor is hidden the parent may not have
1416 * allocated/requested so we need to start from scratch
1417 * and avoid the short-circuiting in
1418 * clutter_actor_queue_relayout().
1420 priv->needs_width_request = FALSE;
1421 priv->needs_height_request = FALSE;
1422 priv->needs_allocation = FALSE;
1423 clutter_actor_queue_relayout (self);
1429 set_show_on_set_parent (ClutterActor *self,
1432 ClutterActorPrivate *priv = self->priv;
1434 set_show = !!set_show;
1436 if (priv->show_on_set_parent == set_show)
1439 if (priv->parent == NULL)
1441 priv->show_on_set_parent = set_show;
1442 g_object_notify_by_pspec (G_OBJECT (self),
1443 obj_props[PROP_SHOW_ON_SET_PARENT]);
1448 * clutter_actor_show:
1449 * @self: A #ClutterActor
1451 * Flags an actor to be displayed. An actor that isn't shown will not
1452 * be rendered on the stage.
1454 * Actors are visible by default.
1456 * If this function is called on an actor without a parent, the
1457 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1461 clutter_actor_show (ClutterActor *self)
1463 ClutterActorPrivate *priv;
1465 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1467 /* simple optimization */
1468 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1470 /* we still need to set the :show-on-set-parent property, in
1471 * case show() is called on an unparented actor
1473 set_show_on_set_parent (self, TRUE);
1477 #ifdef CLUTTER_ENABLE_DEBUG
1478 clutter_actor_verify_map_state (self);
1483 g_object_freeze_notify (G_OBJECT (self));
1485 set_show_on_set_parent (self, TRUE);
1487 g_signal_emit (self, actor_signals[SHOW], 0);
1488 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1490 if (priv->parent != NULL)
1491 clutter_actor_queue_redraw (priv->parent);
1493 g_object_thaw_notify (G_OBJECT (self));
1497 * clutter_actor_show_all:
1498 * @self: a #ClutterActor
1500 * Calls clutter_actor_show() on all children of an actor (if any).
1504 * Deprecated: 1.10: Actors are visible by default
1507 clutter_actor_show_all (ClutterActor *self)
1509 ClutterActorClass *klass;
1511 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1513 klass = CLUTTER_ACTOR_GET_CLASS (self);
1514 if (klass->show_all)
1515 klass->show_all (self);
1519 clutter_actor_real_hide (ClutterActor *self)
1521 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1523 ClutterActorPrivate *priv = self->priv;
1525 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1527 /* we notify on the "visible" flag in the clutter_actor_hide()
1528 * wrapper so the entire hide signal emission completes first
1531 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1533 /* we queue a relayout unless the actor is inside a
1534 * container that explicitly told us not to
1536 if (priv->parent != NULL &&
1537 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1538 clutter_actor_queue_relayout (priv->parent);
1543 * clutter_actor_hide:
1544 * @self: A #ClutterActor
1546 * Flags an actor to be hidden. A hidden actor will not be
1547 * rendered on the stage.
1549 * Actors are visible by default.
1551 * If this function is called on an actor without a parent, the
1552 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1556 clutter_actor_hide (ClutterActor *self)
1558 ClutterActorPrivate *priv;
1560 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1562 /* simple optimization */
1563 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1565 /* we still need to set the :show-on-set-parent property, in
1566 * case hide() is called on an unparented actor
1568 set_show_on_set_parent (self, FALSE);
1572 #ifdef CLUTTER_ENABLE_DEBUG
1573 clutter_actor_verify_map_state (self);
1578 g_object_freeze_notify (G_OBJECT (self));
1580 set_show_on_set_parent (self, FALSE);
1582 g_signal_emit (self, actor_signals[HIDE], 0);
1583 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1585 if (priv->parent != NULL)
1586 clutter_actor_queue_redraw (priv->parent);
1588 g_object_thaw_notify (G_OBJECT (self));
1592 * clutter_actor_hide_all:
1593 * @self: a #ClutterActor
1595 * Calls clutter_actor_hide() on all child actors (if any).
1599 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1600 * prevent its children from being painted as well.
1603 clutter_actor_hide_all (ClutterActor *self)
1605 ClutterActorClass *klass;
1607 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1609 klass = CLUTTER_ACTOR_GET_CLASS (self);
1610 if (klass->hide_all)
1611 klass->hide_all (self);
1615 * clutter_actor_realize:
1616 * @self: A #ClutterActor
1618 * Realization informs the actor that it is attached to a stage. It
1619 * can use this to allocate resources if it wanted to delay allocation
1620 * until it would be rendered. However it is perfectly acceptable for
1621 * an actor to create resources before being realized because Clutter
1622 * only ever has a single rendering context so that actor is free to
1623 * be moved from one stage to another.
1625 * This function does nothing if the actor is already realized.
1627 * Because a realized actor must have realized parent actors, calling
1628 * clutter_actor_realize() will also realize all parents of the actor.
1630 * This function does not realize child actors, except in the special
1631 * case that realizing the stage, when the stage is visible, will
1632 * suddenly map (and thus realize) the children of the stage.
1635 clutter_actor_realize (ClutterActor *self)
1637 ClutterActorPrivate *priv;
1639 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1643 #ifdef CLUTTER_ENABLE_DEBUG
1644 clutter_actor_verify_map_state (self);
1647 if (CLUTTER_ACTOR_IS_REALIZED (self))
1650 /* To be realized, our parent actors must be realized first.
1651 * This will only succeed if we're inside a toplevel.
1653 if (priv->parent != NULL)
1654 clutter_actor_realize (priv->parent);
1656 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1658 /* toplevels can be realized at any time */
1662 /* "Fail" the realization if parent is missing or unrealized;
1663 * this should really be a g_warning() not some kind of runtime
1664 * failure; how can an app possibly recover? Instead it's a bug
1665 * in the app and the app should get an explanatory warning so
1666 * someone can fix it. But for now it's too hard to fix this
1667 * because e.g. ClutterTexture needs reworking.
1669 if (priv->parent == NULL ||
1670 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1674 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1676 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1677 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1679 g_signal_emit (self, actor_signals[REALIZE], 0);
1681 /* Stage actor is allowed to unset the realized flag again in its
1682 * default signal handler, though that is a pathological situation.
1685 /* If realization "failed" we'll have to update child state. */
1686 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1690 clutter_actor_real_unrealize (ClutterActor *self)
1692 /* we must be unmapped (implying our children are also unmapped) */
1693 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1697 * clutter_actor_unrealize:
1698 * @self: A #ClutterActor
1700 * Unrealization informs the actor that it may be being destroyed or
1701 * moved to another stage. The actor may want to destroy any
1702 * underlying graphics resources at this point. However it is
1703 * perfectly acceptable for it to retain the resources until the actor
1704 * is destroyed because Clutter only ever uses a single rendering
1705 * context and all of the graphics resources are valid on any stage.
1707 * Because mapped actors must be realized, actors may not be
1708 * unrealized if they are mapped. This function hides the actor to be
1709 * sure it isn't mapped, an application-visible side effect that you
1710 * may not be expecting.
1712 * This function should not be called by application code.
1715 clutter_actor_unrealize (ClutterActor *self)
1717 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1718 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1720 /* This function should not really be in the public API, because
1721 * there isn't a good reason to call it. ClutterActor will already
1722 * unrealize things for you when it's important to do so.
1724 * If you were using clutter_actor_unrealize() in a dispose
1725 * implementation, then don't, just chain up to ClutterActor's
1728 * If you were using clutter_actor_unrealize() to implement
1729 * unrealizing children of your container, then don't, ClutterActor
1730 * will already take care of that.
1732 * If you were using clutter_actor_unrealize() to re-realize to
1733 * create your resources in a different way, then use
1734 * _clutter_actor_rerealize() (inside Clutter) or just call your
1735 * code that recreates your resources directly (outside Clutter).
1738 #ifdef CLUTTER_ENABLE_DEBUG
1739 clutter_actor_verify_map_state (self);
1742 clutter_actor_hide (self);
1744 clutter_actor_unrealize_not_hiding (self);
1747 static ClutterActorTraverseVisitFlags
1748 unrealize_actor_before_children_cb (ClutterActor *self,
1752 /* If an actor is already unrealized we know its children have also
1753 * already been unrealized... */
1754 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1755 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1757 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1759 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1762 static ClutterActorTraverseVisitFlags
1763 unrealize_actor_after_children_cb (ClutterActor *self,
1767 /* We want to unset the realized flag only _after_
1768 * child actors are unrealized, to maintain invariants.
1770 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1771 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1772 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1776 * clutter_actor_unrealize_not_hiding:
1777 * @self: A #ClutterActor
1779 * Unrealization informs the actor that it may be being destroyed or
1780 * moved to another stage. The actor may want to destroy any
1781 * underlying graphics resources at this point. However it is
1782 * perfectly acceptable for it to retain the resources until the actor
1783 * is destroyed because Clutter only ever uses a single rendering
1784 * context and all of the graphics resources are valid on any stage.
1786 * Because mapped actors must be realized, actors may not be
1787 * unrealized if they are mapped. You must hide the actor or one of
1788 * its parents before attempting to unrealize.
1790 * This function is separate from clutter_actor_unrealize() because it
1791 * does not automatically hide the actor.
1792 * Actors need not be hidden to be unrealized, they just need to
1793 * be unmapped. In fact we don't want to mess up the application's
1794 * setting of the "visible" flag, so hiding is very undesirable.
1796 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1797 * backward compatibility.
1800 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1802 _clutter_actor_traverse (self,
1803 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1804 unrealize_actor_before_children_cb,
1805 unrealize_actor_after_children_cb,
1810 * _clutter_actor_rerealize:
1811 * @self: A #ClutterActor
1812 * @callback: Function to call while unrealized
1813 * @data: data for callback
1815 * If an actor is already unrealized, this just calls the callback.
1817 * If it is realized, it unrealizes temporarily, calls the callback,
1818 * and then re-realizes the actor.
1820 * As a side effect, leaves all children of the actor unrealized if
1821 * the actor was realized but not showing. This is because when we
1822 * unrealize the actor temporarily we must unrealize its children
1823 * (e.g. children of a stage can't be realized if stage window is
1824 * gone). And we aren't clever enough to save the realization state of
1825 * all children. In most cases this should not matter, because
1826 * the children will automatically realize when they next become mapped.
1829 _clutter_actor_rerealize (ClutterActor *self,
1830 ClutterCallback callback,
1833 gboolean was_mapped;
1834 gboolean was_showing;
1835 gboolean was_realized;
1837 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1839 #ifdef CLUTTER_ENABLE_DEBUG
1840 clutter_actor_verify_map_state (self);
1843 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1844 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1845 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1847 /* Must be unmapped to unrealize. Note we only have to hide this
1848 * actor if it was mapped (if all parents were showing). If actor
1849 * is merely visible (but not mapped), then that's fine, we can
1853 clutter_actor_hide (self);
1855 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1857 /* unrealize self and all children */
1858 clutter_actor_unrealize_not_hiding (self);
1860 if (callback != NULL)
1862 (* callback) (self, data);
1866 clutter_actor_show (self); /* will realize only if mapping implies it */
1867 else if (was_realized)
1868 clutter_actor_realize (self); /* realize self and all parents */
1872 clutter_actor_real_pick (ClutterActor *self,
1873 const ClutterColor *color)
1875 /* the default implementation is just to paint a rectangle
1876 * with the same size of the actor using the passed color
1878 if (clutter_actor_should_pick_paint (self))
1880 ClutterActorBox box = { 0, };
1881 float width, height;
1883 clutter_actor_get_allocation_box (self, &box);
1885 width = box.x2 - box.x1;
1886 height = box.y2 - box.y1;
1888 cogl_set_source_color4ub (color->red,
1893 cogl_rectangle (0, 0, width, height);
1896 /* XXX - this thoroughly sucks, but we need to maintain compatibility
1897 * with existing container classes that override the pick() virtual
1898 * and chain up to the default implementation - otherwise we'll end up
1899 * painting our children twice.
1901 * this has to go away for 2.0; hopefully along the pick() itself.
1903 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1907 for (iter = self->priv->first_child;
1909 iter = iter->priv->next_sibling)
1910 clutter_actor_paint (iter);
1915 * clutter_actor_should_pick_paint:
1916 * @self: A #ClutterActor
1918 * Should be called inside the implementation of the
1919 * #ClutterActor::pick virtual function in order to check whether
1920 * the actor should paint itself in pick mode or not.
1922 * This function should never be called directly by applications.
1924 * Return value: %TRUE if the actor should paint its silhouette,
1928 clutter_actor_should_pick_paint (ClutterActor *self)
1930 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1932 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1933 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1934 CLUTTER_ACTOR_IS_REACTIVE (self)))
1941 clutter_actor_real_get_preferred_width (ClutterActor *self,
1943 gfloat *min_width_p,
1944 gfloat *natural_width_p)
1946 ClutterActorPrivate *priv = self->priv;
1948 if (priv->n_children != 0 &&
1949 priv->layout_manager != NULL)
1951 ClutterContainer *container = CLUTTER_CONTAINER (self);
1953 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1954 "for the preferred width",
1955 G_OBJECT_TYPE_NAME (priv->layout_manager),
1956 priv->layout_manager);
1958 clutter_layout_manager_get_preferred_width (priv->layout_manager,
1967 /* Default implementation is always 0x0, usually an actor
1968 * using this default is relying on someone to set the
1971 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1976 if (natural_width_p)
1977 *natural_width_p = 0;
1981 clutter_actor_real_get_preferred_height (ClutterActor *self,
1983 gfloat *min_height_p,
1984 gfloat *natural_height_p)
1986 ClutterActorPrivate *priv = self->priv;
1988 if (priv->n_children != 0 &&
1989 priv->layout_manager != NULL)
1991 ClutterContainer *container = CLUTTER_CONTAINER (self);
1993 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1994 "for the preferred height",
1995 G_OBJECT_TYPE_NAME (priv->layout_manager),
1996 priv->layout_manager);
1998 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2006 /* Default implementation is always 0x0, usually an actor
2007 * using this default is relying on someone to set the
2010 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2015 if (natural_height_p)
2016 *natural_height_p = 0;
2020 clutter_actor_store_old_geometry (ClutterActor *self,
2021 ClutterActorBox *box)
2023 *box = self->priv->allocation;
2027 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2028 const ClutterActorBox *old)
2030 ClutterActorPrivate *priv = self->priv;
2031 GObject *obj = G_OBJECT (self);
2033 g_object_freeze_notify (obj);
2035 /* to avoid excessive requisition or allocation cycles we
2036 * use the cached values.
2038 * - if we don't have an allocation we assume that we need
2040 * - if we don't have a width or a height request we notify
2042 * - if we have a valid allocation then we check the old
2043 * bounding box with the current allocation and we notify
2046 if (priv->needs_allocation)
2048 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2049 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2050 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2051 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2053 else if (priv->needs_width_request || priv->needs_height_request)
2055 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2056 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2061 gfloat width, height;
2063 x = priv->allocation.x1;
2064 y = priv->allocation.y1;
2065 width = priv->allocation.x2 - priv->allocation.x1;
2066 height = priv->allocation.y2 - priv->allocation.y1;
2069 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2072 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2074 if (width != (old->x2 - old->x1))
2075 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2077 if (height != (old->y2 - old->y1))
2078 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2081 g_object_thaw_notify (obj);
2085 * clutter_actor_set_allocation_internal:
2086 * @self: a #ClutterActor
2087 * @box: a #ClutterActorBox
2088 * @flags: allocation flags
2090 * Stores the allocation of @self.
2092 * This function only performs basic storage and property notification.
2094 * This function should be called by clutter_actor_set_allocation()
2095 * and by the default implementation of #ClutterActorClass.allocate().
2097 * Return value: %TRUE if the allocation of the #ClutterActor has been
2098 * changed, and %FALSE otherwise
2100 static inline gboolean
2101 clutter_actor_set_allocation_internal (ClutterActor *self,
2102 const ClutterActorBox *box,
2103 ClutterAllocationFlags flags)
2105 ClutterActorPrivate *priv = self->priv;
2107 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2108 gboolean flags_changed;
2110 ClutterActorBox old_alloc = { 0, };
2112 obj = G_OBJECT (self);
2114 g_object_freeze_notify (obj);
2116 clutter_actor_store_old_geometry (self, &old_alloc);
2118 x1_changed = priv->allocation.x1 != box->x1;
2119 y1_changed = priv->allocation.y1 != box->y1;
2120 x2_changed = priv->allocation.x2 != box->x2;
2121 y2_changed = priv->allocation.y2 != box->y2;
2123 flags_changed = priv->allocation_flags != flags;
2125 priv->allocation = *box;
2126 priv->allocation_flags = flags;
2128 /* allocation is authoritative */
2129 priv->needs_width_request = FALSE;
2130 priv->needs_height_request = FALSE;
2131 priv->needs_allocation = FALSE;
2133 if (x1_changed || y1_changed ||
2134 x2_changed || y2_changed ||
2137 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2138 _clutter_actor_get_debug_name (self));
2140 priv->transform_valid = FALSE;
2142 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2144 /* if the allocation changes, so does the content box */
2145 if (priv->content != NULL)
2146 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2153 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2155 g_object_thaw_notify (obj);
2160 static void clutter_actor_real_allocate (ClutterActor *self,
2161 const ClutterActorBox *box,
2162 ClutterAllocationFlags flags);
2165 clutter_actor_maybe_layout_children (ClutterActor *self,
2166 const ClutterActorBox *allocation,
2167 ClutterAllocationFlags flags)
2169 ClutterActorPrivate *priv = self->priv;
2171 /* this is going to be a bit hard to follow, so let's put an explanation
2174 * we want ClutterActor to have a default layout manager if the actor was
2175 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2177 * we also want any subclass of ClutterActor that does not override the
2178 * ::allocate() virtual function to delegate to a layout manager.
2180 * finally, we want to allow people subclassing ClutterActor and overriding
2181 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2183 * on the other hand, we want existing actor subclasses overriding the
2184 * ::allocate() virtual function and chaining up to the parent's
2185 * implementation to continue working without allocating their children
2186 * twice, or without entering an allocation loop.
2188 * for the first two points, we check if the class of the actor is
2189 * overridding the ::allocate() virtual function; if it isn't, then we
2190 * follow through with checking whether we have children and a layout
2191 * manager, and eventually calling clutter_layout_manager_allocate().
2193 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2194 * allocation flags that we got passed, and if it is present, we continue
2195 * with the check above.
2197 * if neither of these two checks yields a positive result, we just
2198 * assume that the ::allocate() virtual function that resulted in this
2199 * function being called will also allocate the children of the actor.
2202 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2205 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2211 if (priv->n_children != 0 &&
2212 priv->layout_manager != NULL)
2214 ClutterContainer *container = CLUTTER_CONTAINER (self);
2215 ClutterAllocationFlags children_flags;
2216 ClutterActorBox children_box;
2218 /* normalize the box passed to the layout manager */
2219 children_box.x1 = children_box.y1 = 0.f;
2220 children_box.x2 = (allocation->x2 - allocation->x1);
2221 children_box.y2 = (allocation->y2 - allocation->y1);
2223 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2224 * the actor's children, since it refers only to the current
2225 * actor's allocation.
2227 children_flags = flags;
2228 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2230 CLUTTER_NOTE (LAYOUT,
2231 "Allocating %d children of %s "
2232 "at { %.2f, %.2f - %.2f x %.2f } "
2235 _clutter_actor_get_debug_name (self),
2238 (allocation->x2 - allocation->x1),
2239 (allocation->y2 - allocation->y1),
2240 G_OBJECT_TYPE_NAME (priv->layout_manager));
2242 clutter_layout_manager_allocate (priv->layout_manager,
2250 clutter_actor_real_allocate (ClutterActor *self,
2251 const ClutterActorBox *box,
2252 ClutterAllocationFlags flags)
2254 ClutterActorPrivate *priv = self->priv;
2257 g_object_freeze_notify (G_OBJECT (self));
2259 changed = clutter_actor_set_allocation_internal (self, box, flags);
2261 /* we allocate our children before we notify changes in our geometry,
2262 * so that people connecting to properties will be able to get valid
2263 * data out of the sub-tree of the scene graph that has this actor at
2266 clutter_actor_maybe_layout_children (self, box, flags);
2270 ClutterActorBox signal_box = priv->allocation;
2271 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2273 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2278 g_object_thaw_notify (G_OBJECT (self));
2282 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2283 ClutterActor *origin)
2285 /* no point in queuing a redraw on a destroyed actor */
2286 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2289 /* NB: We can't bail out early here if the actor is hidden in case
2290 * the actor bas been cloned. In this case the clone will need to
2291 * receive the signal so it can queue its own redraw.
2294 /* calls klass->queue_redraw in default handler */
2295 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2299 clutter_actor_real_queue_redraw (ClutterActor *self,
2300 ClutterActor *origin)
2302 ClutterActor *parent;
2304 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2305 _clutter_actor_get_debug_name (self),
2306 origin != NULL ? _clutter_actor_get_debug_name (origin)
2309 /* no point in queuing a redraw on a destroyed actor */
2310 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2313 /* If the queue redraw is coming from a child then the actor has
2314 become dirty and any queued effect is no longer valid */
2317 self->priv->is_dirty = TRUE;
2318 self->priv->effect_to_redraw = NULL;
2321 /* If the actor isn't visible, we still had to emit the signal
2322 * to allow for a ClutterClone, but the appearance of the parent
2323 * won't change so we don't have to propagate up the hierarchy.
2325 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2328 /* Although we could determine here that a full stage redraw
2329 * has already been queued and immediately bail out, we actually
2330 * guarantee that we will propagate a queue-redraw signal to our
2331 * parent at least once so that it's possible to implement a
2332 * container that tracks which of its children have queued a
2335 if (self->priv->propagated_one_redraw)
2337 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2338 if (stage != NULL &&
2339 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2343 self->priv->propagated_one_redraw = TRUE;
2345 /* notify parents, if they are all visible eventually we'll
2346 * queue redraw on the stage, which queues the redraw idle.
2348 parent = clutter_actor_get_parent (self);
2351 /* this will go up recursively */
2352 _clutter_actor_signal_queue_redraw (parent, origin);
2357 clutter_actor_real_queue_relayout (ClutterActor *self)
2359 ClutterActorPrivate *priv = self->priv;
2361 /* no point in queueing a redraw on a destroyed actor */
2362 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2365 priv->needs_width_request = TRUE;
2366 priv->needs_height_request = TRUE;
2367 priv->needs_allocation = TRUE;
2369 /* reset the cached size requests */
2370 memset (priv->width_requests, 0,
2371 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2372 memset (priv->height_requests, 0,
2373 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2375 /* We need to go all the way up the hierarchy */
2376 if (priv->parent != NULL)
2377 _clutter_actor_queue_only_relayout (priv->parent);
2381 * clutter_actor_apply_relative_transform_to_point:
2382 * @self: A #ClutterActor
2383 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2384 * default #ClutterStage
2385 * @point: A point as #ClutterVertex
2386 * @vertex: (out caller-allocates): The translated #ClutterVertex
2388 * Transforms @point in coordinates relative to the actor into
2389 * ancestor-relative coordinates using the relevant transform
2390 * stack (i.e. scale, rotation, etc).
2392 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2393 * this case, the coordinates returned will be the coordinates on
2394 * the stage before the projection is applied. This is different from
2395 * the behaviour of clutter_actor_apply_transform_to_point().
2400 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2401 ClutterActor *ancestor,
2402 const ClutterVertex *point,
2403 ClutterVertex *vertex)
2408 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2409 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2410 g_return_if_fail (point != NULL);
2411 g_return_if_fail (vertex != NULL);
2416 if (ancestor == NULL)
2417 ancestor = _clutter_actor_get_stage_internal (self);
2419 if (ancestor == NULL)
2425 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2426 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2430 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2431 const ClutterVertex *vertices_in,
2432 ClutterVertex *vertices_out,
2435 ClutterActor *stage;
2436 CoglMatrix modelview;
2437 CoglMatrix projection;
2440 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2442 stage = _clutter_actor_get_stage_internal (self);
2444 /* We really can't do anything meaningful in this case so don't try
2445 * to do any transform */
2449 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2450 * that gets us to stage coordinates, we want to go all the way to eye
2452 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2454 /* Fetch the projection and viewport */
2455 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2456 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2462 _clutter_util_fully_transform_vertices (&modelview,
2473 * clutter_actor_apply_transform_to_point:
2474 * @self: A #ClutterActor
2475 * @point: A point as #ClutterVertex
2476 * @vertex: (out caller-allocates): The translated #ClutterVertex
2478 * Transforms @point in coordinates relative to the actor
2479 * into screen-relative coordinates with the current actor
2480 * transformation (i.e. scale, rotation, etc)
2485 clutter_actor_apply_transform_to_point (ClutterActor *self,
2486 const ClutterVertex *point,
2487 ClutterVertex *vertex)
2489 g_return_if_fail (point != NULL);
2490 g_return_if_fail (vertex != NULL);
2491 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2495 * _clutter_actor_get_relative_transformation_matrix:
2496 * @self: The actor whose coordinate space you want to transform from.
2497 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2498 * or %NULL if you want to transform all the way to eye coordinates.
2499 * @matrix: A #CoglMatrix to store the transformation
2501 * This gets a transformation @matrix that will transform coordinates from the
2502 * coordinate space of @self into the coordinate space of @ancestor.
2504 * For example if you need a matrix that can transform the local actor
2505 * coordinates of @self into stage coordinates you would pass the actor's stage
2506 * pointer as the @ancestor.
2508 * If you pass %NULL then the transformation will take you all the way through
2509 * to eye coordinates. This can be useful if you want to extract the entire
2510 * modelview transform that Clutter applies before applying the projection
2511 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2512 * using cogl_set_modelview_matrix() for example then you would want a matrix
2513 * that transforms into eye coordinates.
2515 * <note><para>This function explicitly initializes the given @matrix. If you just
2516 * want clutter to multiply a relative transformation with an existing matrix
2517 * you can use clutter_actor_apply_relative_transformation_matrix()
2518 * instead.</para></note>
2521 /* XXX: We should consider caching the stage relative modelview along with
2522 * the actor itself */
2524 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2525 ClutterActor *ancestor,
2528 cogl_matrix_init_identity (matrix);
2530 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2533 /* Project the given @box into stage window coordinates, writing the
2534 * transformed vertices to @verts[]. */
2536 _clutter_actor_transform_and_project_box (ClutterActor *self,
2537 const ClutterActorBox *box,
2538 ClutterVertex verts[])
2540 ClutterVertex box_vertices[4];
2542 box_vertices[0].x = box->x1;
2543 box_vertices[0].y = box->y1;
2544 box_vertices[0].z = 0;
2545 box_vertices[1].x = box->x2;
2546 box_vertices[1].y = box->y1;
2547 box_vertices[1].z = 0;
2548 box_vertices[2].x = box->x1;
2549 box_vertices[2].y = box->y2;
2550 box_vertices[2].z = 0;
2551 box_vertices[3].x = box->x2;
2552 box_vertices[3].y = box->y2;
2553 box_vertices[3].z = 0;
2556 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2560 * clutter_actor_get_allocation_vertices:
2561 * @self: A #ClutterActor
2562 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2563 * against, or %NULL to use the #ClutterStage
2564 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2565 * location for an array of 4 #ClutterVertex in which to store the result
2567 * Calculates the transformed coordinates of the four corners of the
2568 * actor in the plane of @ancestor. The returned vertices relate to
2569 * the #ClutterActorBox coordinates as follows:
2571 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2572 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2573 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2574 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2577 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2578 * this case, the coordinates returned will be the coordinates on
2579 * the stage before the projection is applied. This is different from
2580 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2585 clutter_actor_get_allocation_vertices (ClutterActor *self,
2586 ClutterActor *ancestor,
2587 ClutterVertex verts[])
2589 ClutterActorPrivate *priv;
2590 ClutterActorBox box;
2591 ClutterVertex vertices[4];
2592 CoglMatrix modelview;
2594 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2595 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2597 if (ancestor == NULL)
2598 ancestor = _clutter_actor_get_stage_internal (self);
2600 /* Fallback to a NOP transform if the actor isn't parented under a
2602 if (ancestor == NULL)
2607 /* if the actor needs to be allocated we force a relayout, so that
2608 * we will have valid values to use in the transformations */
2609 if (priv->needs_allocation)
2611 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2613 _clutter_stage_maybe_relayout (stage);
2616 box.x1 = box.y1 = 0;
2617 /* The result isn't really meaningful in this case but at
2618 * least try to do something *vaguely* reasonable... */
2619 clutter_actor_get_size (self, &box.x2, &box.y2);
2623 clutter_actor_get_allocation_box (self, &box);
2625 vertices[0].x = box.x1;
2626 vertices[0].y = box.y1;
2628 vertices[1].x = box.x2;
2629 vertices[1].y = box.y1;
2631 vertices[2].x = box.x1;
2632 vertices[2].y = box.y2;
2634 vertices[3].x = box.x2;
2635 vertices[3].y = box.y2;
2638 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2641 cogl_matrix_transform_points (&modelview,
2643 sizeof (ClutterVertex),
2645 sizeof (ClutterVertex),
2651 * clutter_actor_get_abs_allocation_vertices:
2652 * @self: A #ClutterActor
2653 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2654 * of 4 #ClutterVertex where to store the result.
2656 * Calculates the transformed screen coordinates of the four corners of
2657 * the actor; the returned vertices relate to the #ClutterActorBox
2658 * coordinates as follows:
2660 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2661 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2662 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2663 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2669 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2670 ClutterVertex verts[])
2672 ClutterActorPrivate *priv;
2673 ClutterActorBox actor_space_allocation;
2675 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2679 /* if the actor needs to be allocated we force a relayout, so that
2680 * the actor allocation box will be valid for
2681 * _clutter_actor_transform_and_project_box()
2683 if (priv->needs_allocation)
2685 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2686 /* There's nothing meaningful we can do now */
2690 _clutter_stage_maybe_relayout (stage);
2693 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2694 * own coordinate space... */
2695 actor_space_allocation.x1 = 0;
2696 actor_space_allocation.y1 = 0;
2697 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2698 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2699 _clutter_actor_transform_and_project_box (self,
2700 &actor_space_allocation,
2705 clutter_actor_real_apply_transform (ClutterActor *self,
2708 ClutterActorPrivate *priv = self->priv;
2710 if (!priv->transform_valid)
2712 CoglMatrix *transform = &priv->transform;
2713 const ClutterTransformInfo *info;
2715 info = _clutter_actor_get_transform_info_or_defaults (self);
2717 cogl_matrix_init_identity (transform);
2719 cogl_matrix_translate (transform,
2720 priv->allocation.x1,
2721 priv->allocation.y1,
2725 cogl_matrix_translate (transform, 0, 0, info->depth);
2728 * because the rotation involves translations, we must scale
2729 * before applying the rotations (if we apply the scale after
2730 * the rotations, the translations included in the rotation are
2731 * not scaled and so the entire object will move on the screen
2732 * as a result of rotating it).
2734 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2736 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2737 &info->scale_center,
2738 cogl_matrix_scale (transform,
2745 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2747 cogl_matrix_rotate (transform,
2752 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2754 cogl_matrix_rotate (transform,
2759 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2761 cogl_matrix_rotate (transform,
2765 if (!clutter_anchor_coord_is_zero (&info->anchor))
2769 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2770 cogl_matrix_translate (transform, -x, -y, -z);
2773 priv->transform_valid = TRUE;
2776 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2779 /* Applies the transforms associated with this actor to the given
2782 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2785 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2789 * clutter_actor_apply_relative_transformation_matrix:
2790 * @self: The actor whose coordinate space you want to transform from.
2791 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2792 * or %NULL if you want to transform all the way to eye coordinates.
2793 * @matrix: A #CoglMatrix to apply the transformation too.
2795 * This multiplies a transform with @matrix that will transform coordinates
2796 * from the coordinate space of @self into the coordinate space of @ancestor.
2798 * For example if you need a matrix that can transform the local actor
2799 * coordinates of @self into stage coordinates you would pass the actor's stage
2800 * pointer as the @ancestor.
2802 * If you pass %NULL then the transformation will take you all the way through
2803 * to eye coordinates. This can be useful if you want to extract the entire
2804 * modelview transform that Clutter applies before applying the projection
2805 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2806 * using cogl_set_modelview_matrix() for example then you would want a matrix
2807 * that transforms into eye coordinates.
2809 * <note>This function doesn't initialize the given @matrix, it simply
2810 * multiplies the requested transformation matrix with the existing contents of
2811 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2812 * before calling this function, or you can use
2813 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2816 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2817 ClutterActor *ancestor,
2820 ClutterActor *parent;
2822 /* Note we terminate before ever calling stage->apply_transform()
2823 * since that would conceptually be relative to the underlying
2824 * window OpenGL coordinates so we'd need a special @ancestor
2825 * value to represent the fake parent of the stage. */
2826 if (self == ancestor)
2829 parent = clutter_actor_get_parent (self);
2832 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2835 _clutter_actor_apply_modelview_transform (self, matrix);
2839 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2840 ClutterPaintVolume *pv,
2842 const CoglColor *color)
2844 static CoglPipeline *outline = NULL;
2845 CoglPrimitive *prim;
2846 ClutterVertex line_ends[12 * 2];
2849 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2850 /* XXX: at some point we'll query this from the stage but we can't
2851 * do that until the osx backend uses Cogl natively. */
2852 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2854 if (outline == NULL)
2855 outline = cogl_pipeline_new (ctx);
2857 _clutter_paint_volume_complete (pv);
2859 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2862 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2863 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2864 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2865 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2870 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2871 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2872 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2873 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2875 /* Lines connecting front face to back face */
2876 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2877 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2878 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2879 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2882 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2884 (CoglVertexP3 *)line_ends);
2886 cogl_pipeline_set_color (outline, color);
2887 cogl_framebuffer_draw_primitive (fb, outline, prim);
2888 cogl_object_unref (prim);
2892 PangoLayout *layout;
2893 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2894 pango_layout_set_text (layout, label, -1);
2895 cogl_pango_render_layout (layout,
2900 g_object_unref (layout);
2905 _clutter_actor_draw_paint_volume (ClutterActor *self)
2907 ClutterPaintVolume *pv;
2910 pv = _clutter_actor_get_paint_volume_mutable (self);
2913 gfloat width, height;
2914 ClutterPaintVolume fake_pv;
2916 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2917 _clutter_paint_volume_init_static (&fake_pv, stage);
2919 clutter_actor_get_size (self, &width, &height);
2920 clutter_paint_volume_set_width (&fake_pv, width);
2921 clutter_paint_volume_set_height (&fake_pv, height);
2923 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2924 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2925 _clutter_actor_get_debug_name (self),
2928 clutter_paint_volume_free (&fake_pv);
2932 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2933 _clutter_actor_draw_paint_volume_full (self, pv,
2934 _clutter_actor_get_debug_name (self),
2940 _clutter_actor_paint_cull_result (ClutterActor *self,
2942 ClutterCullResult result)
2944 ClutterPaintVolume *pv;
2949 if (result == CLUTTER_CULL_RESULT_IN)
2950 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2951 else if (result == CLUTTER_CULL_RESULT_OUT)
2952 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2954 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2957 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2959 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2960 _clutter_actor_draw_paint_volume_full (self, pv,
2961 _clutter_actor_get_debug_name (self),
2965 PangoLayout *layout;
2967 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2968 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2969 cogl_set_source_color (&color);
2971 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2972 pango_layout_set_text (layout, label, -1);
2973 cogl_pango_render_layout (layout,
2979 g_object_unref (layout);
2983 static int clone_paint_level = 0;
2986 _clutter_actor_push_clone_paint (void)
2988 clone_paint_level++;
2992 _clutter_actor_pop_clone_paint (void)
2994 clone_paint_level--;
2998 in_clone_paint (void)
3000 return clone_paint_level > 0;
3003 /* Returns TRUE if the actor can be ignored */
3004 /* FIXME: we should return a ClutterCullResult, and
3005 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3006 * means there's no point in trying to cull descendants of the current
3009 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3011 ClutterActorPrivate *priv = self->priv;
3012 ClutterActor *stage;
3013 const ClutterPlane *stage_clip;
3015 if (!priv->last_paint_volume_valid)
3017 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3018 "->last_paint_volume_valid == FALSE",
3019 _clutter_actor_get_debug_name (self));
3023 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3026 stage = _clutter_actor_get_stage_internal (self);
3027 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3028 if (G_UNLIKELY (!stage_clip))
3030 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3031 "No stage clip set",
3032 _clutter_actor_get_debug_name (self));
3036 if (cogl_get_draw_framebuffer () !=
3037 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3039 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3040 "Current framebuffer doesn't correspond to stage",
3041 _clutter_actor_get_debug_name (self));
3046 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3051 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3053 ClutterActorPrivate *priv = self->priv;
3054 const ClutterPaintVolume *pv;
3056 if (priv->last_paint_volume_valid)
3058 clutter_paint_volume_free (&priv->last_paint_volume);
3059 priv->last_paint_volume_valid = FALSE;
3062 pv = clutter_actor_get_paint_volume (self);
3065 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3066 "Actor failed to report a paint volume",
3067 _clutter_actor_get_debug_name (self));
3071 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3073 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3074 NULL); /* eye coordinates */
3076 priv->last_paint_volume_valid = TRUE;
3079 static inline gboolean
3080 actor_has_shader_data (ClutterActor *self)
3082 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3086 _clutter_actor_get_pick_id (ClutterActor *self)
3088 if (self->priv->pick_id < 0)
3091 return self->priv->pick_id;
3094 /* This is the same as clutter_actor_add_effect except that it doesn't
3095 queue a redraw and it doesn't notify on the effect property */
3097 _clutter_actor_add_effect_internal (ClutterActor *self,
3098 ClutterEffect *effect)
3100 ClutterActorPrivate *priv = self->priv;
3102 if (priv->effects == NULL)
3104 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3105 priv->effects->actor = self;
3108 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3111 /* This is the same as clutter_actor_remove_effect except that it doesn't
3112 queue a redraw and it doesn't notify on the effect property */
3114 _clutter_actor_remove_effect_internal (ClutterActor *self,
3115 ClutterEffect *effect)
3117 ClutterActorPrivate *priv = self->priv;
3119 if (priv->effects == NULL)
3122 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3126 needs_flatten_effect (ClutterActor *self)
3128 ClutterActorPrivate *priv = self->priv;
3130 if (G_UNLIKELY (clutter_paint_debug_flags &
3131 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3134 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3136 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3138 if (clutter_actor_get_paint_opacity (self) < 255 &&
3139 clutter_actor_has_overlaps (self))
3147 add_or_remove_flatten_effect (ClutterActor *self)
3149 ClutterActorPrivate *priv = self->priv;
3151 /* Add or remove the flatten effect depending on the
3152 offscreen-redirect property. */
3153 if (needs_flatten_effect (self))
3155 if (priv->flatten_effect == NULL)
3157 ClutterActorMeta *actor_meta;
3160 priv->flatten_effect = _clutter_flatten_effect_new ();
3161 /* Keep a reference to the effect so that we can queue
3163 g_object_ref_sink (priv->flatten_effect);
3165 /* Set the priority of the effect to high so that it will
3166 always be applied to the actor first. It uses an internal
3167 priority so that it won't be visible to applications */
3168 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3169 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3170 _clutter_actor_meta_set_priority (actor_meta, priority);
3172 /* This will add the effect without queueing a redraw */
3173 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3178 if (priv->flatten_effect != NULL)
3180 /* Destroy the effect so that it will lose its fbo cache of
3182 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3183 g_clear_object (&priv->flatten_effect);
3189 clutter_actor_real_paint (ClutterActor *actor)
3191 ClutterActorPrivate *priv = actor->priv;
3194 for (iter = priv->first_child;
3196 iter = iter->priv->next_sibling)
3198 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3199 _clutter_actor_get_debug_name (iter),
3200 _clutter_actor_get_debug_name (actor),
3201 iter->priv->allocation.x1,
3202 iter->priv->allocation.y1,
3203 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3204 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3206 clutter_actor_paint (iter);
3211 clutter_actor_paint_node (ClutterActor *actor,
3212 ClutterPaintNode *root)
3214 ClutterActorPrivate *priv = actor->priv;
3219 if (priv->bg_color_set &&
3220 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3222 ClutterPaintNode *node;
3223 ClutterColor bg_color;
3224 ClutterActorBox box;
3228 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3229 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3231 bg_color = priv->bg_color;
3232 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3233 * priv->bg_color.alpha
3236 node = clutter_color_node_new (&bg_color);
3237 clutter_paint_node_set_name (node, "backgroundColor");
3238 clutter_paint_node_add_rectangle (node, &box);
3239 clutter_paint_node_add_child (root, node);
3240 clutter_paint_node_unref (node);
3243 if (priv->content != NULL)
3244 _clutter_content_paint_content (priv->content, actor, root);
3246 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3247 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3249 if (clutter_paint_node_get_n_children (root) == 0)
3252 #ifdef CLUTTER_ENABLE_DEBUG
3253 if (CLUTTER_HAS_DEBUG (PAINT))
3255 /* dump the tree only if we have one */
3256 _clutter_paint_node_dump_tree (root);
3258 #endif /* CLUTTER_ENABLE_DEBUG */
3260 _clutter_paint_node_paint (root);
3263 /* XXX: Uncomment this when we disable emitting the paint signal */
3264 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3271 * clutter_actor_paint:
3272 * @self: A #ClutterActor
3274 * Renders the actor to display.
3276 * This function should not be called directly by applications.
3277 * Call clutter_actor_queue_redraw() to queue paints, instead.
3279 * This function is context-aware, and will either cause a
3280 * regular paint or a pick paint.
3282 * This function will emit the #ClutterActor::paint signal or
3283 * the #ClutterActor::pick signal, depending on the context.
3285 * This function does not paint the actor if the actor is set to 0,
3286 * unless it is performing a pick paint.
3289 clutter_actor_paint (ClutterActor *self)
3291 ClutterActorPrivate *priv;
3292 ClutterPickMode pick_mode;
3293 gboolean clip_set = FALSE;
3294 gboolean shader_applied = FALSE;
3296 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3297 "Actor real-paint counter",
3298 "Increments each time any actor is painted",
3299 0 /* no application private data */);
3300 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3301 "Actor pick-paint counter",
3302 "Increments each time any actor is painted "
3304 0 /* no application private data */);
3306 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3308 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3313 pick_mode = _clutter_context_get_pick_mode ();
3315 if (pick_mode == CLUTTER_PICK_NONE)
3316 priv->propagated_one_redraw = FALSE;
3318 /* It's an important optimization that we consider painting of
3319 * actors with 0 opacity to be a NOP... */
3320 if (pick_mode == CLUTTER_PICK_NONE &&
3321 /* ignore top-levels, since they might be transparent */
3322 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3323 /* Use the override opacity if its been set */
3324 ((priv->opacity_override >= 0) ?
3325 priv->opacity_override : priv->opacity) == 0)
3328 /* if we aren't paintable (not in a toplevel with all
3329 * parents paintable) then do nothing.
3331 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3334 /* mark that we are in the paint process */
3335 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3339 if (priv->enable_model_view_transform)
3343 /* XXX: It could be better to cache the modelview with the actor
3344 * instead of progressively building up the transformations on
3345 * the matrix stack every time we paint. */
3346 cogl_get_modelview_matrix (&matrix);
3347 _clutter_actor_apply_modelview_transform (self, &matrix);
3349 #ifdef CLUTTER_ENABLE_DEBUG
3350 /* Catch when out-of-band transforms have been made by actors not as part
3351 * of an apply_transform vfunc... */
3352 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3354 CoglMatrix expected_matrix;
3356 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3359 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3361 GString *buf = g_string_sized_new (1024);
3362 ClutterActor *parent;
3365 while (parent != NULL)
3367 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3369 if (parent->priv->parent != NULL)
3370 g_string_append (buf, "->");
3372 parent = parent->priv->parent;
3375 g_warning ("Unexpected transform found when painting actor "
3376 "\"%s\". This will be caused by one of the actor's "
3377 "ancestors (%s) using the Cogl API directly to transform "
3378 "children instead of using ::apply_transform().",
3379 _clutter_actor_get_debug_name (self),
3382 g_string_free (buf, TRUE);
3385 #endif /* CLUTTER_ENABLE_DEBUG */
3387 cogl_set_modelview_matrix (&matrix);
3392 cogl_clip_push_rectangle (priv->clip.x,
3394 priv->clip.x + priv->clip.width,
3395 priv->clip.y + priv->clip.height);
3398 else if (priv->clip_to_allocation)
3400 gfloat width, height;
3402 width = priv->allocation.x2 - priv->allocation.x1;
3403 height = priv->allocation.y2 - priv->allocation.y1;
3405 cogl_clip_push_rectangle (0, 0, width, height);
3409 if (pick_mode == CLUTTER_PICK_NONE)
3411 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3413 /* We check whether we need to add the flatten effect before
3414 each paint so that we can avoid having a mechanism for
3415 applications to notify when the value of the
3416 has_overlaps virtual changes. */
3417 add_or_remove_flatten_effect (self);
3420 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3422 /* We save the current paint volume so that the next time the
3423 * actor queues a redraw we can constrain the redraw to just
3424 * cover the union of the new bounding box and the old.
3426 * We also fetch the current paint volume to perform culling so
3427 * we can avoid painting actors outside the current clip region.
3429 * If we are painting inside a clone, we should neither update
3430 * the paint volume or use it to cull painting, since the paint
3431 * box represents the location of the source actor on the
3434 * XXX: We are starting to do a lot of vertex transforms on
3435 * the CPU in a typical paint, so at some point we should
3436 * audit these and consider caching some things.
3438 * NB: We don't perform culling while picking at this point because
3439 * clutter-stage.c doesn't setup the clipping planes appropriately.
3441 * NB: We don't want to update the last-paint-volume during picking
3442 * because the last-paint-volume is used to determine the old screen
3443 * space location of an actor that has moved so we can know the
3444 * minimal region to redraw to clear an old view of the actor. If we
3445 * update this during picking then by the time we come around to
3446 * paint then the last-paint-volume would likely represent the new
3447 * actor position not the old.
3449 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3452 /* annoyingly gcc warns if uninitialized even though
3453 * the initialization is redundant :-( */
3454 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3456 if (G_LIKELY ((clutter_paint_debug_flags &
3457 (CLUTTER_DEBUG_DISABLE_CULLING |
3458 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3459 (CLUTTER_DEBUG_DISABLE_CULLING |
3460 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3461 _clutter_actor_update_last_paint_volume (self);
3463 success = cull_actor (self, &result);
3465 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3466 _clutter_actor_paint_cull_result (self, success, result);
3467 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3471 if (priv->effects == NULL)
3473 if (pick_mode == CLUTTER_PICK_NONE &&
3474 actor_has_shader_data (self))
3476 _clutter_actor_shader_pre_paint (self, FALSE);
3477 shader_applied = TRUE;
3480 priv->next_effect_to_paint = NULL;
3483 priv->next_effect_to_paint =
3484 _clutter_meta_group_peek_metas (priv->effects);
3486 clutter_actor_continue_paint (self);
3489 _clutter_actor_shader_post_paint (self);
3491 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3492 pick_mode == CLUTTER_PICK_NONE))
3493 _clutter_actor_draw_paint_volume (self);
3496 /* If we make it here then the actor has run through a complete
3497 paint run including all the effects so it's no longer dirty */
3498 if (pick_mode == CLUTTER_PICK_NONE)
3499 priv->is_dirty = FALSE;
3506 /* paint sequence complete */
3507 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3511 * clutter_actor_continue_paint:
3512 * @self: A #ClutterActor
3514 * Run the next stage of the paint sequence. This function should only
3515 * be called within the implementation of the ‘run’ virtual of a
3516 * #ClutterEffect. It will cause the run method of the next effect to
3517 * be applied, or it will paint the actual actor if the current effect
3518 * is the last effect in the chain.
3523 clutter_actor_continue_paint (ClutterActor *self)
3525 ClutterActorPrivate *priv;
3527 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3528 /* This should only be called from with in the ‘run’ implementation
3529 of a ClutterEffect */
3530 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3534 /* Skip any effects that are disabled */
3535 while (priv->next_effect_to_paint &&
3536 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3537 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3539 /* If this has come from the last effect then we'll just paint the
3541 if (priv->next_effect_to_paint == NULL)
3543 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3545 ClutterPaintNode *dummy;
3547 /* XXX - this will go away in 2.0, when we can get rid of this
3548 * stuff and switch to a pure retained render tree of PaintNodes
3549 * for the entire frame, starting from the Stage; the paint()
3550 * virtual function can then be called directly.
3552 dummy = _clutter_dummy_node_new (self);
3553 clutter_paint_node_set_name (dummy, "Root");
3555 /* XXX - for 1.12, we use the return value of paint_node() to
3556 * decide whether we should emit the ::paint signal.
3558 clutter_actor_paint_node (self, dummy);
3559 clutter_paint_node_unref (dummy);
3561 g_signal_emit (self, actor_signals[PAINT], 0);
3565 ClutterColor col = { 0, };
3567 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3569 /* Actor will then paint silhouette of itself in supplied
3570 * color. See clutter_stage_get_actor_at_pos() for where
3571 * picking is enabled.
3573 g_signal_emit (self, actor_signals[PICK], 0, &col);
3578 ClutterEffect *old_current_effect;
3579 ClutterEffectPaintFlags run_flags = 0;
3581 /* Cache the current effect so that we can put it back before
3583 old_current_effect = priv->current_effect;
3585 priv->current_effect = priv->next_effect_to_paint->data;
3586 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3588 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3592 /* If there's an effect queued with this redraw then all
3593 effects up to that one will be considered dirty. It
3594 is expected the queued effect will paint the cached
3595 image and not call clutter_actor_continue_paint again
3596 (although it should work ok if it does) */
3597 if (priv->effect_to_redraw == NULL ||
3598 priv->current_effect != priv->effect_to_redraw)
3599 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3602 _clutter_effect_paint (priv->current_effect, run_flags);
3606 /* We can't determine when an actor has been modified since
3607 its last pick so lets just assume it has always been
3609 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3611 _clutter_effect_pick (priv->current_effect, run_flags);
3614 priv->current_effect = old_current_effect;
3618 static ClutterActorTraverseVisitFlags
3619 invalidate_queue_redraw_entry (ClutterActor *self,
3623 ClutterActorPrivate *priv = self->priv;
3625 if (priv->queue_redraw_entry != NULL)
3627 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3628 priv->queue_redraw_entry = NULL;
3631 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3635 remove_child (ClutterActor *self,
3636 ClutterActor *child)
3638 ClutterActor *prev_sibling, *next_sibling;
3640 prev_sibling = child->priv->prev_sibling;
3641 next_sibling = child->priv->next_sibling;
3643 if (prev_sibling != NULL)
3644 prev_sibling->priv->next_sibling = next_sibling;
3646 if (next_sibling != NULL)
3647 next_sibling->priv->prev_sibling = prev_sibling;
3649 if (self->priv->first_child == child)
3650 self->priv->first_child = next_sibling;
3652 if (self->priv->last_child == child)
3653 self->priv->last_child = prev_sibling;
3655 child->priv->parent = NULL;
3656 child->priv->prev_sibling = NULL;
3657 child->priv->next_sibling = NULL;
3661 REMOVE_CHILD_DESTROY_META = 1 << 0,
3662 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3663 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3664 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3665 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3666 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3668 /* default flags for public API */
3669 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3670 REMOVE_CHILD_EMIT_PARENT_SET |
3671 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3672 REMOVE_CHILD_CHECK_STATE |
3673 REMOVE_CHILD_FLUSH_QUEUE |
3674 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3676 /* flags for legacy/deprecated API */
3677 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3678 REMOVE_CHILD_FLUSH_QUEUE |
3679 REMOVE_CHILD_EMIT_PARENT_SET |
3680 REMOVE_CHILD_NOTIFY_FIRST_LAST
3681 } ClutterActorRemoveChildFlags;
3684 * clutter_actor_remove_child_internal:
3685 * @self: a #ClutterActor
3686 * @child: the child of @self that has to be removed
3687 * @flags: control the removal operations
3689 * Removes @child from the list of children of @self.
3692 clutter_actor_remove_child_internal (ClutterActor *self,
3693 ClutterActor *child,
3694 ClutterActorRemoveChildFlags flags)
3696 ClutterActor *old_first, *old_last;
3697 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3698 gboolean flush_queue;
3699 gboolean notify_first_last;
3700 gboolean was_mapped;
3702 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3703 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3704 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3705 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3706 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3707 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3709 g_object_freeze_notify (G_OBJECT (self));
3712 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3716 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3718 /* we need to unrealize *before* we set parent_actor to NULL,
3719 * because in an unrealize method actors are dissociating from the
3720 * stage, which means they need to be able to
3721 * clutter_actor_get_stage().
3723 * yhis should unmap and unrealize, unless we're reparenting.
3725 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3732 /* We take this opportunity to invalidate any queue redraw entry
3733 * associated with the actor and descendants since we won't be able to
3734 * determine the appropriate stage after this.
3736 * we do this after we updated the mapped state because actors might
3737 * end up queueing redraws inside their mapped/unmapped virtual
3738 * functions, and if we invalidate the redraw entry we could end up
3739 * with an inconsistent state and weird memory corruption. see
3742 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3743 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3745 _clutter_actor_traverse (child,
3747 invalidate_queue_redraw_entry,
3752 old_first = self->priv->first_child;
3753 old_last = self->priv->last_child;
3755 remove_child (self, child);
3757 self->priv->n_children -= 1;
3759 self->priv->age += 1;
3761 /* clutter_actor_reparent() will emit ::parent-set for us */
3762 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3763 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3765 /* if the child was mapped then we need to relayout ourselves to account
3766 * for the removed child
3769 clutter_actor_queue_relayout (self);
3771 /* we need to emit the signal before dropping the reference */
3772 if (emit_actor_removed)
3773 g_signal_emit_by_name (self, "actor-removed", child);
3775 if (notify_first_last)
3777 if (old_first != self->priv->first_child)
3778 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3780 if (old_last != self->priv->last_child)
3781 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3784 g_object_thaw_notify (G_OBJECT (self));
3786 /* remove the reference we acquired in clutter_actor_add_child() */
3787 g_object_unref (child);
3790 static const ClutterTransformInfo default_transform_info = {
3791 0.0, { 0, }, /* rotation-x */
3792 0.0, { 0, }, /* rotation-y */
3793 0.0, { 0, }, /* rotation-z */
3795 1.0, 1.0, { 0, }, /* scale */
3797 { 0, }, /* anchor */
3803 * _clutter_actor_get_transform_info_or_defaults:
3804 * @self: a #ClutterActor
3806 * Retrieves the ClutterTransformInfo structure associated to an actor.
3808 * If the actor does not have a ClutterTransformInfo structure associated
3809 * to it, then the default structure will be returned.
3811 * This function should only be used for getters.
3813 * Return value: a const pointer to the ClutterTransformInfo structure
3815 const ClutterTransformInfo *
3816 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3818 ClutterTransformInfo *info;
3820 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3824 return &default_transform_info;
3828 clutter_transform_info_free (gpointer data)
3831 g_slice_free (ClutterTransformInfo, data);
3835 * _clutter_actor_get_transform_info:
3836 * @self: a #ClutterActor
3838 * Retrieves a pointer to the ClutterTransformInfo structure.
3840 * If the actor does not have a ClutterTransformInfo associated to it, one
3841 * will be created and initialized to the default values.
3843 * This function should be used for setters.
3845 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3848 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3851 ClutterTransformInfo *
3852 _clutter_actor_get_transform_info (ClutterActor *self)
3854 ClutterTransformInfo *info;
3856 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3859 info = g_slice_new (ClutterTransformInfo);
3861 *info = default_transform_info;
3863 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3865 clutter_transform_info_free);
3872 * clutter_actor_set_rotation_angle_internal:
3873 * @self: a #ClutterActor
3874 * @axis: the axis of the angle to change
3875 * @angle: the angle of rotation
3877 * Sets the rotation angle on the given axis without affecting the
3878 * rotation center point.
3881 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3882 ClutterRotateAxis axis,
3885 GObject *obj = G_OBJECT (self);
3886 ClutterTransformInfo *info;
3888 info = _clutter_actor_get_transform_info (self);
3890 g_object_freeze_notify (obj);
3894 case CLUTTER_X_AXIS:
3895 info->rx_angle = angle;
3896 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3899 case CLUTTER_Y_AXIS:
3900 info->ry_angle = angle;
3901 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3904 case CLUTTER_Z_AXIS:
3905 info->rz_angle = angle;
3906 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3910 self->priv->transform_valid = FALSE;
3912 g_object_thaw_notify (obj);
3914 clutter_actor_queue_redraw (self);
3918 clutter_actor_set_rotation_angle (ClutterActor *self,
3919 ClutterRotateAxis axis,
3922 ClutterTransformInfo *info;
3924 info = _clutter_actor_get_transform_info (self);
3926 if (clutter_actor_get_easing_duration (self) != 0)
3928 ClutterTransition *transition;
3929 GParamSpec *pspec = NULL;
3930 double *cur_angle_p = NULL;
3934 case CLUTTER_X_AXIS:
3935 cur_angle_p = &info->rx_angle;
3936 pspec = obj_props[PROP_ROTATION_ANGLE_X];
3939 case CLUTTER_Y_AXIS:
3940 cur_angle_p = &info->ry_angle;
3941 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3944 case CLUTTER_Z_AXIS:
3945 cur_angle_p = &info->rz_angle;
3946 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3950 g_assert (pspec != NULL);
3951 g_assert (cur_angle_p != NULL);
3953 transition = _clutter_actor_get_transition (self, pspec);
3954 if (transition == NULL)
3956 transition = _clutter_actor_create_transition (self, pspec,
3961 _clutter_actor_update_transition (self, pspec, angle);
3963 self->priv->transform_valid = FALSE;
3964 clutter_actor_queue_redraw (self);
3967 clutter_actor_set_rotation_angle_internal (self, axis, angle);
3971 * clutter_actor_set_rotation_center_internal:
3972 * @self: a #ClutterActor
3973 * @axis: the axis of the center to change
3974 * @center: the coordinates of the rotation center
3976 * Sets the rotation center on the given axis without affecting the
3980 clutter_actor_set_rotation_center_internal (ClutterActor *self,
3981 ClutterRotateAxis axis,
3982 const ClutterVertex *center)
3984 GObject *obj = G_OBJECT (self);
3985 ClutterTransformInfo *info;
3986 ClutterVertex v = { 0, 0, 0 };
3988 info = _clutter_actor_get_transform_info (self);
3993 g_object_freeze_notify (obj);
3997 case CLUTTER_X_AXIS:
3998 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3999 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4002 case CLUTTER_Y_AXIS:
4003 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4004 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4007 case CLUTTER_Z_AXIS:
4008 /* if the previously set rotation center was fractional, then
4009 * setting explicit coordinates will have to notify the
4010 * :rotation-center-z-gravity property as well
4012 if (info->rz_center.is_fractional)
4013 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4015 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4016 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4020 self->priv->transform_valid = FALSE;
4022 g_object_thaw_notify (obj);
4024 clutter_actor_queue_redraw (self);
4028 clutter_actor_animate_scale_factor (ClutterActor *self,
4033 ClutterTransition *transition;
4035 transition = _clutter_actor_get_transition (self, pspec);
4036 if (transition == NULL)
4038 transition = _clutter_actor_create_transition (self, pspec,
4043 _clutter_actor_update_transition (self, pspec, new_factor);
4046 self->priv->transform_valid = FALSE;
4047 clutter_actor_queue_redraw (self);
4051 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4055 GObject *obj = G_OBJECT (self);
4056 ClutterTransformInfo *info;
4058 info = _clutter_actor_get_transform_info (self);
4060 if (pspec == obj_props[PROP_SCALE_X])
4061 info->scale_x = factor;
4063 info->scale_y = factor;
4065 self->priv->transform_valid = FALSE;
4066 clutter_actor_queue_redraw (self);
4067 g_object_notify_by_pspec (obj, pspec);
4071 clutter_actor_set_scale_factor (ClutterActor *self,
4072 ClutterRotateAxis axis,
4075 GObject *obj = G_OBJECT (self);
4076 ClutterTransformInfo *info;
4079 info = _clutter_actor_get_transform_info (self);
4081 g_object_freeze_notify (obj);
4085 case CLUTTER_X_AXIS:
4086 pspec = obj_props[PROP_SCALE_X];
4088 if (clutter_actor_get_easing_duration (self) != 0)
4089 clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4091 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4094 case CLUTTER_Y_AXIS:
4095 pspec = obj_props[PROP_SCALE_Y];
4097 if (clutter_actor_get_easing_duration (self) != 0)
4098 clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4100 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4104 g_assert_not_reached ();
4107 g_object_thaw_notify (obj);
4111 clutter_actor_set_scale_center (ClutterActor *self,
4112 ClutterRotateAxis axis,
4115 GObject *obj = G_OBJECT (self);
4116 ClutterTransformInfo *info;
4117 gfloat center_x, center_y;
4119 info = _clutter_actor_get_transform_info (self);
4121 g_object_freeze_notify (obj);
4123 /* get the current scale center coordinates */
4124 clutter_anchor_coord_get_units (self, &info->scale_center,
4129 /* we need to notify this too, because setting explicit coordinates will
4130 * change the gravity as a side effect
4132 if (info->scale_center.is_fractional)
4133 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4137 case CLUTTER_X_AXIS:
4138 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4139 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4142 case CLUTTER_Y_AXIS:
4143 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4144 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4148 g_assert_not_reached ();
4151 self->priv->transform_valid = FALSE;
4153 clutter_actor_queue_redraw (self);
4155 g_object_thaw_notify (obj);
4159 clutter_actor_set_scale_gravity (ClutterActor *self,
4160 ClutterGravity gravity)
4162 ClutterTransformInfo *info;
4165 info = _clutter_actor_get_transform_info (self);
4166 obj = G_OBJECT (self);
4168 if (gravity == CLUTTER_GRAVITY_NONE)
4169 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4171 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4173 self->priv->transform_valid = FALSE;
4175 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4176 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4177 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4179 clutter_actor_queue_redraw (self);
4183 clutter_actor_set_anchor_coord (ClutterActor *self,
4184 ClutterRotateAxis axis,
4187 GObject *obj = G_OBJECT (self);
4188 ClutterTransformInfo *info;
4189 gfloat anchor_x, anchor_y;
4191 info = _clutter_actor_get_transform_info (self);
4193 g_object_freeze_notify (obj);
4195 clutter_anchor_coord_get_units (self, &info->anchor,
4200 if (info->anchor.is_fractional)
4201 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4205 case CLUTTER_X_AXIS:
4206 clutter_anchor_coord_set_units (&info->anchor,
4210 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4213 case CLUTTER_Y_AXIS:
4214 clutter_anchor_coord_set_units (&info->anchor,
4218 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4222 g_assert_not_reached ();
4225 self->priv->transform_valid = FALSE;
4227 clutter_actor_queue_redraw (self);
4229 g_object_thaw_notify (obj);
4233 clutter_actor_set_property (GObject *object,
4235 const GValue *value,
4238 ClutterActor *actor = CLUTTER_ACTOR (object);
4239 ClutterActorPrivate *priv = actor->priv;
4244 clutter_actor_set_x (actor, g_value_get_float (value));
4248 clutter_actor_set_y (actor, g_value_get_float (value));
4252 clutter_actor_set_width (actor, g_value_get_float (value));
4256 clutter_actor_set_height (actor, g_value_get_float (value));
4260 clutter_actor_set_x (actor, g_value_get_float (value));
4264 clutter_actor_set_y (actor, g_value_get_float (value));
4267 case PROP_FIXED_POSITION_SET:
4268 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4271 case PROP_MIN_WIDTH:
4272 clutter_actor_set_min_width (actor, g_value_get_float (value));
4275 case PROP_MIN_HEIGHT:
4276 clutter_actor_set_min_height (actor, g_value_get_float (value));
4279 case PROP_NATURAL_WIDTH:
4280 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4283 case PROP_NATURAL_HEIGHT:
4284 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4287 case PROP_MIN_WIDTH_SET:
4288 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4291 case PROP_MIN_HEIGHT_SET:
4292 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4295 case PROP_NATURAL_WIDTH_SET:
4296 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4299 case PROP_NATURAL_HEIGHT_SET:
4300 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4303 case PROP_REQUEST_MODE:
4304 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4308 clutter_actor_set_depth (actor, g_value_get_float (value));
4312 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4315 case PROP_OFFSCREEN_REDIRECT:
4316 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4320 clutter_actor_set_name (actor, g_value_get_string (value));
4324 if (g_value_get_boolean (value) == TRUE)
4325 clutter_actor_show (actor);
4327 clutter_actor_hide (actor);
4331 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4332 g_value_get_double (value));
4336 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4337 g_value_get_double (value));
4340 case PROP_SCALE_CENTER_X:
4341 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4342 g_value_get_float (value));
4345 case PROP_SCALE_CENTER_Y:
4346 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4347 g_value_get_float (value));
4350 case PROP_SCALE_GRAVITY:
4351 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4356 const ClutterGeometry *geom = g_value_get_boxed (value);
4358 clutter_actor_set_clip (actor,
4360 geom->width, geom->height);
4364 case PROP_CLIP_TO_ALLOCATION:
4365 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4369 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4372 case PROP_ROTATION_ANGLE_X:
4373 clutter_actor_set_rotation_angle (actor,
4375 g_value_get_double (value));
4378 case PROP_ROTATION_ANGLE_Y:
4379 clutter_actor_set_rotation_angle (actor,
4381 g_value_get_double (value));
4384 case PROP_ROTATION_ANGLE_Z:
4385 clutter_actor_set_rotation_angle (actor,
4387 g_value_get_double (value));
4390 case PROP_ROTATION_CENTER_X:
4391 clutter_actor_set_rotation_center_internal (actor,
4393 g_value_get_boxed (value));
4396 case PROP_ROTATION_CENTER_Y:
4397 clutter_actor_set_rotation_center_internal (actor,
4399 g_value_get_boxed (value));
4402 case PROP_ROTATION_CENTER_Z:
4403 clutter_actor_set_rotation_center_internal (actor,
4405 g_value_get_boxed (value));
4408 case PROP_ROTATION_CENTER_Z_GRAVITY:
4410 const ClutterTransformInfo *info;
4412 info = _clutter_actor_get_transform_info_or_defaults (actor);
4413 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4414 g_value_get_enum (value));
4419 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4420 g_value_get_float (value));
4424 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4425 g_value_get_float (value));
4428 case PROP_ANCHOR_GRAVITY:
4429 clutter_actor_set_anchor_point_from_gravity (actor,
4430 g_value_get_enum (value));
4433 case PROP_SHOW_ON_SET_PARENT:
4434 priv->show_on_set_parent = g_value_get_boolean (value);
4437 case PROP_TEXT_DIRECTION:
4438 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4442 clutter_actor_add_action (actor, g_value_get_object (value));
4445 case PROP_CONSTRAINTS:
4446 clutter_actor_add_constraint (actor, g_value_get_object (value));
4450 clutter_actor_add_effect (actor, g_value_get_object (value));
4453 case PROP_LAYOUT_MANAGER:
4454 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4458 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4462 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4465 case PROP_MARGIN_TOP:
4466 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4469 case PROP_MARGIN_BOTTOM:
4470 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4473 case PROP_MARGIN_LEFT:
4474 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4477 case PROP_MARGIN_RIGHT:
4478 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4481 case PROP_BACKGROUND_COLOR:
4482 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4486 clutter_actor_set_content (actor, g_value_get_object (value));
4489 case PROP_CONTENT_GRAVITY:
4490 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4493 case PROP_MINIFICATION_FILTER:
4494 clutter_actor_set_content_scaling_filters (actor,
4495 g_value_get_enum (value),
4496 actor->priv->mag_filter);
4499 case PROP_MAGNIFICATION_FILTER:
4500 clutter_actor_set_content_scaling_filters (actor,
4501 actor->priv->min_filter,
4502 g_value_get_enum (value));
4506 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4512 clutter_actor_get_property (GObject *object,
4517 ClutterActor *actor = CLUTTER_ACTOR (object);
4518 ClutterActorPrivate *priv = actor->priv;
4523 g_value_set_float (value, clutter_actor_get_x (actor));
4527 g_value_set_float (value, clutter_actor_get_y (actor));
4531 g_value_set_float (value, clutter_actor_get_width (actor));
4535 g_value_set_float (value, clutter_actor_get_height (actor));
4540 const ClutterLayoutInfo *info;
4542 info = _clutter_actor_get_layout_info_or_defaults (actor);
4543 g_value_set_float (value, info->fixed_x);
4549 const ClutterLayoutInfo *info;
4551 info = _clutter_actor_get_layout_info_or_defaults (actor);
4552 g_value_set_float (value, info->fixed_y);
4556 case PROP_FIXED_POSITION_SET:
4557 g_value_set_boolean (value, priv->position_set);
4560 case PROP_MIN_WIDTH:
4562 const ClutterLayoutInfo *info;
4564 info = _clutter_actor_get_layout_info_or_defaults (actor);
4565 g_value_set_float (value, info->min_width);
4569 case PROP_MIN_HEIGHT:
4571 const ClutterLayoutInfo *info;
4573 info = _clutter_actor_get_layout_info_or_defaults (actor);
4574 g_value_set_float (value, info->min_height);
4578 case PROP_NATURAL_WIDTH:
4580 const ClutterLayoutInfo *info;
4582 info = _clutter_actor_get_layout_info_or_defaults (actor);
4583 g_value_set_float (value, info->natural_width);
4587 case PROP_NATURAL_HEIGHT:
4589 const ClutterLayoutInfo *info;
4591 info = _clutter_actor_get_layout_info_or_defaults (actor);
4592 g_value_set_float (value, info->natural_height);
4596 case PROP_MIN_WIDTH_SET:
4597 g_value_set_boolean (value, priv->min_width_set);
4600 case PROP_MIN_HEIGHT_SET:
4601 g_value_set_boolean (value, priv->min_height_set);
4604 case PROP_NATURAL_WIDTH_SET:
4605 g_value_set_boolean (value, priv->natural_width_set);
4608 case PROP_NATURAL_HEIGHT_SET:
4609 g_value_set_boolean (value, priv->natural_height_set);
4612 case PROP_REQUEST_MODE:
4613 g_value_set_enum (value, priv->request_mode);
4616 case PROP_ALLOCATION:
4617 g_value_set_boxed (value, &priv->allocation);
4621 g_value_set_float (value, clutter_actor_get_depth (actor));
4625 g_value_set_uint (value, priv->opacity);
4628 case PROP_OFFSCREEN_REDIRECT:
4629 g_value_set_enum (value, priv->offscreen_redirect);
4633 g_value_set_string (value, priv->name);
4637 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4641 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4645 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4649 g_value_set_boolean (value, priv->has_clip);
4654 ClutterGeometry clip;
4656 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4657 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4658 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4659 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4661 g_value_set_boxed (value, &clip);
4665 case PROP_CLIP_TO_ALLOCATION:
4666 g_value_set_boolean (value, priv->clip_to_allocation);
4671 const ClutterTransformInfo *info;
4673 info = _clutter_actor_get_transform_info_or_defaults (actor);
4674 g_value_set_double (value, info->scale_x);
4680 const ClutterTransformInfo *info;
4682 info = _clutter_actor_get_transform_info_or_defaults (actor);
4683 g_value_set_double (value, info->scale_y);
4687 case PROP_SCALE_CENTER_X:
4691 clutter_actor_get_scale_center (actor, ¢er, NULL);
4693 g_value_set_float (value, center);
4697 case PROP_SCALE_CENTER_Y:
4701 clutter_actor_get_scale_center (actor, NULL, ¢er);
4703 g_value_set_float (value, center);
4707 case PROP_SCALE_GRAVITY:
4708 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4712 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4715 case PROP_ROTATION_ANGLE_X:
4717 const ClutterTransformInfo *info;
4719 info = _clutter_actor_get_transform_info_or_defaults (actor);
4720 g_value_set_double (value, info->rx_angle);
4724 case PROP_ROTATION_ANGLE_Y:
4726 const ClutterTransformInfo *info;
4728 info = _clutter_actor_get_transform_info_or_defaults (actor);
4729 g_value_set_double (value, info->ry_angle);
4733 case PROP_ROTATION_ANGLE_Z:
4735 const ClutterTransformInfo *info;
4737 info = _clutter_actor_get_transform_info_or_defaults (actor);
4738 g_value_set_double (value, info->rz_angle);
4742 case PROP_ROTATION_CENTER_X:
4744 ClutterVertex center;
4746 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4751 g_value_set_boxed (value, ¢er);
4755 case PROP_ROTATION_CENTER_Y:
4757 ClutterVertex center;
4759 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4764 g_value_set_boxed (value, ¢er);
4768 case PROP_ROTATION_CENTER_Z:
4770 ClutterVertex center;
4772 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4777 g_value_set_boxed (value, ¢er);
4781 case PROP_ROTATION_CENTER_Z_GRAVITY:
4782 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4787 const ClutterTransformInfo *info;
4790 info = _clutter_actor_get_transform_info_or_defaults (actor);
4791 clutter_anchor_coord_get_units (actor, &info->anchor,
4795 g_value_set_float (value, anchor_x);
4801 const ClutterTransformInfo *info;
4804 info = _clutter_actor_get_transform_info_or_defaults (actor);
4805 clutter_anchor_coord_get_units (actor, &info->anchor,
4809 g_value_set_float (value, anchor_y);
4813 case PROP_ANCHOR_GRAVITY:
4814 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4817 case PROP_SHOW_ON_SET_PARENT:
4818 g_value_set_boolean (value, priv->show_on_set_parent);
4821 case PROP_TEXT_DIRECTION:
4822 g_value_set_enum (value, priv->text_direction);
4825 case PROP_HAS_POINTER:
4826 g_value_set_boolean (value, priv->has_pointer);
4829 case PROP_LAYOUT_MANAGER:
4830 g_value_set_object (value, priv->layout_manager);
4835 const ClutterLayoutInfo *info;
4837 info = _clutter_actor_get_layout_info_or_defaults (actor);
4838 g_value_set_enum (value, info->x_align);
4844 const ClutterLayoutInfo *info;
4846 info = _clutter_actor_get_layout_info_or_defaults (actor);
4847 g_value_set_enum (value, info->y_align);
4851 case PROP_MARGIN_TOP:
4853 const ClutterLayoutInfo *info;
4855 info = _clutter_actor_get_layout_info_or_defaults (actor);
4856 g_value_set_float (value, info->margin.top);
4860 case PROP_MARGIN_BOTTOM:
4862 const ClutterLayoutInfo *info;
4864 info = _clutter_actor_get_layout_info_or_defaults (actor);
4865 g_value_set_float (value, info->margin.bottom);
4869 case PROP_MARGIN_LEFT:
4871 const ClutterLayoutInfo *info;
4873 info = _clutter_actor_get_layout_info_or_defaults (actor);
4874 g_value_set_float (value, info->margin.left);
4878 case PROP_MARGIN_RIGHT:
4880 const ClutterLayoutInfo *info;
4882 info = _clutter_actor_get_layout_info_or_defaults (actor);
4883 g_value_set_float (value, info->margin.right);
4887 case PROP_BACKGROUND_COLOR_SET:
4888 g_value_set_boolean (value, priv->bg_color_set);
4891 case PROP_BACKGROUND_COLOR:
4892 g_value_set_boxed (value, &priv->bg_color);
4895 case PROP_FIRST_CHILD:
4896 g_value_set_object (value, priv->first_child);
4899 case PROP_LAST_CHILD:
4900 g_value_set_object (value, priv->last_child);
4904 g_value_set_object (value, priv->content);
4907 case PROP_CONTENT_GRAVITY:
4908 g_value_set_enum (value, priv->content_gravity);
4911 case PROP_CONTENT_BOX:
4913 ClutterActorBox box = { 0, };
4915 clutter_actor_get_content_box (actor, &box);
4916 g_value_set_boxed (value, &box);
4920 case PROP_MINIFICATION_FILTER:
4921 g_value_set_enum (value, priv->min_filter);
4924 case PROP_MAGNIFICATION_FILTER:
4925 g_value_set_enum (value, priv->mag_filter);
4929 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4935 clutter_actor_dispose (GObject *object)
4937 ClutterActor *self = CLUTTER_ACTOR (object);
4938 ClutterActorPrivate *priv = self->priv;
4940 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4942 g_type_name (G_OBJECT_TYPE (self)),
4945 g_signal_emit (self, actor_signals[DESTROY], 0);
4947 /* avoid recursing when called from clutter_actor_destroy() */
4948 if (priv->parent != NULL)
4950 ClutterActor *parent = priv->parent;
4952 /* go through the Container implementation unless this
4953 * is an internal child and has been marked as such.
4955 * removing the actor from its parent will reset the
4956 * realized and mapped states.
4958 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4959 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4961 clutter_actor_remove_child_internal (parent, self,
4962 REMOVE_CHILD_LEGACY_FLAGS);
4965 /* parent must be gone at this point */
4966 g_assert (priv->parent == NULL);
4968 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4970 /* can't be mapped or realized with no parent */
4971 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4972 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4975 g_clear_object (&priv->pango_context);
4976 g_clear_object (&priv->actions);
4977 g_clear_object (&priv->constraints);
4978 g_clear_object (&priv->effects);
4979 g_clear_object (&priv->flatten_effect);
4981 if (priv->layout_manager != NULL)
4983 clutter_layout_manager_set_container (priv->layout_manager, NULL);
4984 g_clear_object (&priv->layout_manager);
4987 if (priv->content != NULL)
4989 _clutter_content_detached (priv->content, self);
4990 g_clear_object (&priv->content);
4993 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4997 clutter_actor_finalize (GObject *object)
4999 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5001 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5002 priv->name != NULL ? priv->name : "<none>",
5004 g_type_name (G_OBJECT_TYPE (object)));
5006 _clutter_context_release_id (priv->id);
5008 g_free (priv->name);
5010 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5015 * clutter_actor_get_accessible:
5016 * @self: a #ClutterActor
5018 * Returns the accessible object that describes the actor to an
5019 * assistive technology.
5021 * If no class-specific #AtkObject implementation is available for the
5022 * actor instance in question, it will inherit an #AtkObject
5023 * implementation from the first ancestor class for which such an
5024 * implementation is defined.
5026 * The documentation of the <ulink
5027 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5028 * library contains more information about accessible objects and
5031 * Returns: (transfer none): the #AtkObject associated with @actor
5034 clutter_actor_get_accessible (ClutterActor *self)
5036 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5038 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5042 clutter_actor_real_get_accessible (ClutterActor *actor)
5044 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5048 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5050 AtkObject *accessible;
5052 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5053 if (accessible != NULL)
5054 g_object_ref (accessible);
5060 atk_implementor_iface_init (AtkImplementorIface *iface)
5062 iface->ref_accessible = _clutter_actor_ref_accessible;
5066 clutter_actor_update_default_paint_volume (ClutterActor *self,
5067 ClutterPaintVolume *volume)
5069 ClutterActorPrivate *priv = self->priv;
5070 gboolean res = FALSE;
5072 /* we start from the allocation */
5073 clutter_paint_volume_set_width (volume,
5074 priv->allocation.x2 - priv->allocation.x1);
5075 clutter_paint_volume_set_height (volume,
5076 priv->allocation.y2 - priv->allocation.y1);
5078 /* if the actor has a clip set then we have a pretty definite
5079 * size for the paint volume: the actor cannot possibly paint
5080 * outside the clip region.
5082 if (priv->clip_to_allocation)
5084 /* the allocation has already been set, so we just flip the
5091 ClutterActor *child;
5093 if (priv->has_clip &&
5094 priv->clip.width >= 0 &&
5095 priv->clip.height >= 0)
5097 ClutterVertex origin;
5099 origin.x = priv->clip.x;
5100 origin.y = priv->clip.y;
5103 clutter_paint_volume_set_origin (volume, &origin);
5104 clutter_paint_volume_set_width (volume, priv->clip.width);
5105 clutter_paint_volume_set_height (volume, priv->clip.height);
5110 /* if we don't have children we just bail out here... */
5111 if (priv->n_children == 0)
5114 /* ...but if we have children then we ask for their paint volume in
5115 * our coordinates. if any of our children replies that it doesn't
5116 * have a paint volume, we bail out
5118 for (child = priv->first_child;
5120 child = child->priv->next_sibling)
5122 const ClutterPaintVolume *child_volume;
5124 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5125 if (child_volume == NULL)
5131 clutter_paint_volume_union (volume, child_volume);
5141 clutter_actor_real_get_paint_volume (ClutterActor *self,
5142 ClutterPaintVolume *volume)
5144 ClutterActorClass *klass;
5147 klass = CLUTTER_ACTOR_GET_CLASS (self);
5149 /* XXX - this thoroughly sucks, but we don't want to penalize users
5150 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5151 * redraw. This should go away in 2.0.
5153 if (klass->paint == clutter_actor_real_paint &&
5154 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5160 /* this is the default return value: we cannot know if a class
5161 * is going to paint outside its allocation, so we take the
5162 * conservative approach.
5167 if (clutter_actor_update_default_paint_volume (self, volume))
5174 * clutter_actor_get_default_paint_volume:
5175 * @self: a #ClutterActor
5177 * Retrieves the default paint volume for @self.
5179 * This function provides the same #ClutterPaintVolume that would be
5180 * computed by the default implementation inside #ClutterActor of the
5181 * #ClutterActorClass.get_paint_volume() virtual function.
5183 * This function should only be used by #ClutterActor subclasses that
5184 * cannot chain up to the parent implementation when computing their
5187 * Return value: (transfer none): a pointer to the default
5188 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5189 * the actor could not compute a valid paint volume. The returned value
5190 * is not guaranteed to be stable across multiple frames, so if you
5191 * want to retain it, you will need to copy it using
5192 * clutter_paint_volume_copy().
5196 const ClutterPaintVolume *
5197 clutter_actor_get_default_paint_volume (ClutterActor *self)
5199 ClutterPaintVolume volume;
5200 ClutterPaintVolume *res;
5202 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5205 _clutter_paint_volume_init_static (&volume, self);
5206 if (clutter_actor_update_default_paint_volume (self, &volume))
5208 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5212 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5213 _clutter_paint_volume_copy_static (&volume, res);
5217 clutter_paint_volume_free (&volume);
5223 clutter_actor_real_has_overlaps (ClutterActor *self)
5225 /* By default we'll assume that all actors need an offscreen redirect to get
5226 * the correct opacity. Actors such as ClutterTexture that would never need
5227 * an offscreen redirect can override this to return FALSE. */
5232 clutter_actor_real_destroy (ClutterActor *actor)
5234 ClutterActorIter iter;
5236 clutter_actor_iter_init (&iter, actor);
5237 while (clutter_actor_iter_next (&iter, NULL))
5238 clutter_actor_iter_destroy (&iter);
5242 clutter_actor_constructor (GType gtype,
5244 GObjectConstructParam *props)
5246 GObjectClass *gobject_class;
5250 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5251 retval = gobject_class->constructor (gtype, n_props, props);
5252 self = CLUTTER_ACTOR (retval);
5254 if (self->priv->layout_manager == NULL)
5256 ClutterLayoutManager *default_layout;
5258 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5260 default_layout = clutter_fixed_layout_new ();
5261 clutter_actor_set_layout_manager (self, default_layout);
5268 clutter_actor_class_init (ClutterActorClass *klass)
5270 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5272 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5273 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5274 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5275 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5277 object_class->constructor = clutter_actor_constructor;
5278 object_class->set_property = clutter_actor_set_property;
5279 object_class->get_property = clutter_actor_get_property;
5280 object_class->dispose = clutter_actor_dispose;
5281 object_class->finalize = clutter_actor_finalize;
5283 klass->show = clutter_actor_real_show;
5284 klass->show_all = clutter_actor_show;
5285 klass->hide = clutter_actor_real_hide;
5286 klass->hide_all = clutter_actor_hide;
5287 klass->map = clutter_actor_real_map;
5288 klass->unmap = clutter_actor_real_unmap;
5289 klass->unrealize = clutter_actor_real_unrealize;
5290 klass->pick = clutter_actor_real_pick;
5291 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5292 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5293 klass->allocate = clutter_actor_real_allocate;
5294 klass->queue_redraw = clutter_actor_real_queue_redraw;
5295 klass->queue_relayout = clutter_actor_real_queue_relayout;
5296 klass->apply_transform = clutter_actor_real_apply_transform;
5297 klass->get_accessible = clutter_actor_real_get_accessible;
5298 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5299 klass->has_overlaps = clutter_actor_real_has_overlaps;
5300 klass->paint = clutter_actor_real_paint;
5301 klass->destroy = clutter_actor_real_destroy;
5303 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5308 * X coordinate of the actor in pixels. If written, forces a fixed
5309 * position for the actor. If read, returns the fixed position if any,
5310 * otherwise the allocation if available, otherwise 0.
5312 * The #ClutterActor:x property is animatable.
5315 g_param_spec_float ("x",
5317 P_("X coordinate of the actor"),
5318 -G_MAXFLOAT, G_MAXFLOAT,
5321 G_PARAM_STATIC_STRINGS |
5322 CLUTTER_PARAM_ANIMATABLE);
5327 * Y coordinate of the actor in pixels. If written, forces a fixed
5328 * position for the actor. If read, returns the fixed position if
5329 * any, otherwise the allocation if available, otherwise 0.
5331 * The #ClutterActor:y property is animatable.
5334 g_param_spec_float ("y",
5336 P_("Y coordinate of the actor"),
5337 -G_MAXFLOAT, G_MAXFLOAT,
5340 G_PARAM_STATIC_STRINGS |
5341 CLUTTER_PARAM_ANIMATABLE);
5344 * ClutterActor:width:
5346 * Width of the actor (in pixels). If written, forces the minimum and
5347 * natural size request of the actor to the given width. If read, returns
5348 * the allocated width if available, otherwise the width request.
5350 * The #ClutterActor:width property is animatable.
5352 obj_props[PROP_WIDTH] =
5353 g_param_spec_float ("width",
5355 P_("Width of the actor"),
5359 G_PARAM_STATIC_STRINGS |
5360 CLUTTER_PARAM_ANIMATABLE);
5363 * ClutterActor:height:
5365 * Height of the actor (in pixels). If written, forces the minimum and
5366 * natural size request of the actor to the given height. If read, returns
5367 * the allocated height if available, otherwise the height request.
5369 * The #ClutterActor:height property is animatable.
5371 obj_props[PROP_HEIGHT] =
5372 g_param_spec_float ("height",
5374 P_("Height of the actor"),
5378 G_PARAM_STATIC_STRINGS |
5379 CLUTTER_PARAM_ANIMATABLE);
5382 * ClutterActor:fixed-x:
5384 * The fixed X position of the actor in pixels.
5386 * Writing this property sets #ClutterActor:fixed-position-set
5387 * property as well, as a side effect
5391 obj_props[PROP_FIXED_X] =
5392 g_param_spec_float ("fixed-x",
5394 P_("Forced X position of the actor"),
5395 -G_MAXFLOAT, G_MAXFLOAT,
5397 CLUTTER_PARAM_READWRITE);
5400 * ClutterActor:fixed-y:
5402 * The fixed Y position of the actor in pixels.
5404 * Writing this property sets the #ClutterActor:fixed-position-set
5405 * property as well, as a side effect
5409 obj_props[PROP_FIXED_Y] =
5410 g_param_spec_float ("fixed-y",
5412 P_("Forced Y position of the actor"),
5413 -G_MAXFLOAT, G_MAXFLOAT,
5415 CLUTTER_PARAM_READWRITE);
5418 * ClutterActor:fixed-position-set:
5420 * This flag controls whether the #ClutterActor:fixed-x and
5421 * #ClutterActor:fixed-y properties are used
5425 obj_props[PROP_FIXED_POSITION_SET] =
5426 g_param_spec_boolean ("fixed-position-set",
5427 P_("Fixed position set"),
5428 P_("Whether to use fixed positioning for the actor"),
5430 CLUTTER_PARAM_READWRITE);
5433 * ClutterActor:min-width:
5435 * A forced minimum width request for the actor, in pixels
5437 * Writing this property sets the #ClutterActor:min-width-set property
5438 * as well, as a side effect.
5440 *This property overrides the usual width request of the actor.
5444 obj_props[PROP_MIN_WIDTH] =
5445 g_param_spec_float ("min-width",
5447 P_("Forced minimum width request for the actor"),
5450 CLUTTER_PARAM_READWRITE);
5453 * ClutterActor:min-height:
5455 * A forced minimum height request for the actor, in pixels
5457 * Writing this property sets the #ClutterActor:min-height-set property
5458 * as well, as a side effect. This property overrides the usual height
5459 * request of the actor.
5463 obj_props[PROP_MIN_HEIGHT] =
5464 g_param_spec_float ("min-height",
5466 P_("Forced minimum height request for the actor"),
5469 CLUTTER_PARAM_READWRITE);
5472 * ClutterActor:natural-width:
5474 * A forced natural width request for the actor, in pixels
5476 * Writing this property sets the #ClutterActor:natural-width-set
5477 * property as well, as a side effect. This property overrides the
5478 * usual width request of the actor
5482 obj_props[PROP_NATURAL_WIDTH] =
5483 g_param_spec_float ("natural-width",
5484 P_("Natural Width"),
5485 P_("Forced natural width request for the actor"),
5488 CLUTTER_PARAM_READWRITE);
5491 * ClutterActor:natural-height:
5493 * A forced natural height request for the actor, in pixels
5495 * Writing this property sets the #ClutterActor:natural-height-set
5496 * property as well, as a side effect. This property overrides the
5497 * usual height request of the actor
5501 obj_props[PROP_NATURAL_HEIGHT] =
5502 g_param_spec_float ("natural-height",
5503 P_("Natural Height"),
5504 P_("Forced natural height request for the actor"),
5507 CLUTTER_PARAM_READWRITE);
5510 * ClutterActor:min-width-set:
5512 * This flag controls whether the #ClutterActor:min-width property
5517 obj_props[PROP_MIN_WIDTH_SET] =
5518 g_param_spec_boolean ("min-width-set",
5519 P_("Minimum width set"),
5520 P_("Whether to use the min-width property"),
5522 CLUTTER_PARAM_READWRITE);
5525 * ClutterActor:min-height-set:
5527 * This flag controls whether the #ClutterActor:min-height property
5532 obj_props[PROP_MIN_HEIGHT_SET] =
5533 g_param_spec_boolean ("min-height-set",
5534 P_("Minimum height set"),
5535 P_("Whether to use the min-height property"),
5537 CLUTTER_PARAM_READWRITE);
5540 * ClutterActor:natural-width-set:
5542 * This flag controls whether the #ClutterActor:natural-width property
5547 obj_props[PROP_NATURAL_WIDTH_SET] =
5548 g_param_spec_boolean ("natural-width-set",
5549 P_("Natural width set"),
5550 P_("Whether to use the natural-width property"),
5552 CLUTTER_PARAM_READWRITE);
5555 * ClutterActor:natural-height-set:
5557 * This flag controls whether the #ClutterActor:natural-height property
5562 obj_props[PROP_NATURAL_HEIGHT_SET] =
5563 g_param_spec_boolean ("natural-height-set",
5564 P_("Natural height set"),
5565 P_("Whether to use the natural-height property"),
5567 CLUTTER_PARAM_READWRITE);
5570 * ClutterActor:allocation:
5572 * The allocation for the actor, in pixels
5574 * This is property is read-only, but you might monitor it to know when an
5575 * actor moves or resizes
5579 obj_props[PROP_ALLOCATION] =
5580 g_param_spec_boxed ("allocation",
5582 P_("The actor's allocation"),
5583 CLUTTER_TYPE_ACTOR_BOX,
5584 CLUTTER_PARAM_READABLE);
5587 * ClutterActor:request-mode:
5589 * Request mode for the #ClutterActor. The request mode determines the
5590 * type of geometry management used by the actor, either height for width
5591 * (the default) or width for height.
5593 * For actors implementing height for width, the parent container should get
5594 * the preferred width first, and then the preferred height for that width.
5596 * For actors implementing width for height, the parent container should get
5597 * the preferred height first, and then the preferred width for that height.
5602 * ClutterRequestMode mode;
5603 * gfloat natural_width, min_width;
5604 * gfloat natural_height, min_height;
5606 * mode = clutter_actor_get_request_mode (child);
5607 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5609 * clutter_actor_get_preferred_width (child, -1,
5611 * &natural_width);
5612 * clutter_actor_get_preferred_height (child, natural_width,
5614 * &natural_height);
5618 * clutter_actor_get_preferred_height (child, -1,
5620 * &natural_height);
5621 * clutter_actor_get_preferred_width (child, natural_height,
5623 * &natural_width);
5627 * will retrieve the minimum and natural width and height depending on the
5628 * preferred request mode of the #ClutterActor "child".
5630 * The clutter_actor_get_preferred_size() function will implement this
5635 obj_props[PROP_REQUEST_MODE] =
5636 g_param_spec_enum ("request-mode",
5638 P_("The actor's request mode"),
5639 CLUTTER_TYPE_REQUEST_MODE,
5640 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5641 CLUTTER_PARAM_READWRITE);
5644 * ClutterActor:depth:
5646 * The position of the actor on the Z axis.
5648 * The #ClutterActor:depth property is relative to the parent's
5651 * The #ClutterActor:depth property is animatable.
5655 obj_props[PROP_DEPTH] =
5656 g_param_spec_float ("depth",
5658 P_("Position on the Z axis"),
5659 -G_MAXFLOAT, G_MAXFLOAT,
5662 G_PARAM_STATIC_STRINGS |
5663 CLUTTER_PARAM_ANIMATABLE);
5666 * ClutterActor:opacity:
5668 * Opacity of an actor, between 0 (fully transparent) and
5669 * 255 (fully opaque)
5671 * The #ClutterActor:opacity property is animatable.
5673 obj_props[PROP_OPACITY] =
5674 g_param_spec_uint ("opacity",
5676 P_("Opacity of an actor"),
5680 G_PARAM_STATIC_STRINGS |
5681 CLUTTER_PARAM_ANIMATABLE);
5684 * ClutterActor:offscreen-redirect:
5686 * Determines the conditions in which the actor will be redirected
5687 * to an offscreen framebuffer while being painted. For example this
5688 * can be used to cache an actor in a framebuffer or for improved
5689 * handling of transparent actors. See
5690 * clutter_actor_set_offscreen_redirect() for details.
5694 obj_props[PROP_OFFSCREEN_REDIRECT] =
5695 g_param_spec_flags ("offscreen-redirect",
5696 P_("Offscreen redirect"),
5697 P_("Flags controlling when to flatten the actor into a single image"),
5698 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5700 CLUTTER_PARAM_READWRITE);
5703 * ClutterActor:visible:
5705 * Whether the actor is set to be visible or not
5707 * See also #ClutterActor:mapped
5709 obj_props[PROP_VISIBLE] =
5710 g_param_spec_boolean ("visible",
5712 P_("Whether the actor is visible or not"),
5714 CLUTTER_PARAM_READWRITE);
5717 * ClutterActor:mapped:
5719 * Whether the actor is mapped (will be painted when the stage
5720 * to which it belongs is mapped)
5724 obj_props[PROP_MAPPED] =
5725 g_param_spec_boolean ("mapped",
5727 P_("Whether the actor will be painted"),
5729 CLUTTER_PARAM_READABLE);
5732 * ClutterActor:realized:
5734 * Whether the actor has been realized
5738 obj_props[PROP_REALIZED] =
5739 g_param_spec_boolean ("realized",
5741 P_("Whether the actor has been realized"),
5743 CLUTTER_PARAM_READABLE);
5746 * ClutterActor:reactive:
5748 * Whether the actor is reactive to events or not
5750 * Only reactive actors will emit event-related signals
5754 obj_props[PROP_REACTIVE] =
5755 g_param_spec_boolean ("reactive",
5757 P_("Whether the actor is reactive to events"),
5759 CLUTTER_PARAM_READWRITE);
5762 * ClutterActor:has-clip:
5764 * Whether the actor has the #ClutterActor:clip property set or not
5766 obj_props[PROP_HAS_CLIP] =
5767 g_param_spec_boolean ("has-clip",
5769 P_("Whether the actor has a clip set"),
5771 CLUTTER_PARAM_READABLE);
5774 * ClutterActor:clip:
5776 * The clip region for the actor, in actor-relative coordinates
5778 * Every part of the actor outside the clip region will not be
5781 obj_props[PROP_CLIP] =
5782 g_param_spec_boxed ("clip",
5784 P_("The clip region for the actor"),
5785 CLUTTER_TYPE_GEOMETRY,
5786 CLUTTER_PARAM_READWRITE);
5789 * ClutterActor:name:
5791 * The name of the actor
5795 obj_props[PROP_NAME] =
5796 g_param_spec_string ("name",
5798 P_("Name of the actor"),
5800 CLUTTER_PARAM_READWRITE);
5803 * ClutterActor:scale-x:
5805 * The horizontal scale of the actor.
5807 * The #ClutterActor:scale-x property is animatable.
5811 obj_props[PROP_SCALE_X] =
5812 g_param_spec_double ("scale-x",
5814 P_("Scale factor on the X axis"),
5818 G_PARAM_STATIC_STRINGS |
5819 CLUTTER_PARAM_ANIMATABLE);
5822 * ClutterActor:scale-y:
5824 * The vertical scale of the actor.
5826 * The #ClutterActor:scale-y property is animatable.
5830 obj_props[PROP_SCALE_Y] =
5831 g_param_spec_double ("scale-y",
5833 P_("Scale factor on the Y axis"),
5837 G_PARAM_STATIC_STRINGS |
5838 CLUTTER_PARAM_ANIMATABLE);
5841 * ClutterActor:scale-center-x:
5843 * The horizontal center point for scaling
5847 obj_props[PROP_SCALE_CENTER_X] =
5848 g_param_spec_float ("scale-center-x",
5849 P_("Scale Center X"),
5850 P_("Horizontal scale center"),
5851 -G_MAXFLOAT, G_MAXFLOAT,
5853 CLUTTER_PARAM_READWRITE);
5856 * ClutterActor:scale-center-y:
5858 * The vertical center point for scaling
5862 obj_props[PROP_SCALE_CENTER_Y] =
5863 g_param_spec_float ("scale-center-y",
5864 P_("Scale Center Y"),
5865 P_("Vertical scale center"),
5866 -G_MAXFLOAT, G_MAXFLOAT,
5868 CLUTTER_PARAM_READWRITE);
5871 * ClutterActor:scale-gravity:
5873 * The center point for scaling expressed as a #ClutterGravity
5877 obj_props[PROP_SCALE_GRAVITY] =
5878 g_param_spec_enum ("scale-gravity",
5879 P_("Scale Gravity"),
5880 P_("The center of scaling"),
5881 CLUTTER_TYPE_GRAVITY,
5882 CLUTTER_GRAVITY_NONE,
5883 CLUTTER_PARAM_READWRITE);
5886 * ClutterActor:rotation-angle-x:
5888 * The rotation angle on the X axis.
5890 * The #ClutterActor:rotation-angle-x property is animatable.
5894 obj_props[PROP_ROTATION_ANGLE_X] =
5895 g_param_spec_double ("rotation-angle-x",
5896 P_("Rotation Angle X"),
5897 P_("The rotation angle on the X axis"),
5898 -G_MAXDOUBLE, G_MAXDOUBLE,
5901 G_PARAM_STATIC_STRINGS |
5902 CLUTTER_PARAM_ANIMATABLE);
5905 * ClutterActor:rotation-angle-y:
5907 * The rotation angle on the Y axis
5909 * The #ClutterActor:rotation-angle-y property is animatable.
5913 obj_props[PROP_ROTATION_ANGLE_Y] =
5914 g_param_spec_double ("rotation-angle-y",
5915 P_("Rotation Angle Y"),
5916 P_("The rotation angle on the Y axis"),
5917 -G_MAXDOUBLE, G_MAXDOUBLE,
5920 G_PARAM_STATIC_STRINGS |
5921 CLUTTER_PARAM_ANIMATABLE);
5924 * ClutterActor:rotation-angle-z:
5926 * The rotation angle on the Z axis
5928 * The #ClutterActor:rotation-angle-z property is animatable.
5932 obj_props[PROP_ROTATION_ANGLE_Z] =
5933 g_param_spec_double ("rotation-angle-z",
5934 P_("Rotation Angle Z"),
5935 P_("The rotation angle on the Z axis"),
5936 -G_MAXDOUBLE, G_MAXDOUBLE,
5939 G_PARAM_STATIC_STRINGS |
5940 CLUTTER_PARAM_ANIMATABLE);
5943 * ClutterActor:rotation-center-x:
5945 * The rotation center on the X axis.
5949 obj_props[PROP_ROTATION_CENTER_X] =
5950 g_param_spec_boxed ("rotation-center-x",
5951 P_("Rotation Center X"),
5952 P_("The rotation center on the X axis"),
5953 CLUTTER_TYPE_VERTEX,
5954 CLUTTER_PARAM_READWRITE);
5957 * ClutterActor:rotation-center-y:
5959 * The rotation center on the Y axis.
5963 obj_props[PROP_ROTATION_CENTER_Y] =
5964 g_param_spec_boxed ("rotation-center-y",
5965 P_("Rotation Center Y"),
5966 P_("The rotation center on the Y axis"),
5967 CLUTTER_TYPE_VERTEX,
5968 CLUTTER_PARAM_READWRITE);
5971 * ClutterActor:rotation-center-z:
5973 * The rotation center on the Z axis.
5977 obj_props[PROP_ROTATION_CENTER_Z] =
5978 g_param_spec_boxed ("rotation-center-z",
5979 P_("Rotation Center Z"),
5980 P_("The rotation center on the Z axis"),
5981 CLUTTER_TYPE_VERTEX,
5982 CLUTTER_PARAM_READWRITE);
5985 * ClutterActor:rotation-center-z-gravity:
5987 * The rotation center on the Z axis expressed as a #ClutterGravity.
5991 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5992 g_param_spec_enum ("rotation-center-z-gravity",
5993 P_("Rotation Center Z Gravity"),
5994 P_("Center point for rotation around the Z axis"),
5995 CLUTTER_TYPE_GRAVITY,
5996 CLUTTER_GRAVITY_NONE,
5997 CLUTTER_PARAM_READWRITE);
6000 * ClutterActor:anchor-x:
6002 * The X coordinate of an actor's anchor point, relative to
6003 * the actor coordinate space, in pixels
6007 obj_props[PROP_ANCHOR_X] =
6008 g_param_spec_float ("anchor-x",
6010 P_("X coordinate of the anchor point"),
6011 -G_MAXFLOAT, G_MAXFLOAT,
6013 CLUTTER_PARAM_READWRITE);
6016 * ClutterActor:anchor-y:
6018 * The Y coordinate of an actor's anchor point, relative to
6019 * the actor coordinate space, in pixels
6023 obj_props[PROP_ANCHOR_Y] =
6024 g_param_spec_float ("anchor-y",
6026 P_("Y coordinate of the anchor point"),
6027 -G_MAXFLOAT, G_MAXFLOAT,
6029 CLUTTER_PARAM_READWRITE);
6032 * ClutterActor:anchor-gravity:
6034 * The anchor point expressed as a #ClutterGravity
6038 obj_props[PROP_ANCHOR_GRAVITY] =
6039 g_param_spec_enum ("anchor-gravity",
6040 P_("Anchor Gravity"),
6041 P_("The anchor point as a ClutterGravity"),
6042 CLUTTER_TYPE_GRAVITY,
6043 CLUTTER_GRAVITY_NONE,
6044 CLUTTER_PARAM_READWRITE);
6047 * ClutterActor:show-on-set-parent:
6049 * If %TRUE, the actor is automatically shown when parented.
6051 * Calling clutter_actor_hide() on an actor which has not been
6052 * parented will set this property to %FALSE as a side effect.
6056 obj_props[PROP_SHOW_ON_SET_PARENT] =
6057 g_param_spec_boolean ("show-on-set-parent",
6058 P_("Show on set parent"),
6059 P_("Whether the actor is shown when parented"),
6061 CLUTTER_PARAM_READWRITE);
6064 * ClutterActor:clip-to-allocation:
6066 * Whether the clip region should track the allocated area
6069 * This property is ignored if a clip area has been explicitly
6070 * set using clutter_actor_set_clip().
6074 obj_props[PROP_CLIP_TO_ALLOCATION] =
6075 g_param_spec_boolean ("clip-to-allocation",
6076 P_("Clip to Allocation"),
6077 P_("Sets the clip region to track the actor's allocation"),
6079 CLUTTER_PARAM_READWRITE);
6082 * ClutterActor:text-direction:
6084 * The direction of the text inside a #ClutterActor.
6088 obj_props[PROP_TEXT_DIRECTION] =
6089 g_param_spec_enum ("text-direction",
6090 P_("Text Direction"),
6091 P_("Direction of the text"),
6092 CLUTTER_TYPE_TEXT_DIRECTION,
6093 CLUTTER_TEXT_DIRECTION_LTR,
6094 CLUTTER_PARAM_READWRITE);
6097 * ClutterActor:has-pointer:
6099 * Whether the actor contains the pointer of a #ClutterInputDevice
6104 obj_props[PROP_HAS_POINTER] =
6105 g_param_spec_boolean ("has-pointer",
6107 P_("Whether the actor contains the pointer of an input device"),
6109 CLUTTER_PARAM_READABLE);
6112 * ClutterActor:actions:
6114 * Adds a #ClutterAction to the actor
6118 obj_props[PROP_ACTIONS] =
6119 g_param_spec_object ("actions",
6121 P_("Adds an action to the actor"),
6122 CLUTTER_TYPE_ACTION,
6123 CLUTTER_PARAM_WRITABLE);
6126 * ClutterActor:constraints:
6128 * Adds a #ClutterConstraint to the actor
6132 obj_props[PROP_CONSTRAINTS] =
6133 g_param_spec_object ("constraints",
6135 P_("Adds a constraint to the actor"),
6136 CLUTTER_TYPE_CONSTRAINT,
6137 CLUTTER_PARAM_WRITABLE);
6140 * ClutterActor:effect:
6142 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6146 obj_props[PROP_EFFECT] =
6147 g_param_spec_object ("effect",
6149 P_("Add an effect to be applied on the actor"),
6150 CLUTTER_TYPE_EFFECT,
6151 CLUTTER_PARAM_WRITABLE);
6154 * ClutterActor:layout-manager:
6156 * A delegate object for controlling the layout of the children of
6161 obj_props[PROP_LAYOUT_MANAGER] =
6162 g_param_spec_object ("layout-manager",
6163 P_("Layout Manager"),
6164 P_("The object controlling the layout of an actor's children"),
6165 CLUTTER_TYPE_LAYOUT_MANAGER,
6166 CLUTTER_PARAM_READWRITE);
6170 * ClutterActor:x-align:
6172 * The alignment of an actor on the X axis, if the actor has been given
6173 * extra space for its allocation.
6177 obj_props[PROP_X_ALIGN] =
6178 g_param_spec_enum ("x-align",
6180 P_("The alignment of the actor on the X axis within its allocation"),
6181 CLUTTER_TYPE_ACTOR_ALIGN,
6182 CLUTTER_ACTOR_ALIGN_FILL,
6183 CLUTTER_PARAM_READWRITE);
6186 * ClutterActor:y-align:
6188 * The alignment of an actor on the Y axis, if the actor has been given
6189 * extra space for its allocation.
6193 obj_props[PROP_Y_ALIGN] =
6194 g_param_spec_enum ("y-align",
6196 P_("The alignment of the actor on the Y axis within its allocation"),
6197 CLUTTER_TYPE_ACTOR_ALIGN,
6198 CLUTTER_ACTOR_ALIGN_FILL,
6199 CLUTTER_PARAM_READWRITE);
6202 * ClutterActor:margin-top:
6204 * The margin (in pixels) from the top of the actor.
6206 * This property adds a margin to the actor's preferred size; the margin
6207 * will be automatically taken into account when allocating the actor.
6211 obj_props[PROP_MARGIN_TOP] =
6212 g_param_spec_float ("margin-top",
6214 P_("Extra space at the top"),
6217 CLUTTER_PARAM_READWRITE);
6220 * ClutterActor:margin-bottom:
6222 * The margin (in pixels) from the bottom of the actor.
6224 * This property adds a margin to the actor's preferred size; the margin
6225 * will be automatically taken into account when allocating the actor.
6229 obj_props[PROP_MARGIN_BOTTOM] =
6230 g_param_spec_float ("margin-bottom",
6231 P_("Margin Bottom"),
6232 P_("Extra space at the bottom"),
6235 CLUTTER_PARAM_READWRITE);
6238 * ClutterActor:margin-left:
6240 * The margin (in pixels) from the left of the actor.
6242 * This property adds a margin to the actor's preferred size; the margin
6243 * will be automatically taken into account when allocating the actor.
6247 obj_props[PROP_MARGIN_LEFT] =
6248 g_param_spec_float ("margin-left",
6250 P_("Extra space at the left"),
6253 CLUTTER_PARAM_READWRITE);
6256 * ClutterActor:margin-right:
6258 * The margin (in pixels) from the right of the actor.
6260 * This property adds a margin to the actor's preferred size; the margin
6261 * will be automatically taken into account when allocating the actor.
6265 obj_props[PROP_MARGIN_RIGHT] =
6266 g_param_spec_float ("margin-right",
6268 P_("Extra space at the right"),
6271 CLUTTER_PARAM_READWRITE);
6274 * ClutterActor:background-color-set:
6276 * Whether the #ClutterActor:background-color property has been set.
6280 obj_props[PROP_BACKGROUND_COLOR_SET] =
6281 g_param_spec_boolean ("background-color-set",
6282 P_("Background Color Set"),
6283 P_("Whether the background color is set"),
6285 CLUTTER_PARAM_READABLE);
6288 * ClutterActor:background-color:
6290 * Paints a solid fill of the actor's allocation using the specified
6293 * The #ClutterActor:background-color property is animatable.
6297 obj_props[PROP_BACKGROUND_COLOR] =
6298 clutter_param_spec_color ("background-color",
6299 P_("Background color"),
6300 P_("The actor's background color"),
6301 CLUTTER_COLOR_Transparent,
6303 G_PARAM_STATIC_STRINGS |
6304 CLUTTER_PARAM_ANIMATABLE);
6307 * ClutterActor:first-child:
6309 * The actor's first child.
6313 obj_props[PROP_FIRST_CHILD] =
6314 g_param_spec_object ("first-child",
6316 P_("The actor's first child"),
6318 CLUTTER_PARAM_READABLE);
6321 * ClutterActor:last-child:
6323 * The actor's last child.
6327 obj_props[PROP_LAST_CHILD] =
6328 g_param_spec_object ("last-child",
6330 P_("The actor's last child"),
6332 CLUTTER_PARAM_READABLE);
6335 * ClutterActor:content:
6337 * The #ClutterContent implementation that controls the content
6342 obj_props[PROP_CONTENT] =
6343 g_param_spec_object ("content",
6345 P_("Delegate object for painting the actor's content"),
6346 CLUTTER_TYPE_CONTENT,
6347 CLUTTER_PARAM_READWRITE);
6350 * ClutterActor:content-gravity:
6352 * The alignment that should be honoured by the #ClutterContent
6353 * set with the #ClutterActor:content property.
6355 * Changing the value of this property will change the bounding box of
6356 * the content; you can use the #ClutterActor:content-box property to
6357 * get the position and size of the content within the actor's
6360 * This property is meaningful only for #ClutterContent implementations
6361 * that have a preferred size, and if the preferred size is smaller than
6362 * the actor's allocation.
6366 obj_props[PROP_CONTENT_GRAVITY] =
6367 g_param_spec_enum ("content-gravity",
6368 P_("Content Gravity"),
6369 P_("Alignment of the actor's content"),
6370 CLUTTER_TYPE_CONTENT_GRAVITY,
6371 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6372 CLUTTER_PARAM_READWRITE);
6375 * ClutterActor:content-box:
6377 * The bounding box for the #ClutterContent used by the actor.
6379 * The value of this property is controlled by the #ClutterActor:allocation
6380 * and #ClutterActor:content-gravity properties of #ClutterActor.
6382 * The bounding box for the content is guaranteed to never exceed the
6383 * allocation's of the actor.
6387 obj_props[PROP_CONTENT_BOX] =
6388 g_param_spec_boxed ("content-box",
6390 P_("The bounding box of the actor's content"),
6391 CLUTTER_TYPE_ACTOR_BOX,
6392 CLUTTER_PARAM_READABLE);
6394 obj_props[PROP_MINIFICATION_FILTER] =
6395 g_param_spec_enum ("minification-filter",
6396 P_("Minification Filter"),
6397 P_("The filter used when reducing the size of the content"),
6398 CLUTTER_TYPE_SCALING_FILTER,
6399 CLUTTER_SCALING_FILTER_LINEAR,
6400 CLUTTER_PARAM_READWRITE);
6402 obj_props[PROP_MAGNIFICATION_FILTER] =
6403 g_param_spec_enum ("magnification-filter",
6404 P_("Magnification Filter"),
6405 P_("The filter used when increasing the size of the content"),
6406 CLUTTER_TYPE_SCALING_FILTER,
6407 CLUTTER_SCALING_FILTER_LINEAR,
6408 CLUTTER_PARAM_READWRITE);
6410 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6413 * ClutterActor::destroy:
6414 * @actor: the #ClutterActor which emitted the signal
6416 * The ::destroy signal notifies that all references held on the
6417 * actor which emitted it should be released.
6419 * The ::destroy signal should be used by all holders of a reference
6422 * This signal might result in the finalization of the #ClutterActor
6423 * if all references are released.
6425 * Composite actors and actors implementing the #ClutterContainer
6426 * interface should override the default implementation of the
6427 * class handler of this signal and call clutter_actor_destroy() on
6428 * their children. When overriding the default class handler, it is
6429 * required to chain up to the parent's implementation.
6433 actor_signals[DESTROY] =
6434 g_signal_new (I_("destroy"),
6435 G_TYPE_FROM_CLASS (object_class),
6436 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6437 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6439 _clutter_marshal_VOID__VOID,
6442 * ClutterActor::show:
6443 * @actor: the object which received the signal
6445 * The ::show signal is emitted when an actor is visible and
6446 * rendered on the stage.
6450 actor_signals[SHOW] =
6451 g_signal_new (I_("show"),
6452 G_TYPE_FROM_CLASS (object_class),
6454 G_STRUCT_OFFSET (ClutterActorClass, show),
6456 _clutter_marshal_VOID__VOID,
6459 * ClutterActor::hide:
6460 * @actor: the object which received the signal
6462 * The ::hide signal is emitted when an actor is no longer rendered
6467 actor_signals[HIDE] =
6468 g_signal_new (I_("hide"),
6469 G_TYPE_FROM_CLASS (object_class),
6471 G_STRUCT_OFFSET (ClutterActorClass, hide),
6473 _clutter_marshal_VOID__VOID,
6476 * ClutterActor::parent-set:
6477 * @actor: the object which received the signal
6478 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6480 * This signal is emitted when the parent of the actor changes.
6484 actor_signals[PARENT_SET] =
6485 g_signal_new (I_("parent-set"),
6486 G_TYPE_FROM_CLASS (object_class),
6488 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6490 _clutter_marshal_VOID__OBJECT,
6492 CLUTTER_TYPE_ACTOR);
6495 * ClutterActor::queue-redraw:
6496 * @actor: the actor we're bubbling the redraw request through
6497 * @origin: the actor which initiated the redraw request
6499 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6500 * is called on @origin.
6502 * The default implementation for #ClutterActor chains up to the
6503 * parent actor and queues a redraw on the parent, thus "bubbling"
6504 * the redraw queue up through the actor graph. The default
6505 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6506 * in a main loop idle handler.
6508 * Note that the @origin actor may be the stage, or a container; it
6509 * does not have to be a leaf node in the actor graph.
6511 * Toolkits embedding a #ClutterStage which require a redraw and
6512 * relayout cycle can stop the emission of this signal using the
6513 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6518 * on_redraw_complete (gpointer data)
6520 * ClutterStage *stage = data;
6522 * /* execute the Clutter drawing pipeline */
6523 * clutter_stage_ensure_redraw (stage);
6527 * on_stage_queue_redraw (ClutterStage *stage)
6529 * /* this prevents the default handler to run */
6530 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6532 * /* queue a redraw with the host toolkit and call
6533 * * a function when the redraw has been completed
6535 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6539 * <note><para>This signal is emitted before the Clutter paint
6540 * pipeline is executed. If you want to know when the pipeline has
6541 * been completed you should connect to the ::paint signal on the
6542 * Stage with g_signal_connect_after().</para></note>
6546 actor_signals[QUEUE_REDRAW] =
6547 g_signal_new (I_("queue-redraw"),
6548 G_TYPE_FROM_CLASS (object_class),
6551 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6553 _clutter_marshal_VOID__OBJECT,
6555 CLUTTER_TYPE_ACTOR);
6558 * ClutterActor::queue-relayout
6559 * @actor: the actor being queued for relayout
6561 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6562 * is called on an actor.
6564 * The default implementation for #ClutterActor chains up to the
6565 * parent actor and queues a relayout on the parent, thus "bubbling"
6566 * the relayout queue up through the actor graph.
6568 * The main purpose of this signal is to allow relayout to be propagated
6569 * properly in the procense of #ClutterClone actors. Applications will
6570 * not normally need to connect to this signal.
6574 actor_signals[QUEUE_RELAYOUT] =
6575 g_signal_new (I_("queue-relayout"),
6576 G_TYPE_FROM_CLASS (object_class),
6579 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6581 _clutter_marshal_VOID__VOID,
6585 * ClutterActor::event:
6586 * @actor: the actor which received the event
6587 * @event: a #ClutterEvent
6589 * The ::event signal is emitted each time an event is received
6590 * by the @actor. This signal will be emitted on every actor,
6591 * following the hierarchy chain, until it reaches the top-level
6592 * container (the #ClutterStage).
6594 * Return value: %TRUE if the event has been handled by the actor,
6595 * or %FALSE to continue the emission.
6599 actor_signals[EVENT] =
6600 g_signal_new (I_("event"),
6601 G_TYPE_FROM_CLASS (object_class),
6603 G_STRUCT_OFFSET (ClutterActorClass, event),
6604 _clutter_boolean_handled_accumulator, NULL,
6605 _clutter_marshal_BOOLEAN__BOXED,
6607 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6609 * ClutterActor::button-press-event:
6610 * @actor: the actor which received the event
6611 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6613 * The ::button-press-event signal is emitted each time a mouse button
6614 * is pressed on @actor.
6616 * Return value: %TRUE if the event has been handled by the actor,
6617 * or %FALSE to continue the emission.
6621 actor_signals[BUTTON_PRESS_EVENT] =
6622 g_signal_new (I_("button-press-event"),
6623 G_TYPE_FROM_CLASS (object_class),
6625 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6626 _clutter_boolean_handled_accumulator, NULL,
6627 _clutter_marshal_BOOLEAN__BOXED,
6629 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6631 * ClutterActor::button-release-event:
6632 * @actor: the actor which received the event
6633 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6635 * The ::button-release-event signal is emitted each time a mouse button
6636 * is released on @actor.
6638 * Return value: %TRUE if the event has been handled by the actor,
6639 * or %FALSE to continue the emission.
6643 actor_signals[BUTTON_RELEASE_EVENT] =
6644 g_signal_new (I_("button-release-event"),
6645 G_TYPE_FROM_CLASS (object_class),
6647 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6648 _clutter_boolean_handled_accumulator, NULL,
6649 _clutter_marshal_BOOLEAN__BOXED,
6651 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6653 * ClutterActor::scroll-event:
6654 * @actor: the actor which received the event
6655 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6657 * The ::scroll-event signal is emitted each time the mouse is
6658 * scrolled on @actor
6660 * Return value: %TRUE if the event has been handled by the actor,
6661 * or %FALSE to continue the emission.
6665 actor_signals[SCROLL_EVENT] =
6666 g_signal_new (I_("scroll-event"),
6667 G_TYPE_FROM_CLASS (object_class),
6669 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6670 _clutter_boolean_handled_accumulator, NULL,
6671 _clutter_marshal_BOOLEAN__BOXED,
6673 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6675 * ClutterActor::key-press-event:
6676 * @actor: the actor which received the event
6677 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6679 * The ::key-press-event signal is emitted each time a keyboard button
6680 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6682 * Return value: %TRUE if the event has been handled by the actor,
6683 * or %FALSE to continue the emission.
6687 actor_signals[KEY_PRESS_EVENT] =
6688 g_signal_new (I_("key-press-event"),
6689 G_TYPE_FROM_CLASS (object_class),
6691 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6692 _clutter_boolean_handled_accumulator, NULL,
6693 _clutter_marshal_BOOLEAN__BOXED,
6695 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6697 * ClutterActor::key-release-event:
6698 * @actor: the actor which received the event
6699 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6701 * The ::key-release-event signal is emitted each time a keyboard button
6702 * is released while @actor has key focus (see
6703 * clutter_stage_set_key_focus()).
6705 * Return value: %TRUE if the event has been handled by the actor,
6706 * or %FALSE to continue the emission.
6710 actor_signals[KEY_RELEASE_EVENT] =
6711 g_signal_new (I_("key-release-event"),
6712 G_TYPE_FROM_CLASS (object_class),
6714 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6715 _clutter_boolean_handled_accumulator, NULL,
6716 _clutter_marshal_BOOLEAN__BOXED,
6718 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6720 * ClutterActor::motion-event:
6721 * @actor: the actor which received the event
6722 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6724 * The ::motion-event signal is emitted each time the mouse pointer is
6725 * moved over @actor.
6727 * Return value: %TRUE if the event has been handled by the actor,
6728 * or %FALSE to continue the emission.
6732 actor_signals[MOTION_EVENT] =
6733 g_signal_new (I_("motion-event"),
6734 G_TYPE_FROM_CLASS (object_class),
6736 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6737 _clutter_boolean_handled_accumulator, NULL,
6738 _clutter_marshal_BOOLEAN__BOXED,
6740 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6743 * ClutterActor::key-focus-in:
6744 * @actor: the actor which now has key focus
6746 * The ::key-focus-in signal is emitted when @actor receives key focus.
6750 actor_signals[KEY_FOCUS_IN] =
6751 g_signal_new (I_("key-focus-in"),
6752 G_TYPE_FROM_CLASS (object_class),
6754 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6756 _clutter_marshal_VOID__VOID,
6760 * ClutterActor::key-focus-out:
6761 * @actor: the actor which now has key focus
6763 * The ::key-focus-out signal is emitted when @actor loses key focus.
6767 actor_signals[KEY_FOCUS_OUT] =
6768 g_signal_new (I_("key-focus-out"),
6769 G_TYPE_FROM_CLASS (object_class),
6771 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6773 _clutter_marshal_VOID__VOID,
6777 * ClutterActor::enter-event:
6778 * @actor: the actor which the pointer has entered.
6779 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6781 * The ::enter-event signal is emitted when the pointer enters the @actor
6783 * Return value: %TRUE if the event has been handled by the actor,
6784 * or %FALSE to continue the emission.
6788 actor_signals[ENTER_EVENT] =
6789 g_signal_new (I_("enter-event"),
6790 G_TYPE_FROM_CLASS (object_class),
6792 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6793 _clutter_boolean_handled_accumulator, NULL,
6794 _clutter_marshal_BOOLEAN__BOXED,
6796 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6799 * ClutterActor::leave-event:
6800 * @actor: the actor which the pointer has left
6801 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6803 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6805 * Return value: %TRUE if the event has been handled by the actor,
6806 * or %FALSE to continue the emission.
6810 actor_signals[LEAVE_EVENT] =
6811 g_signal_new (I_("leave-event"),
6812 G_TYPE_FROM_CLASS (object_class),
6814 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6815 _clutter_boolean_handled_accumulator, NULL,
6816 _clutter_marshal_BOOLEAN__BOXED,
6818 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6821 * ClutterActor::captured-event:
6822 * @actor: the actor which received the signal
6823 * @event: a #ClutterEvent
6825 * The ::captured-event signal is emitted when an event is captured
6826 * by Clutter. This signal will be emitted starting from the top-level
6827 * container (the #ClutterStage) to the actor which received the event
6828 * going down the hierarchy. This signal can be used to intercept every
6829 * event before the specialized events (like
6830 * ClutterActor::button-press-event or ::key-released-event) are
6833 * Return value: %TRUE if the event has been handled by the actor,
6834 * or %FALSE to continue the emission.
6838 actor_signals[CAPTURED_EVENT] =
6839 g_signal_new (I_("captured-event"),
6840 G_TYPE_FROM_CLASS (object_class),
6842 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6843 _clutter_boolean_handled_accumulator, NULL,
6844 _clutter_marshal_BOOLEAN__BOXED,
6846 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6849 * ClutterActor::paint:
6850 * @actor: the #ClutterActor that received the signal
6852 * The ::paint signal is emitted each time an actor is being painted.
6854 * Subclasses of #ClutterActor should override the class signal handler
6855 * and paint themselves in that function.
6857 * It is possible to connect a handler to the ::paint signal in order
6858 * to set up some custom aspect of a paint.
6862 actor_signals[PAINT] =
6863 g_signal_new (I_("paint"),
6864 G_TYPE_FROM_CLASS (object_class),
6867 G_STRUCT_OFFSET (ClutterActorClass, paint),
6869 _clutter_marshal_VOID__VOID,
6872 * ClutterActor::realize:
6873 * @actor: the #ClutterActor that received the signal
6875 * The ::realize signal is emitted each time an actor is being
6880 actor_signals[REALIZE] =
6881 g_signal_new (I_("realize"),
6882 G_TYPE_FROM_CLASS (object_class),
6884 G_STRUCT_OFFSET (ClutterActorClass, realize),
6886 _clutter_marshal_VOID__VOID,
6889 * ClutterActor::unrealize:
6890 * @actor: the #ClutterActor that received the signal
6892 * The ::unrealize signal is emitted each time an actor is being
6897 actor_signals[UNREALIZE] =
6898 g_signal_new (I_("unrealize"),
6899 G_TYPE_FROM_CLASS (object_class),
6901 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6903 _clutter_marshal_VOID__VOID,
6907 * ClutterActor::pick:
6908 * @actor: the #ClutterActor that received the signal
6909 * @color: the #ClutterColor to be used when picking
6911 * The ::pick signal is emitted each time an actor is being painted
6912 * in "pick mode". The pick mode is used to identify the actor during
6913 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6914 * The actor should paint its shape using the passed @pick_color.
6916 * Subclasses of #ClutterActor should override the class signal handler
6917 * and paint themselves in that function.
6919 * It is possible to connect a handler to the ::pick signal in order
6920 * to set up some custom aspect of a paint in pick mode.
6924 actor_signals[PICK] =
6925 g_signal_new (I_("pick"),
6926 G_TYPE_FROM_CLASS (object_class),
6928 G_STRUCT_OFFSET (ClutterActorClass, pick),
6930 _clutter_marshal_VOID__BOXED,
6932 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6935 * ClutterActor::allocation-changed:
6936 * @actor: the #ClutterActor that emitted the signal
6937 * @box: a #ClutterActorBox with the new allocation
6938 * @flags: #ClutterAllocationFlags for the allocation
6940 * The ::allocation-changed signal is emitted when the
6941 * #ClutterActor:allocation property changes. Usually, application
6942 * code should just use the notifications for the :allocation property
6943 * but if you want to track the allocation flags as well, for instance
6944 * to know whether the absolute origin of @actor changed, then you might
6945 * want use this signal instead.
6949 actor_signals[ALLOCATION_CHANGED] =
6950 g_signal_new (I_("allocation-changed"),
6951 G_TYPE_FROM_CLASS (object_class),
6955 _clutter_marshal_VOID__BOXED_FLAGS,
6957 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6958 CLUTTER_TYPE_ALLOCATION_FLAGS);
6961 * ClutterActor::transitions-completed:
6962 * @actor: a #ClutterActor
6964 * The ::transitions-completed signal is emitted once all transitions
6965 * involving @actor are complete.
6969 actor_signals[TRANSITIONS_COMPLETED] =
6970 g_signal_new (I_("transitions-completed"),
6971 G_TYPE_FROM_CLASS (object_class),
6975 _clutter_marshal_VOID__VOID,
6980 clutter_actor_init (ClutterActor *self)
6982 ClutterActorPrivate *priv;
6984 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6986 priv->id = _clutter_context_acquire_id (self);
6989 priv->opacity = 0xff;
6990 priv->show_on_set_parent = TRUE;
6992 priv->needs_width_request = TRUE;
6993 priv->needs_height_request = TRUE;
6994 priv->needs_allocation = TRUE;
6996 priv->cached_width_age = 1;
6997 priv->cached_height_age = 1;
6999 priv->opacity_override = -1;
7000 priv->enable_model_view_transform = TRUE;
7002 /* Initialize an empty paint volume to start with */
7003 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7004 priv->last_paint_volume_valid = TRUE;
7006 priv->transform_valid = FALSE;
7008 /* the default is to stretch the content, to match the
7009 * current behaviour of basically all actors. also, it's
7010 * the easiest thing to compute.
7012 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7013 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7014 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7018 * clutter_actor_new:
7020 * Creates a new #ClutterActor.
7022 * A newly created actor has a floating reference, which will be sunk
7023 * when it is added to another actor.
7025 * Return value: (transfer full): the newly created #ClutterActor
7030 clutter_actor_new (void)
7032 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7036 * clutter_actor_destroy:
7037 * @self: a #ClutterActor
7039 * Destroys an actor. When an actor is destroyed, it will break any
7040 * references it holds to other objects. If the actor is inside a
7041 * container, the actor will be removed.
7043 * When you destroy a container, its children will be destroyed as well.
7045 * Note: you cannot destroy the #ClutterStage returned by
7046 * clutter_stage_get_default().
7049 clutter_actor_destroy (ClutterActor *self)
7051 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7053 g_object_ref (self);
7055 /* avoid recursion while destroying */
7056 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7058 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7060 g_object_run_dispose (G_OBJECT (self));
7062 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7065 g_object_unref (self);
7069 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7070 ClutterPaintVolume *clip)
7072 ClutterActorPrivate *priv = self->priv;
7073 ClutterPaintVolume *pv;
7076 /* Remove queue entry early in the process, otherwise a new
7077 queue_redraw() during signal handling could put back this
7078 object in the stage redraw list (but the entry is freed as
7079 soon as we return from this function, causing a segfault
7082 priv->queue_redraw_entry = NULL;
7084 /* If we've been explicitly passed a clip volume then there's
7085 * nothing more to calculate, but otherwise the only thing we know
7086 * is that the change is constrained to the given actor.
7088 * The idea is that if we know the paint volume for where the actor
7089 * was last drawn (in eye coordinates) and we also have the paint
7090 * volume for where it will be drawn next (in actor coordinates)
7091 * then if we queue a redraw for both these volumes that will cover
7092 * everything that needs to be redrawn to clear the old view and
7093 * show the latest view of the actor.
7095 * Don't clip this redraw if we don't know what position we had for
7096 * the previous redraw since we don't know where to set the clip so
7097 * it will clear the actor as it is currently.
7101 _clutter_actor_set_queue_redraw_clip (self, clip);
7104 else if (G_LIKELY (priv->last_paint_volume_valid))
7106 pv = _clutter_actor_get_paint_volume_mutable (self);
7109 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7111 /* make sure we redraw the actors old position... */
7112 _clutter_actor_set_queue_redraw_clip (stage,
7113 &priv->last_paint_volume);
7114 _clutter_actor_signal_queue_redraw (stage, stage);
7115 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7117 /* XXX: Ideally the redraw signal would take a clip volume
7118 * argument, but that would be an ABI break. Until we can
7119 * break the ABI we pass the argument out-of-band
7122 /* setup the clip for the actors new position... */
7123 _clutter_actor_set_queue_redraw_clip (self, pv);
7132 _clutter_actor_signal_queue_redraw (self, self);
7134 /* Just in case anyone is manually firing redraw signals without
7135 * using the public queue_redraw() API we are careful to ensure that
7136 * our out-of-band clip member is cleared before returning...
7138 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7140 if (G_LIKELY (clipped))
7141 _clutter_actor_set_queue_redraw_clip (self, NULL);
7145 _clutter_actor_get_allocation_clip (ClutterActor *self,
7146 ClutterActorBox *clip)
7148 ClutterActorBox allocation;
7150 /* XXX: we don't care if we get an out of date allocation here
7151 * because clutter_actor_queue_redraw_with_clip knows to ignore
7152 * the clip if the actor's allocation is invalid.
7154 * This is noted because clutter_actor_get_allocation_box does some
7155 * unnecessary work to support buggy code with a comment suggesting
7156 * that it could be changed later which would be good for this use
7159 clutter_actor_get_allocation_box (self, &allocation);
7161 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7162 * actor's own coordinate space but the allocation is in parent
7166 clip->x2 = allocation.x2 - allocation.x1;
7167 clip->y2 = allocation.y2 - allocation.y1;
7171 _clutter_actor_queue_redraw_full (ClutterActor *self,
7172 ClutterRedrawFlags flags,
7173 ClutterPaintVolume *volume,
7174 ClutterEffect *effect)
7176 ClutterActorPrivate *priv = self->priv;
7177 ClutterPaintVolume allocation_pv;
7178 ClutterPaintVolume *pv;
7179 gboolean should_free_pv;
7180 ClutterActor *stage;
7182 /* Here's an outline of the actor queue redraw mechanism:
7184 * The process starts in one of the following two functions which
7185 * are wrappers for this function:
7186 * clutter_actor_queue_redraw
7187 * _clutter_actor_queue_redraw_with_clip
7189 * additionally, an effect can queue a redraw by wrapping this
7190 * function in clutter_effect_queue_rerun
7192 * This functions queues an entry in a list associated with the
7193 * stage which is a list of actors that queued a redraw while
7194 * updating the timelines, performing layouting and processing other
7195 * mainloop sources before the next paint starts.
7197 * We aim to minimize the processing done at this point because
7198 * there is a good chance other events will happen while updating
7199 * the scenegraph that would invalidate any expensive work we might
7200 * otherwise try to do here. For example we don't try and resolve
7201 * the screen space bounding box of an actor at this stage so as to
7202 * minimize how much of the screen redraw because it's possible
7203 * something else will happen which will force a full redraw anyway.
7205 * When all updates are complete and we come to paint the stage then
7206 * we iterate this list and actually emit the "queue-redraw" signals
7207 * for each of the listed actors which will bubble up to the stage
7208 * for each actor and at that point we will transform the actors
7209 * paint volume into screen coordinates to determine the clip region
7210 * for what needs to be redrawn in the next paint.
7212 * Besides minimizing redundant work another reason for this
7213 * deferred design is that it's more likely we will be able to
7214 * determine the paint volume of an actor once we've finished
7215 * updating the scenegraph because its allocation should be up to
7216 * date. NB: If we can't determine an actors paint volume then we
7217 * can't automatically queue a clipped redraw which can make a big
7218 * difference to performance.
7220 * So the control flow goes like this:
7221 * One of clutter_actor_queue_redraw,
7222 * _clutter_actor_queue_redraw_with_clip
7223 * or clutter_effect_queue_rerun
7225 * then control moves to:
7226 * _clutter_stage_queue_actor_redraw
7228 * later during _clutter_stage_do_update, once relayouting is done
7229 * and the scenegraph has been updated we will call:
7230 * _clutter_stage_finish_queue_redraws
7232 * _clutter_stage_finish_queue_redraws will call
7233 * _clutter_actor_finish_queue_redraw for each listed actor.
7234 * Note: actors *are* allowed to queue further redraws during this
7235 * process (considering clone actors or texture_new_from_actor which
7236 * respond to their source queueing a redraw by queuing a redraw
7237 * themselves). We repeat the process until the list is empty.
7239 * This will result in the "queue-redraw" signal being fired for
7240 * each actor which will pass control to the default signal handler:
7241 * clutter_actor_real_queue_redraw
7243 * This will bubble up to the stages handler:
7244 * clutter_stage_real_queue_redraw
7246 * clutter_stage_real_queue_redraw will transform the actors paint
7247 * volume into screen space and add it as a clip region for the next
7251 /* ignore queueing a redraw for actors being destroyed */
7252 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7255 stage = _clutter_actor_get_stage_internal (self);
7257 /* Ignore queueing a redraw for actors not descended from a stage */
7261 /* ignore queueing a redraw on stages that are being destroyed */
7262 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7265 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7267 ClutterActorBox allocation_clip;
7268 ClutterVertex origin;
7270 /* If the actor doesn't have a valid allocation then we will
7271 * queue a full stage redraw. */
7272 if (priv->needs_allocation)
7274 /* NB: NULL denotes an undefined clip which will result in a
7276 _clutter_actor_set_queue_redraw_clip (self, NULL);
7277 _clutter_actor_signal_queue_redraw (self, self);
7281 _clutter_paint_volume_init_static (&allocation_pv, self);
7282 pv = &allocation_pv;
7284 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7286 origin.x = allocation_clip.x1;
7287 origin.y = allocation_clip.y1;
7289 clutter_paint_volume_set_origin (pv, &origin);
7290 clutter_paint_volume_set_width (pv,
7291 allocation_clip.x2 - allocation_clip.x1);
7292 clutter_paint_volume_set_height (pv,
7293 allocation_clip.y2 -
7294 allocation_clip.y1);
7295 should_free_pv = TRUE;
7300 should_free_pv = FALSE;
7303 self->priv->queue_redraw_entry =
7304 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7305 priv->queue_redraw_entry,
7310 clutter_paint_volume_free (pv);
7312 /* If this is the first redraw queued then we can directly use the
7314 if (!priv->is_dirty)
7315 priv->effect_to_redraw = effect;
7316 /* Otherwise we need to merge it with the existing effect parameter */
7317 else if (effect != NULL)
7319 /* If there's already an effect then we need to use whichever is
7320 later in the chain of actors. Otherwise a full redraw has
7321 already been queued on the actor so we need to ignore the
7323 if (priv->effect_to_redraw != NULL)
7325 if (priv->effects == NULL)
7326 g_warning ("Redraw queued with an effect that is "
7327 "not applied to the actor");
7332 for (l = _clutter_meta_group_peek_metas (priv->effects);
7336 if (l->data == priv->effect_to_redraw ||
7338 priv->effect_to_redraw = l->data;
7345 /* If no effect is specified then we need to redraw the whole
7347 priv->effect_to_redraw = NULL;
7350 priv->is_dirty = TRUE;
7354 * clutter_actor_queue_redraw:
7355 * @self: A #ClutterActor
7357 * Queues up a redraw of an actor and any children. The redraw occurs
7358 * once the main loop becomes idle (after the current batch of events
7359 * has been processed, roughly).
7361 * Applications rarely need to call this, as redraws are handled
7362 * automatically by modification functions.
7364 * This function will not do anything if @self is not visible, or
7365 * if the actor is inside an invisible part of the scenegraph.
7367 * Also be aware that painting is a NOP for actors with an opacity of
7370 * When you are implementing a custom actor you must queue a redraw
7371 * whenever some private state changes that will affect painting or
7372 * picking of your actor.
7375 clutter_actor_queue_redraw (ClutterActor *self)
7377 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7379 _clutter_actor_queue_redraw_full (self,
7381 NULL, /* clip volume */
7386 * _clutter_actor_queue_redraw_with_clip:
7387 * @self: A #ClutterActor
7388 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7389 * this queue redraw.
7390 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7391 * redrawn or %NULL if you are just using a @flag to state your
7394 * Queues up a clipped redraw of an actor and any children. The redraw
7395 * occurs once the main loop becomes idle (after the current batch of
7396 * events has been processed, roughly).
7398 * If no flags are given the clip volume is defined by @volume
7399 * specified in actor coordinates and tells Clutter that only content
7400 * within this volume has been changed so Clutter can optionally
7401 * optimize the redraw.
7403 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7404 * should be %NULL and this tells Clutter to use the actor's current
7405 * allocation as a clip box. This flag can only be used for 2D actors,
7406 * because any actor with depth may be projected outside its
7409 * Applications rarely need to call this, as redraws are handled
7410 * automatically by modification functions.
7412 * This function will not do anything if @self is not visible, or if
7413 * the actor is inside an invisible part of the scenegraph.
7415 * Also be aware that painting is a NOP for actors with an opacity of
7418 * When you are implementing a custom actor you must queue a redraw
7419 * whenever some private state changes that will affect painting or
7420 * picking of your actor.
7423 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7424 ClutterRedrawFlags flags,
7425 ClutterPaintVolume *volume)
7427 _clutter_actor_queue_redraw_full (self,
7429 volume, /* clip volume */
7434 _clutter_actor_queue_only_relayout (ClutterActor *self)
7436 ClutterActorPrivate *priv = self->priv;
7438 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7441 if (priv->needs_width_request &&
7442 priv->needs_height_request &&
7443 priv->needs_allocation)
7444 return; /* save some cpu cycles */
7446 #if CLUTTER_ENABLE_DEBUG
7447 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7449 g_warning ("The actor '%s' is currently inside an allocation "
7450 "cycle; calling clutter_actor_queue_relayout() is "
7452 _clutter_actor_get_debug_name (self));
7454 #endif /* CLUTTER_ENABLE_DEBUG */
7456 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7460 * clutter_actor_queue_redraw_with_clip:
7461 * @self: a #ClutterActor
7462 * @clip: (allow-none): a rectangular clip region, or %NULL
7464 * Queues a redraw on @self limited to a specific, actor-relative
7467 * If @clip is %NULL this function is equivalent to
7468 * clutter_actor_queue_redraw().
7473 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7474 const cairo_rectangle_int_t *clip)
7476 ClutterPaintVolume volume;
7477 ClutterVertex origin;
7479 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7483 clutter_actor_queue_redraw (self);
7487 _clutter_paint_volume_init_static (&volume, self);
7493 clutter_paint_volume_set_origin (&volume, &origin);
7494 clutter_paint_volume_set_width (&volume, clip->width);
7495 clutter_paint_volume_set_height (&volume, clip->height);
7497 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7499 clutter_paint_volume_free (&volume);
7503 * clutter_actor_queue_relayout:
7504 * @self: A #ClutterActor
7506 * Indicates that the actor's size request or other layout-affecting
7507 * properties may have changed. This function is used inside #ClutterActor
7508 * subclass implementations, not by applications directly.
7510 * Queueing a new layout automatically queues a redraw as well.
7515 clutter_actor_queue_relayout (ClutterActor *self)
7517 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7519 _clutter_actor_queue_only_relayout (self);
7520 clutter_actor_queue_redraw (self);
7524 * clutter_actor_get_preferred_size:
7525 * @self: a #ClutterActor
7526 * @min_width_p: (out) (allow-none): return location for the minimum
7528 * @min_height_p: (out) (allow-none): return location for the minimum
7530 * @natural_width_p: (out) (allow-none): return location for the natural
7532 * @natural_height_p: (out) (allow-none): return location for the natural
7535 * Computes the preferred minimum and natural size of an actor, taking into
7536 * account the actor's geometry management (either height-for-width
7537 * or width-for-height).
7539 * The width and height used to compute the preferred height and preferred
7540 * width are the actor's natural ones.
7542 * If you need to control the height for the preferred width, or the width for
7543 * the preferred height, you should use clutter_actor_get_preferred_width()
7544 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7545 * geometry management using the #ClutterActor:request-mode property.
7550 clutter_actor_get_preferred_size (ClutterActor *self,
7551 gfloat *min_width_p,
7552 gfloat *min_height_p,
7553 gfloat *natural_width_p,
7554 gfloat *natural_height_p)
7556 ClutterActorPrivate *priv;
7557 gfloat min_width, min_height;
7558 gfloat natural_width, natural_height;
7560 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7564 min_width = min_height = 0;
7565 natural_width = natural_height = 0;
7567 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7569 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7570 clutter_actor_get_preferred_width (self, -1,
7573 clutter_actor_get_preferred_height (self, natural_width,
7579 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7580 clutter_actor_get_preferred_height (self, -1,
7583 clutter_actor_get_preferred_width (self, natural_height,
7589 *min_width_p = min_width;
7592 *min_height_p = min_height;
7594 if (natural_width_p)
7595 *natural_width_p = natural_width;
7597 if (natural_height_p)
7598 *natural_height_p = natural_height;
7603 * @align: a #ClutterActorAlign
7604 * @direction: a #ClutterTextDirection
7606 * Retrieves the correct alignment depending on the text direction
7608 * Return value: the effective alignment
7610 static ClutterActorAlign
7611 effective_align (ClutterActorAlign align,
7612 ClutterTextDirection direction)
7614 ClutterActorAlign res;
7618 case CLUTTER_ACTOR_ALIGN_START:
7619 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7620 ? CLUTTER_ACTOR_ALIGN_END
7621 : CLUTTER_ACTOR_ALIGN_START;
7624 case CLUTTER_ACTOR_ALIGN_END:
7625 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7626 ? CLUTTER_ACTOR_ALIGN_START
7627 : CLUTTER_ACTOR_ALIGN_END;
7639 adjust_for_margin (float margin_start,
7641 float *minimum_size,
7642 float *natural_size,
7643 float *allocated_start,
7644 float *allocated_end)
7646 *minimum_size -= (margin_start + margin_end);
7647 *natural_size -= (margin_start + margin_end);
7648 *allocated_start += margin_start;
7649 *allocated_end -= margin_end;
7653 adjust_for_alignment (ClutterActorAlign alignment,
7655 float *allocated_start,
7656 float *allocated_end)
7658 float allocated_size = *allocated_end - *allocated_start;
7662 case CLUTTER_ACTOR_ALIGN_FILL:
7666 case CLUTTER_ACTOR_ALIGN_START:
7668 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7671 case CLUTTER_ACTOR_ALIGN_END:
7672 if (allocated_size > natural_size)
7674 *allocated_start += (allocated_size - natural_size);
7675 *allocated_end = *allocated_start + natural_size;
7679 case CLUTTER_ACTOR_ALIGN_CENTER:
7680 if (allocated_size > natural_size)
7682 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7683 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7690 * clutter_actor_adjust_width:
7691 * @self: a #ClutterActor
7692 * @minimum_width: (inout): the actor's preferred minimum width, which
7693 * will be adjusted depending on the margin
7694 * @natural_width: (inout): the actor's preferred natural width, which
7695 * will be adjusted depending on the margin
7696 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7697 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7699 * Adjusts the preferred and allocated position and size of an actor,
7700 * depending on the margin and alignment properties.
7703 clutter_actor_adjust_width (ClutterActor *self,
7704 gfloat *minimum_width,
7705 gfloat *natural_width,
7706 gfloat *adjusted_x1,
7707 gfloat *adjusted_x2)
7709 ClutterTextDirection text_dir;
7710 const ClutterLayoutInfo *info;
7712 info = _clutter_actor_get_layout_info_or_defaults (self);
7713 text_dir = clutter_actor_get_text_direction (self);
7715 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7717 /* this will tweak natural_width to remove the margin, so that
7718 * adjust_for_alignment() will use the correct size
7720 adjust_for_margin (info->margin.left, info->margin.right,
7721 minimum_width, natural_width,
7722 adjusted_x1, adjusted_x2);
7724 adjust_for_alignment (effective_align (info->x_align, text_dir),
7726 adjusted_x1, adjusted_x2);
7730 * clutter_actor_adjust_height:
7731 * @self: a #ClutterActor
7732 * @minimum_height: (inout): the actor's preferred minimum height, which
7733 * will be adjusted depending on the margin
7734 * @natural_height: (inout): the actor's preferred natural height, which
7735 * will be adjusted depending on the margin
7736 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7737 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7739 * Adjusts the preferred and allocated position and size of an actor,
7740 * depending on the margin and alignment properties.
7743 clutter_actor_adjust_height (ClutterActor *self,
7744 gfloat *minimum_height,
7745 gfloat *natural_height,
7746 gfloat *adjusted_y1,
7747 gfloat *adjusted_y2)
7749 const ClutterLayoutInfo *info;
7751 info = _clutter_actor_get_layout_info_or_defaults (self);
7753 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7755 /* this will tweak natural_height to remove the margin, so that
7756 * adjust_for_alignment() will use the correct size
7758 adjust_for_margin (info->margin.top, info->margin.bottom,
7759 minimum_height, natural_height,
7763 /* we don't use effective_align() here, because text direction
7764 * only affects the horizontal axis
7766 adjust_for_alignment (info->y_align,
7773 /* looks for a cached size request for this for_size. If not
7774 * found, returns the oldest entry so it can be overwritten */
7776 _clutter_actor_get_cached_size_request (gfloat for_size,
7777 SizeRequest *cached_size_requests,
7778 SizeRequest **result)
7782 *result = &cached_size_requests[0];
7784 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7788 sr = &cached_size_requests[i];
7791 sr->for_size == for_size)
7793 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7797 else if (sr->age < (*result)->age)
7803 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7809 * clutter_actor_get_preferred_width:
7810 * @self: A #ClutterActor
7811 * @for_height: available height when computing the preferred width,
7812 * or a negative value to indicate that no height is defined
7813 * @min_width_p: (out) (allow-none): return location for minimum width,
7815 * @natural_width_p: (out) (allow-none): return location for the natural
7818 * Computes the requested minimum and natural widths for an actor,
7819 * optionally depending on the specified height, or if they are
7820 * already computed, returns the cached values.
7822 * An actor may not get its request - depending on the layout
7823 * manager that's in effect.
7825 * A request should not incorporate the actor's scale or anchor point;
7826 * those transformations do not affect layout, only rendering.
7831 clutter_actor_get_preferred_width (ClutterActor *self,
7833 gfloat *min_width_p,
7834 gfloat *natural_width_p)
7836 float request_min_width, request_natural_width;
7837 SizeRequest *cached_size_request;
7838 const ClutterLayoutInfo *info;
7839 ClutterActorPrivate *priv;
7840 gboolean found_in_cache;
7842 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7846 info = _clutter_actor_get_layout_info_or_defaults (self);
7848 /* we shortcircuit the case of a fixed size set using set_width() */
7849 if (priv->min_width_set && priv->natural_width_set)
7851 if (min_width_p != NULL)
7852 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7854 if (natural_width_p != NULL)
7855 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7860 /* the remaining cases are:
7862 * - either min_width or natural_width have been set
7863 * - neither min_width or natural_width have been set
7865 * in both cases, we go through the cache (and through the actor in case
7866 * of cache misses) and determine the authoritative value depending on
7870 if (!priv->needs_width_request)
7873 _clutter_actor_get_cached_size_request (for_height,
7874 priv->width_requests,
7875 &cached_size_request);
7879 /* if the actor needs a width request we use the first slot */
7880 found_in_cache = FALSE;
7881 cached_size_request = &priv->width_requests[0];
7884 if (!found_in_cache)
7886 gfloat minimum_width, natural_width;
7887 ClutterActorClass *klass;
7889 minimum_width = natural_width = 0;
7891 /* adjust for the margin */
7892 if (for_height >= 0)
7894 for_height -= (info->margin.top + info->margin.bottom);
7899 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7901 klass = CLUTTER_ACTOR_GET_CLASS (self);
7902 klass->get_preferred_width (self, for_height,
7906 /* adjust for the margin */
7907 minimum_width += (info->margin.left + info->margin.right);
7908 natural_width += (info->margin.left + info->margin.right);
7910 /* Due to accumulated float errors, it's better not to warn
7911 * on this, but just fix it.
7913 if (natural_width < minimum_width)
7914 natural_width = minimum_width;
7916 cached_size_request->min_size = minimum_width;
7917 cached_size_request->natural_size = natural_width;
7918 cached_size_request->for_size = for_height;
7919 cached_size_request->age = priv->cached_width_age;
7921 priv->cached_width_age += 1;
7922 priv->needs_width_request = FALSE;
7925 if (!priv->min_width_set)
7926 request_min_width = cached_size_request->min_size;
7928 request_min_width = info->min_width;
7930 if (!priv->natural_width_set)
7931 request_natural_width = cached_size_request->natural_size;
7933 request_natural_width = info->natural_width;
7936 *min_width_p = request_min_width;
7938 if (natural_width_p)
7939 *natural_width_p = request_natural_width;
7943 * clutter_actor_get_preferred_height:
7944 * @self: A #ClutterActor
7945 * @for_width: available width to assume in computing desired height,
7946 * or a negative value to indicate that no width is defined
7947 * @min_height_p: (out) (allow-none): return location for minimum height,
7949 * @natural_height_p: (out) (allow-none): return location for natural
7952 * Computes the requested minimum and natural heights for an actor,
7953 * or if they are already computed, returns the cached values.
7955 * An actor may not get its request - depending on the layout
7956 * manager that's in effect.
7958 * A request should not incorporate the actor's scale or anchor point;
7959 * those transformations do not affect layout, only rendering.
7964 clutter_actor_get_preferred_height (ClutterActor *self,
7966 gfloat *min_height_p,
7967 gfloat *natural_height_p)
7969 float request_min_height, request_natural_height;
7970 SizeRequest *cached_size_request;
7971 const ClutterLayoutInfo *info;
7972 ClutterActorPrivate *priv;
7973 gboolean found_in_cache;
7975 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7979 info = _clutter_actor_get_layout_info_or_defaults (self);
7981 /* we shortcircuit the case of a fixed size set using set_height() */
7982 if (priv->min_height_set && priv->natural_height_set)
7984 if (min_height_p != NULL)
7985 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7987 if (natural_height_p != NULL)
7988 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7993 /* the remaining cases are:
7995 * - either min_height or natural_height have been set
7996 * - neither min_height or natural_height have been set
7998 * in both cases, we go through the cache (and through the actor in case
7999 * of cache misses) and determine the authoritative value depending on
8003 if (!priv->needs_height_request)
8006 _clutter_actor_get_cached_size_request (for_width,
8007 priv->height_requests,
8008 &cached_size_request);
8012 found_in_cache = FALSE;
8013 cached_size_request = &priv->height_requests[0];
8016 if (!found_in_cache)
8018 gfloat minimum_height, natural_height;
8019 ClutterActorClass *klass;
8021 minimum_height = natural_height = 0;
8023 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8025 /* adjust for margin */
8028 for_width -= (info->margin.left + info->margin.right);
8033 klass = CLUTTER_ACTOR_GET_CLASS (self);
8034 klass->get_preferred_height (self, for_width,
8038 /* adjust for margin */
8039 minimum_height += (info->margin.top + info->margin.bottom);
8040 natural_height += (info->margin.top + info->margin.bottom);
8042 /* Due to accumulated float errors, it's better not to warn
8043 * on this, but just fix it.
8045 if (natural_height < minimum_height)
8046 natural_height = minimum_height;
8048 cached_size_request->min_size = minimum_height;
8049 cached_size_request->natural_size = natural_height;
8050 cached_size_request->for_size = for_width;
8051 cached_size_request->age = priv->cached_height_age;
8053 priv->cached_height_age += 1;
8054 priv->needs_height_request = FALSE;
8057 if (!priv->min_height_set)
8058 request_min_height = cached_size_request->min_size;
8060 request_min_height = info->min_height;
8062 if (!priv->natural_height_set)
8063 request_natural_height = cached_size_request->natural_size;
8065 request_natural_height = info->natural_height;
8068 *min_height_p = request_min_height;
8070 if (natural_height_p)
8071 *natural_height_p = request_natural_height;
8075 * clutter_actor_get_allocation_box:
8076 * @self: A #ClutterActor
8077 * @box: (out): the function fills this in with the actor's allocation
8079 * Gets the layout box an actor has been assigned. The allocation can
8080 * only be assumed valid inside a paint() method; anywhere else, it
8081 * may be out-of-date.
8083 * An allocation does not incorporate the actor's scale or anchor point;
8084 * those transformations do not affect layout, only rendering.
8086 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8087 * of functions inside the implementation of the get_preferred_width()
8088 * or get_preferred_height() virtual functions.</note>
8093 clutter_actor_get_allocation_box (ClutterActor *self,
8094 ClutterActorBox *box)
8096 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8098 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8099 * which limits calling get_allocation to inside paint() basically; or
8100 * we can 2) force a layout, which could be expensive if someone calls
8101 * get_allocation somewhere silly; or we can 3) just return the latest
8102 * value, allowing it to be out-of-date, and assume people know what
8105 * The least-surprises approach that keeps existing code working is
8106 * likely to be 2). People can end up doing some inefficient things,
8107 * though, and in general code that requires 2) is probably broken.
8110 /* this implements 2) */
8111 if (G_UNLIKELY (self->priv->needs_allocation))
8113 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8115 /* do not queue a relayout on an unparented actor */
8117 _clutter_stage_maybe_relayout (stage);
8120 /* commenting out the code above and just keeping this assigment
8123 *box = self->priv->allocation;
8127 * clutter_actor_get_allocation_geometry:
8128 * @self: A #ClutterActor
8129 * @geom: (out): allocation geometry in pixels
8131 * Gets the layout box an actor has been assigned. The allocation can
8132 * only be assumed valid inside a paint() method; anywhere else, it
8133 * may be out-of-date.
8135 * An allocation does not incorporate the actor's scale or anchor point;
8136 * those transformations do not affect layout, only rendering.
8138 * The returned rectangle is in pixels.
8143 clutter_actor_get_allocation_geometry (ClutterActor *self,
8144 ClutterGeometry *geom)
8146 ClutterActorBox box;
8148 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8149 g_return_if_fail (geom != NULL);
8151 clutter_actor_get_allocation_box (self, &box);
8153 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8154 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8155 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8156 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8160 clutter_actor_update_constraints (ClutterActor *self,
8161 ClutterActorBox *allocation)
8163 ClutterActorPrivate *priv = self->priv;
8164 const GList *constraints, *l;
8166 if (priv->constraints == NULL)
8169 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8170 for (l = constraints; l != NULL; l = l->next)
8172 ClutterConstraint *constraint = l->data;
8173 ClutterActorMeta *meta = l->data;
8175 if (clutter_actor_meta_get_enabled (meta))
8177 _clutter_constraint_update_allocation (constraint,
8181 CLUTTER_NOTE (LAYOUT,
8182 "Allocation of '%s' after constraint '%s': "
8183 "{ %.2f, %.2f, %.2f, %.2f }",
8184 _clutter_actor_get_debug_name (self),
8185 _clutter_actor_meta_get_debug_name (meta),
8195 * clutter_actor_adjust_allocation:
8196 * @self: a #ClutterActor
8197 * @allocation: (inout): the allocation to adjust
8199 * Adjusts the passed allocation box taking into account the actor's
8200 * layout information, like alignment, expansion, and margin.
8203 clutter_actor_adjust_allocation (ClutterActor *self,
8204 ClutterActorBox *allocation)
8206 ClutterActorBox adj_allocation;
8207 float alloc_width, alloc_height;
8208 float min_width, min_height;
8209 float nat_width, nat_height;
8210 ClutterRequestMode req_mode;
8212 adj_allocation = *allocation;
8214 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8216 /* we want to hit the cache, so we use the public API */
8217 req_mode = clutter_actor_get_request_mode (self);
8219 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8221 clutter_actor_get_preferred_width (self, -1,
8224 clutter_actor_get_preferred_height (self, alloc_width,
8228 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8230 clutter_actor_get_preferred_height (self, -1,
8233 clutter_actor_get_preferred_height (self, alloc_height,
8238 #ifdef CLUTTER_ENABLE_DEBUG
8239 /* warn about underallocations */
8240 if (_clutter_diagnostic_enabled () &&
8241 (floorf (min_width - alloc_width) > 0 ||
8242 floorf (min_height - alloc_height) > 0))
8244 ClutterActor *parent = clutter_actor_get_parent (self);
8246 /* the only actors that are allowed to be underallocated are the Stage,
8247 * as it doesn't have an implicit size, and Actors that specifically
8248 * told us that they want to opt-out from layout control mechanisms
8249 * through the NO_LAYOUT escape hatch.
8251 if (parent != NULL &&
8252 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8254 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8255 "of %.2f x %.2f from its parent actor '%s', but its "
8256 "requested minimum size is of %.2f x %.2f",
8257 _clutter_actor_get_debug_name (self),
8258 alloc_width, alloc_height,
8259 _clutter_actor_get_debug_name (parent),
8260 min_width, min_height);
8265 clutter_actor_adjust_width (self,
8269 &adj_allocation.x2);
8271 clutter_actor_adjust_height (self,
8275 &adj_allocation.y2);
8277 /* we maintain the invariant that an allocation cannot be adjusted
8278 * to be outside the parent-given box
8280 if (adj_allocation.x1 < allocation->x1 ||
8281 adj_allocation.y1 < allocation->y1 ||
8282 adj_allocation.x2 > allocation->x2 ||
8283 adj_allocation.y2 > allocation->y2)
8285 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8286 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8287 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8288 _clutter_actor_get_debug_name (self),
8289 adj_allocation.x1, adj_allocation.y1,
8290 adj_allocation.x2 - adj_allocation.x1,
8291 adj_allocation.y2 - adj_allocation.y1,
8292 allocation->x1, allocation->y1,
8293 allocation->x2 - allocation->x1,
8294 allocation->y2 - allocation->y1);
8298 *allocation = adj_allocation;
8302 * clutter_actor_allocate:
8303 * @self: A #ClutterActor
8304 * @box: new allocation of the actor, in parent-relative coordinates
8305 * @flags: flags that control the allocation
8307 * Called by the parent of an actor to assign the actor its size.
8308 * Should never be called by applications (except when implementing
8309 * a container or layout manager).
8311 * Actors can know from their allocation box whether they have moved
8312 * with respect to their parent actor. The @flags parameter describes
8313 * additional information about the allocation, for instance whether
8314 * the parent has moved with respect to the stage, for example because
8315 * a grandparent's origin has moved.
8320 clutter_actor_allocate (ClutterActor *self,
8321 const ClutterActorBox *box,
8322 ClutterAllocationFlags flags)
8324 ClutterActorPrivate *priv;
8325 ClutterActorClass *klass;
8326 ClutterActorBox old_allocation, real_allocation;
8327 gboolean origin_changed, child_moved, size_changed;
8328 gboolean stage_allocation_changed;
8330 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8331 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8333 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8334 "which isn't a descendent of the stage!\n",
8335 self, _clutter_actor_get_debug_name (self));
8341 old_allocation = priv->allocation;
8342 real_allocation = *box;
8344 /* constraints are allowed to modify the allocation only here; we do
8345 * this prior to all the other checks so that we can bail out if the
8346 * allocation did not change
8348 clutter_actor_update_constraints (self, &real_allocation);
8350 /* adjust the allocation depending on the align/margin properties */
8351 clutter_actor_adjust_allocation (self, &real_allocation);
8353 if (real_allocation.x2 < real_allocation.x1 ||
8354 real_allocation.y2 < real_allocation.y1)
8356 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8357 _clutter_actor_get_debug_name (self),
8358 real_allocation.x2 - real_allocation.x1,
8359 real_allocation.y2 - real_allocation.y1);
8362 /* we allow 0-sized actors, but not negative-sized ones */
8363 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8364 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8366 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8368 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8369 real_allocation.y1 != old_allocation.y1);
8371 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8372 real_allocation.y2 != old_allocation.y2);
8374 if (origin_changed || child_moved || size_changed)
8375 stage_allocation_changed = TRUE;
8377 stage_allocation_changed = FALSE;
8379 /* If we get an allocation "out of the blue"
8380 * (we did not queue relayout), then we want to
8381 * ignore it. But if we have needs_allocation set,
8382 * we want to guarantee that allocate() virtual
8383 * method is always called, i.e. that queue_relayout()
8384 * always results in an allocate() invocation on
8387 * The optimization here is to avoid re-allocating
8388 * actors that did not queue relayout and were
8391 if (!priv->needs_allocation && !stage_allocation_changed)
8393 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8397 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8398 * clutter_actor_allocate(), it indicates whether the parent has its
8399 * absolute origin moved; when passed in to ClutterActor::allocate()
8400 * virtual method though, it indicates whether the child has its
8401 * absolute origin moved. So we set it when child_moved is TRUE
8404 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8406 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8408 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8409 _clutter_actor_get_debug_name (self));
8411 klass = CLUTTER_ACTOR_GET_CLASS (self);
8412 klass->allocate (self, &real_allocation, flags);
8414 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8416 if (stage_allocation_changed)
8417 clutter_actor_queue_redraw (self);
8421 * clutter_actor_set_allocation:
8422 * @self: a #ClutterActor
8423 * @box: a #ClutterActorBox
8424 * @flags: allocation flags
8426 * Stores the allocation of @self as defined by @box.
8428 * This function can only be called from within the implementation of
8429 * the #ClutterActorClass.allocate() virtual function.
8431 * The allocation should have been adjusted to take into account constraints,
8432 * alignment, and margin properties. If you are implementing a #ClutterActor
8433 * subclass that provides its own layout management policy for its children
8434 * instead of using a #ClutterLayoutManager delegate, you should not call
8435 * this function on the children of @self; instead, you should call
8436 * clutter_actor_allocate(), which will adjust the allocation box for
8439 * This function should only be used by subclasses of #ClutterActor
8440 * that wish to store their allocation but cannot chain up to the
8441 * parent's implementation; the default implementation of the
8442 * #ClutterActorClass.allocate() virtual function will call this
8445 * It is important to note that, while chaining up was the recommended
8446 * behaviour for #ClutterActor subclasses prior to the introduction of
8447 * this function, it is recommended to call clutter_actor_set_allocation()
8450 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8451 * to handle the allocation of its children, this function will call
8452 * the clutter_layout_manager_allocate() function only if the
8453 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8454 * expected that the subclass will call clutter_layout_manager_allocate()
8455 * by itself. For instance, the following code:
8459 * my_actor_allocate (ClutterActor *actor,
8460 * const ClutterActorBox *allocation,
8461 * ClutterAllocationFlags flags)
8463 * ClutterActorBox new_alloc;
8464 * ClutterAllocationFlags new_flags;
8466 * adjust_allocation (allocation, &new_alloc);
8468 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8470 * /* this will use the layout manager set on the actor */
8471 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8475 * is equivalent to this:
8479 * my_actor_allocate (ClutterActor *actor,
8480 * const ClutterActorBox *allocation,
8481 * ClutterAllocationFlags flags)
8483 * ClutterLayoutManager *layout;
8484 * ClutterActorBox new_alloc;
8486 * adjust_allocation (allocation, &new_alloc);
8488 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8490 * layout = clutter_actor_get_layout_manager (actor);
8491 * clutter_layout_manager_allocate (layout,
8492 * CLUTTER_CONTAINER (actor),
8501 clutter_actor_set_allocation (ClutterActor *self,
8502 const ClutterActorBox *box,
8503 ClutterAllocationFlags flags)
8505 ClutterActorPrivate *priv;
8508 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8509 g_return_if_fail (box != NULL);
8511 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8513 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8514 "can only be called from within the implementation of "
8515 "the ClutterActor::allocate() virtual function.");
8521 g_object_freeze_notify (G_OBJECT (self));
8523 changed = clutter_actor_set_allocation_internal (self, box, flags);
8525 /* we allocate our children before we notify changes in our geometry,
8526 * so that people connecting to properties will be able to get valid
8527 * data out of the sub-tree of the scene graph that has this actor at
8530 clutter_actor_maybe_layout_children (self, box, flags);
8534 ClutterActorBox signal_box = priv->allocation;
8535 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8537 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8542 g_object_thaw_notify (G_OBJECT (self));
8546 * clutter_actor_set_geometry:
8547 * @self: A #ClutterActor
8548 * @geometry: A #ClutterGeometry
8550 * Sets the actor's fixed position and forces its minimum and natural
8551 * size, in pixels. This means the untransformed actor will have the
8552 * given geometry. This is the same as calling clutter_actor_set_position()
8553 * and clutter_actor_set_size().
8555 * Deprecated: 1.10: Use clutter_actor_set_position() and
8556 * clutter_actor_set_size() instead.
8559 clutter_actor_set_geometry (ClutterActor *self,
8560 const ClutterGeometry *geometry)
8562 g_object_freeze_notify (G_OBJECT (self));
8564 clutter_actor_set_position (self, geometry->x, geometry->y);
8565 clutter_actor_set_size (self, geometry->width, geometry->height);
8567 g_object_thaw_notify (G_OBJECT (self));
8571 * clutter_actor_get_geometry:
8572 * @self: A #ClutterActor
8573 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8575 * Gets the size and position of an actor relative to its parent
8576 * actor. This is the same as calling clutter_actor_get_position() and
8577 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8578 * requested size and position if the actor's allocation is invalid.
8580 * Deprecated: 1.10: Use clutter_actor_get_position() and
8581 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8585 clutter_actor_get_geometry (ClutterActor *self,
8586 ClutterGeometry *geometry)
8588 gfloat x, y, width, height;
8590 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8591 g_return_if_fail (geometry != NULL);
8593 clutter_actor_get_position (self, &x, &y);
8594 clutter_actor_get_size (self, &width, &height);
8596 geometry->x = (int) x;
8597 geometry->y = (int) y;
8598 geometry->width = (int) width;
8599 geometry->height = (int) height;
8603 * clutter_actor_set_position:
8604 * @self: A #ClutterActor
8605 * @x: New left position of actor in pixels.
8606 * @y: New top position of actor in pixels.
8608 * Sets the actor's fixed position in pixels relative to any parent
8611 * If a layout manager is in use, this position will override the
8612 * layout manager and force a fixed position.
8615 clutter_actor_set_position (ClutterActor *self,
8619 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8621 g_object_freeze_notify (G_OBJECT (self));
8623 clutter_actor_set_x (self, x);
8624 clutter_actor_set_y (self, y);
8626 g_object_thaw_notify (G_OBJECT (self));
8630 * clutter_actor_get_fixed_position_set:
8631 * @self: A #ClutterActor
8633 * Checks whether an actor has a fixed position set (and will thus be
8634 * unaffected by any layout manager).
8636 * Return value: %TRUE if the fixed position is set on the actor
8641 clutter_actor_get_fixed_position_set (ClutterActor *self)
8643 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8645 return self->priv->position_set;
8649 * clutter_actor_set_fixed_position_set:
8650 * @self: A #ClutterActor
8651 * @is_set: whether to use fixed position
8653 * Sets whether an actor has a fixed position set (and will thus be
8654 * unaffected by any layout manager).
8659 clutter_actor_set_fixed_position_set (ClutterActor *self,
8662 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8664 if (self->priv->position_set == (is_set != FALSE))
8667 self->priv->position_set = is_set != FALSE;
8668 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8670 clutter_actor_queue_relayout (self);
8674 * clutter_actor_move_by:
8675 * @self: A #ClutterActor
8676 * @dx: Distance to move Actor on X axis.
8677 * @dy: Distance to move Actor on Y axis.
8679 * Moves an actor by the specified distance relative to its current
8680 * position in pixels.
8682 * This function modifies the fixed position of an actor and thus removes
8683 * it from any layout management. Another way to move an actor is with an
8684 * anchor point, see clutter_actor_set_anchor_point().
8689 clutter_actor_move_by (ClutterActor *self,
8693 const ClutterLayoutInfo *info;
8696 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8698 info = _clutter_actor_get_layout_info_or_defaults (self);
8702 clutter_actor_set_position (self, x + dx, y + dy);
8706 clutter_actor_set_min_width (ClutterActor *self,
8709 ClutterActorPrivate *priv = self->priv;
8710 ClutterActorBox old = { 0, };
8711 ClutterLayoutInfo *info;
8713 /* if we are setting the size on a top-level actor and the
8714 * backend only supports static top-levels (e.g. framebuffers)
8715 * then we ignore the passed value and we override it with
8716 * the stage implementation's preferred size.
8718 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8719 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8722 info = _clutter_actor_get_layout_info (self);
8724 if (priv->min_width_set && min_width == info->min_width)
8727 g_object_freeze_notify (G_OBJECT (self));
8729 clutter_actor_store_old_geometry (self, &old);
8731 info->min_width = min_width;
8732 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8733 clutter_actor_set_min_width_set (self, TRUE);
8735 clutter_actor_notify_if_geometry_changed (self, &old);
8737 g_object_thaw_notify (G_OBJECT (self));
8739 clutter_actor_queue_relayout (self);
8743 clutter_actor_set_min_height (ClutterActor *self,
8747 ClutterActorPrivate *priv = self->priv;
8748 ClutterActorBox old = { 0, };
8749 ClutterLayoutInfo *info;
8751 /* if we are setting the size on a top-level actor and the
8752 * backend only supports static top-levels (e.g. framebuffers)
8753 * then we ignore the passed value and we override it with
8754 * the stage implementation's preferred size.
8756 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8757 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8760 info = _clutter_actor_get_layout_info (self);
8762 if (priv->min_height_set && min_height == info->min_height)
8765 g_object_freeze_notify (G_OBJECT (self));
8767 clutter_actor_store_old_geometry (self, &old);
8769 info->min_height = min_height;
8770 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8771 clutter_actor_set_min_height_set (self, TRUE);
8773 clutter_actor_notify_if_geometry_changed (self, &old);
8775 g_object_thaw_notify (G_OBJECT (self));
8777 clutter_actor_queue_relayout (self);
8781 clutter_actor_set_natural_width (ClutterActor *self,
8782 gfloat natural_width)
8784 ClutterActorPrivate *priv = self->priv;
8785 ClutterActorBox old = { 0, };
8786 ClutterLayoutInfo *info;
8788 /* if we are setting the size on a top-level actor and the
8789 * backend only supports static top-levels (e.g. framebuffers)
8790 * then we ignore the passed value and we override it with
8791 * the stage implementation's preferred size.
8793 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8794 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8797 info = _clutter_actor_get_layout_info (self);
8799 if (priv->natural_width_set && natural_width == info->natural_width)
8802 g_object_freeze_notify (G_OBJECT (self));
8804 clutter_actor_store_old_geometry (self, &old);
8806 info->natural_width = natural_width;
8807 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8808 clutter_actor_set_natural_width_set (self, TRUE);
8810 clutter_actor_notify_if_geometry_changed (self, &old);
8812 g_object_thaw_notify (G_OBJECT (self));
8814 clutter_actor_queue_relayout (self);
8818 clutter_actor_set_natural_height (ClutterActor *self,
8819 gfloat natural_height)
8821 ClutterActorPrivate *priv = self->priv;
8822 ClutterActorBox old = { 0, };
8823 ClutterLayoutInfo *info;
8825 /* if we are setting the size on a top-level actor and the
8826 * backend only supports static top-levels (e.g. framebuffers)
8827 * then we ignore the passed value and we override it with
8828 * the stage implementation's preferred size.
8830 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8831 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8834 info = _clutter_actor_get_layout_info (self);
8836 if (priv->natural_height_set && natural_height == info->natural_height)
8839 g_object_freeze_notify (G_OBJECT (self));
8841 clutter_actor_store_old_geometry (self, &old);
8843 info->natural_height = natural_height;
8844 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8845 clutter_actor_set_natural_height_set (self, TRUE);
8847 clutter_actor_notify_if_geometry_changed (self, &old);
8849 g_object_thaw_notify (G_OBJECT (self));
8851 clutter_actor_queue_relayout (self);
8855 clutter_actor_set_min_width_set (ClutterActor *self,
8856 gboolean use_min_width)
8858 ClutterActorPrivate *priv = self->priv;
8859 ClutterActorBox old = { 0, };
8861 if (priv->min_width_set == (use_min_width != FALSE))
8864 clutter_actor_store_old_geometry (self, &old);
8866 priv->min_width_set = use_min_width != FALSE;
8867 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8869 clutter_actor_notify_if_geometry_changed (self, &old);
8871 clutter_actor_queue_relayout (self);
8875 clutter_actor_set_min_height_set (ClutterActor *self,
8876 gboolean use_min_height)
8878 ClutterActorPrivate *priv = self->priv;
8879 ClutterActorBox old = { 0, };
8881 if (priv->min_height_set == (use_min_height != FALSE))
8884 clutter_actor_store_old_geometry (self, &old);
8886 priv->min_height_set = use_min_height != FALSE;
8887 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8889 clutter_actor_notify_if_geometry_changed (self, &old);
8891 clutter_actor_queue_relayout (self);
8895 clutter_actor_set_natural_width_set (ClutterActor *self,
8896 gboolean use_natural_width)
8898 ClutterActorPrivate *priv = self->priv;
8899 ClutterActorBox old = { 0, };
8901 if (priv->natural_width_set == (use_natural_width != FALSE))
8904 clutter_actor_store_old_geometry (self, &old);
8906 priv->natural_width_set = use_natural_width != FALSE;
8907 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8909 clutter_actor_notify_if_geometry_changed (self, &old);
8911 clutter_actor_queue_relayout (self);
8915 clutter_actor_set_natural_height_set (ClutterActor *self,
8916 gboolean use_natural_height)
8918 ClutterActorPrivate *priv = self->priv;
8919 ClutterActorBox old = { 0, };
8921 if (priv->natural_height_set == (use_natural_height != FALSE))
8924 clutter_actor_store_old_geometry (self, &old);
8926 priv->natural_height_set = use_natural_height != FALSE;
8927 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8929 clutter_actor_notify_if_geometry_changed (self, &old);
8931 clutter_actor_queue_relayout (self);
8935 * clutter_actor_set_request_mode:
8936 * @self: a #ClutterActor
8937 * @mode: the request mode
8939 * Sets the geometry request mode of @self.
8941 * The @mode determines the order for invoking
8942 * clutter_actor_get_preferred_width() and
8943 * clutter_actor_get_preferred_height()
8948 clutter_actor_set_request_mode (ClutterActor *self,
8949 ClutterRequestMode mode)
8951 ClutterActorPrivate *priv;
8953 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8957 if (priv->request_mode == mode)
8960 priv->request_mode = mode;
8962 priv->needs_width_request = TRUE;
8963 priv->needs_height_request = TRUE;
8965 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8967 clutter_actor_queue_relayout (self);
8971 * clutter_actor_get_request_mode:
8972 * @self: a #ClutterActor
8974 * Retrieves the geometry request mode of @self
8976 * Return value: the request mode for the actor
8981 clutter_actor_get_request_mode (ClutterActor *self)
8983 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8984 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8986 return self->priv->request_mode;
8989 /* variant of set_width() without checks and without notification
8990 * freeze+thaw, for internal usage only
8993 clutter_actor_set_width_internal (ClutterActor *self,
8998 /* the Stage will use the :min-width to control the minimum
8999 * width to be resized to, so we should not be setting it
9000 * along with the :natural-width
9002 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9003 clutter_actor_set_min_width (self, width);
9005 clutter_actor_set_natural_width (self, width);
9009 /* we only unset the :natural-width for the Stage */
9010 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9011 clutter_actor_set_min_width_set (self, FALSE);
9013 clutter_actor_set_natural_width_set (self, FALSE);
9017 /* variant of set_height() without checks and without notification
9018 * freeze+thaw, for internal usage only
9021 clutter_actor_set_height_internal (ClutterActor *self,
9026 /* see the comment above in set_width_internal() */
9027 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9028 clutter_actor_set_min_height (self, height);
9030 clutter_actor_set_natural_height (self, height);
9034 /* see the comment above in set_width_internal() */
9035 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9036 clutter_actor_set_min_height_set (self, FALSE);
9038 clutter_actor_set_natural_height_set (self, FALSE);
9043 * clutter_actor_set_size:
9044 * @self: A #ClutterActor
9045 * @width: New width of actor in pixels, or -1
9046 * @height: New height of actor in pixels, or -1
9048 * Sets the actor's size request in pixels. This overrides any
9049 * "normal" size request the actor would have. For example
9050 * a text actor might normally request the size of the text;
9051 * this function would force a specific size instead.
9053 * If @width and/or @height are -1 the actor will use its
9054 * "normal" size request instead of overriding it, i.e.
9055 * you can "unset" the size with -1.
9057 * This function sets or unsets both the minimum and natural size.
9060 clutter_actor_set_size (ClutterActor *self,
9064 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9066 g_object_freeze_notify (G_OBJECT (self));
9068 clutter_actor_set_width (self, width);
9069 clutter_actor_set_height (self, height);
9071 g_object_thaw_notify (G_OBJECT (self));
9075 * clutter_actor_get_size:
9076 * @self: A #ClutterActor
9077 * @width: (out) (allow-none): return location for the width, or %NULL.
9078 * @height: (out) (allow-none): return location for the height, or %NULL.
9080 * This function tries to "do what you mean" and return
9081 * the size an actor will have. If the actor has a valid
9082 * allocation, the allocation will be returned; otherwise,
9083 * the actors natural size request will be returned.
9085 * If you care whether you get the request vs. the allocation, you
9086 * should probably call a different function like
9087 * clutter_actor_get_allocation_box() or
9088 * clutter_actor_get_preferred_width().
9093 clutter_actor_get_size (ClutterActor *self,
9097 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9100 *width = clutter_actor_get_width (self);
9103 *height = clutter_actor_get_height (self);
9107 * clutter_actor_get_position:
9108 * @self: a #ClutterActor
9109 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9110 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9112 * This function tries to "do what you mean" and tell you where the
9113 * actor is, prior to any transformations. Retrieves the fixed
9114 * position of an actor in pixels, if one has been set; otherwise, if
9115 * the allocation is valid, returns the actor's allocated position;
9116 * otherwise, returns 0,0.
9118 * The returned position is in pixels.
9123 clutter_actor_get_position (ClutterActor *self,
9127 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9130 *x = clutter_actor_get_x (self);
9133 *y = clutter_actor_get_y (self);
9137 * clutter_actor_get_transformed_position:
9138 * @self: A #ClutterActor
9139 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9140 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9142 * Gets the absolute position of an actor, in pixels relative to the stage.
9147 clutter_actor_get_transformed_position (ClutterActor *self,
9154 v1.x = v1.y = v1.z = 0;
9155 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9165 * clutter_actor_get_transformed_size:
9166 * @self: A #ClutterActor
9167 * @width: (out) (allow-none): return location for the width, or %NULL
9168 * @height: (out) (allow-none): return location for the height, or %NULL
9170 * Gets the absolute size of an actor in pixels, taking into account the
9173 * If the actor has a valid allocation, the allocated size will be used.
9174 * If the actor has not a valid allocation then the preferred size will
9175 * be transformed and returned.
9177 * If you want the transformed allocation, see
9178 * clutter_actor_get_abs_allocation_vertices() instead.
9180 * <note>When the actor (or one of its ancestors) is rotated around the
9181 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9182 * as a generic quadrangle; in that case this function returns the size
9183 * of the smallest rectangle that encapsulates the entire quad. Please
9184 * note that in this case no assumptions can be made about the relative
9185 * position of this envelope to the absolute position of the actor, as
9186 * returned by clutter_actor_get_transformed_position(); if you need this
9187 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9188 * to get the coords of the actual quadrangle.</note>
9193 clutter_actor_get_transformed_size (ClutterActor *self,
9197 ClutterActorPrivate *priv;
9199 gfloat x_min, x_max, y_min, y_max;
9202 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9206 /* if the actor hasn't been allocated yet, get the preferred
9207 * size and transform that
9209 if (priv->needs_allocation)
9211 gfloat natural_width, natural_height;
9212 ClutterActorBox box;
9214 /* Make a fake allocation to transform.
9216 * NB: _clutter_actor_transform_and_project_box expects a box in
9217 * the actor's coordinate space... */
9222 natural_width = natural_height = 0;
9223 clutter_actor_get_preferred_size (self, NULL, NULL,
9227 box.x2 = natural_width;
9228 box.y2 = natural_height;
9230 _clutter_actor_transform_and_project_box (self, &box, v);
9233 clutter_actor_get_abs_allocation_vertices (self, v);
9235 x_min = x_max = v[0].x;
9236 y_min = y_max = v[0].y;
9238 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9254 *width = x_max - x_min;
9257 *height = y_max - y_min;
9261 * clutter_actor_get_width:
9262 * @self: A #ClutterActor
9264 * Retrieves the width of a #ClutterActor.
9266 * If the actor has a valid allocation, this function will return the
9267 * width of the allocated area given to the actor.
9269 * If the actor does not have a valid allocation, this function will
9270 * return the actor's natural width, that is the preferred width of
9273 * If you care whether you get the preferred width or the width that
9274 * has been assigned to the actor, you should probably call a different
9275 * function like clutter_actor_get_allocation_box() to retrieve the
9276 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9279 * If an actor has a fixed width, for instance a width that has been
9280 * assigned using clutter_actor_set_width(), the width returned will
9281 * be the same value.
9283 * Return value: the width of the actor, in pixels
9286 clutter_actor_get_width (ClutterActor *self)
9288 ClutterActorPrivate *priv;
9290 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9294 if (priv->needs_allocation)
9296 gfloat natural_width = 0;
9298 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9299 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9302 gfloat natural_height = 0;
9304 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9305 clutter_actor_get_preferred_width (self, natural_height,
9310 return natural_width;
9313 return priv->allocation.x2 - priv->allocation.x1;
9317 * clutter_actor_get_height:
9318 * @self: A #ClutterActor
9320 * Retrieves the height of a #ClutterActor.
9322 * If the actor has a valid allocation, this function will return the
9323 * height of the allocated area given to the actor.
9325 * If the actor does not have a valid allocation, this function will
9326 * return the actor's natural height, that is the preferred height of
9329 * If you care whether you get the preferred height or the height that
9330 * has been assigned to the actor, you should probably call a different
9331 * function like clutter_actor_get_allocation_box() to retrieve the
9332 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9335 * If an actor has a fixed height, for instance a height that has been
9336 * assigned using clutter_actor_set_height(), the height returned will
9337 * be the same value.
9339 * Return value: the height of the actor, in pixels
9342 clutter_actor_get_height (ClutterActor *self)
9344 ClutterActorPrivate *priv;
9346 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9350 if (priv->needs_allocation)
9352 gfloat natural_height = 0;
9354 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9356 gfloat natural_width = 0;
9358 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9359 clutter_actor_get_preferred_height (self, natural_width,
9360 NULL, &natural_height);
9363 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9365 return natural_height;
9368 return priv->allocation.y2 - priv->allocation.y1;
9372 * clutter_actor_set_width:
9373 * @self: A #ClutterActor
9374 * @width: Requested new width for the actor, in pixels, or -1
9376 * Forces a width on an actor, causing the actor's preferred width
9377 * and height (if any) to be ignored.
9379 * If @width is -1 the actor will use its preferred width request
9380 * instead of overriding it, i.e. you can "unset" the width with -1.
9382 * This function sets both the minimum and natural size of the actor.
9387 clutter_actor_set_width (ClutterActor *self,
9390 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9392 if (clutter_actor_get_easing_duration (self) != 0)
9394 ClutterTransition *transition;
9396 transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9397 if (transition == NULL)
9399 float old_width = clutter_actor_get_width (self);
9401 transition = _clutter_actor_create_transition (self,
9402 obj_props[PROP_WIDTH],
9407 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9409 clutter_actor_queue_relayout (self);
9413 g_object_freeze_notify (G_OBJECT (self));
9415 clutter_actor_set_width_internal (self, width);
9417 g_object_thaw_notify (G_OBJECT (self));
9422 * clutter_actor_set_height:
9423 * @self: A #ClutterActor
9424 * @height: Requested new height for the actor, in pixels, or -1
9426 * Forces a height on an actor, causing the actor's preferred width
9427 * and height (if any) to be ignored.
9429 * If @height is -1 the actor will use its preferred height instead of
9430 * overriding it, i.e. you can "unset" the height with -1.
9432 * This function sets both the minimum and natural size of the actor.
9437 clutter_actor_set_height (ClutterActor *self,
9440 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9442 if (clutter_actor_get_easing_duration (self) != 0)
9444 ClutterTransition *transition;
9446 transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9447 if (transition == NULL)
9449 float old_height = clutter_actor_get_height (self);
9451 transition = _clutter_actor_create_transition (self,
9452 obj_props[PROP_HEIGHT],
9457 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9459 clutter_actor_queue_relayout (self);
9463 g_object_freeze_notify (G_OBJECT (self));
9465 clutter_actor_set_height_internal (self, height);
9467 g_object_thaw_notify (G_OBJECT (self));
9472 clutter_actor_set_x_internal (ClutterActor *self,
9475 ClutterActorPrivate *priv = self->priv;
9476 ClutterLayoutInfo *linfo;
9477 ClutterActorBox old = { 0, };
9479 linfo = _clutter_actor_get_layout_info (self);
9481 if (priv->position_set && linfo->fixed_x == x)
9484 clutter_actor_store_old_geometry (self, &old);
9487 clutter_actor_set_fixed_position_set (self, TRUE);
9489 clutter_actor_notify_if_geometry_changed (self, &old);
9491 clutter_actor_queue_relayout (self);
9495 clutter_actor_set_y_internal (ClutterActor *self,
9498 ClutterActorPrivate *priv = self->priv;
9499 ClutterLayoutInfo *linfo;
9500 ClutterActorBox old = { 0, };
9502 linfo = _clutter_actor_get_layout_info (self);
9504 if (priv->position_set && linfo->fixed_y == y)
9507 clutter_actor_store_old_geometry (self, &old);
9510 clutter_actor_set_fixed_position_set (self, TRUE);
9512 clutter_actor_notify_if_geometry_changed (self, &old);
9514 clutter_actor_queue_relayout (self);
9518 * clutter_actor_set_x:
9519 * @self: a #ClutterActor
9520 * @x: the actor's position on the X axis
9522 * Sets the actor's X coordinate, relative to its parent, in pixels.
9524 * Overrides any layout manager and forces a fixed position for
9527 * The #ClutterActor:x property is animatable.
9532 clutter_actor_set_x (ClutterActor *self,
9535 const ClutterLayoutInfo *linfo;
9537 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9539 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9541 if (clutter_actor_get_easing_duration (self) != 0)
9543 ClutterTransition *transition;
9545 transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9546 if (transition == NULL)
9548 transition = _clutter_actor_create_transition (self,
9554 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9556 clutter_actor_queue_relayout (self);
9559 clutter_actor_set_x_internal (self, x);
9563 * clutter_actor_set_y:
9564 * @self: a #ClutterActor
9565 * @y: the actor's position on the Y axis
9567 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9569 * Overrides any layout manager and forces a fixed position for
9572 * The #ClutterActor:y property is animatable.
9577 clutter_actor_set_y (ClutterActor *self,
9580 const ClutterLayoutInfo *linfo;
9582 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9584 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9586 if (clutter_actor_get_easing_duration (self) != 0)
9588 ClutterTransition *transition;
9590 transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9591 if (transition == NULL)
9593 transition = _clutter_actor_create_transition (self,
9599 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9601 clutter_actor_queue_relayout (self);
9604 clutter_actor_set_y_internal (self, y);
9606 clutter_actor_queue_relayout (self);
9610 * clutter_actor_get_x:
9611 * @self: A #ClutterActor
9613 * Retrieves the X coordinate of a #ClutterActor.
9615 * This function tries to "do what you mean", by returning the
9616 * correct value depending on the actor's state.
9618 * If the actor has a valid allocation, this function will return
9619 * the X coordinate of the origin of the allocation box.
9621 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9622 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9623 * function will return that coordinate.
9625 * If both the allocation and a fixed position are missing, this function
9628 * Return value: the X coordinate, in pixels, ignoring any
9629 * transformation (i.e. scaling, rotation)
9632 clutter_actor_get_x (ClutterActor *self)
9634 ClutterActorPrivate *priv;
9636 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9640 if (priv->needs_allocation)
9642 if (priv->position_set)
9644 const ClutterLayoutInfo *info;
9646 info = _clutter_actor_get_layout_info_or_defaults (self);
9648 return info->fixed_x;
9654 return priv->allocation.x1;
9658 * clutter_actor_get_y:
9659 * @self: A #ClutterActor
9661 * Retrieves the Y coordinate of a #ClutterActor.
9663 * This function tries to "do what you mean", by returning the
9664 * correct value depending on the actor's state.
9666 * If the actor has a valid allocation, this function will return
9667 * the Y coordinate of the origin of the allocation box.
9669 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9670 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9671 * function will return that coordinate.
9673 * If both the allocation and a fixed position are missing, this function
9676 * Return value: the Y coordinate, in pixels, ignoring any
9677 * transformation (i.e. scaling, rotation)
9680 clutter_actor_get_y (ClutterActor *self)
9682 ClutterActorPrivate *priv;
9684 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9688 if (priv->needs_allocation)
9690 if (priv->position_set)
9692 const ClutterLayoutInfo *info;
9694 info = _clutter_actor_get_layout_info_or_defaults (self);
9696 return info->fixed_y;
9702 return priv->allocation.y1;
9706 * clutter_actor_set_scale:
9707 * @self: A #ClutterActor
9708 * @scale_x: double factor to scale actor by horizontally.
9709 * @scale_y: double factor to scale actor by vertically.
9711 * Scales an actor with the given factors. The scaling is relative to
9712 * the scale center and the anchor point. The scale center is
9713 * unchanged by this function and defaults to 0,0.
9715 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9721 clutter_actor_set_scale (ClutterActor *self,
9725 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9727 g_object_freeze_notify (G_OBJECT (self));
9729 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9730 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9732 g_object_thaw_notify (G_OBJECT (self));
9736 * clutter_actor_set_scale_full:
9737 * @self: A #ClutterActor
9738 * @scale_x: double factor to scale actor by horizontally.
9739 * @scale_y: double factor to scale actor by vertically.
9740 * @center_x: X coordinate of the center of the scale.
9741 * @center_y: Y coordinate of the center of the scale
9743 * Scales an actor with the given factors around the given center
9744 * point. The center point is specified in pixels relative to the
9745 * anchor point (usually the top left corner of the actor).
9747 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9753 clutter_actor_set_scale_full (ClutterActor *self,
9759 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9761 g_object_freeze_notify (G_OBJECT (self));
9763 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9764 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9765 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9766 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9768 g_object_thaw_notify (G_OBJECT (self));
9772 * clutter_actor_set_scale_with_gravity:
9773 * @self: A #ClutterActor
9774 * @scale_x: double factor to scale actor by horizontally.
9775 * @scale_y: double factor to scale actor by vertically.
9776 * @gravity: the location of the scale center expressed as a compass
9779 * Scales an actor with the given factors around the given
9780 * center point. The center point is specified as one of the compass
9781 * directions in #ClutterGravity. For example, setting it to north
9782 * will cause the top of the actor to remain unchanged and the rest of
9783 * the actor to expand left, right and downwards.
9785 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9791 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9794 ClutterGravity gravity)
9796 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9798 g_object_freeze_notify (G_OBJECT (self));
9800 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9801 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9802 clutter_actor_set_scale_gravity (self, gravity);
9804 g_object_thaw_notify (G_OBJECT (self));
9808 * clutter_actor_get_scale:
9809 * @self: A #ClutterActor
9810 * @scale_x: (out) (allow-none): Location to store horizonal
9811 * scale factor, or %NULL.
9812 * @scale_y: (out) (allow-none): Location to store vertical
9813 * scale factor, or %NULL.
9815 * Retrieves an actors scale factors.
9820 clutter_actor_get_scale (ClutterActor *self,
9824 const ClutterTransformInfo *info;
9826 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9828 info = _clutter_actor_get_transform_info_or_defaults (self);
9831 *scale_x = info->scale_x;
9834 *scale_y = info->scale_y;
9838 * clutter_actor_get_scale_center:
9839 * @self: A #ClutterActor
9840 * @center_x: (out) (allow-none): Location to store the X position
9841 * of the scale center, or %NULL.
9842 * @center_y: (out) (allow-none): Location to store the Y position
9843 * of the scale center, or %NULL.
9845 * Retrieves the scale center coordinate in pixels relative to the top
9846 * left corner of the actor. If the scale center was specified using a
9847 * #ClutterGravity this will calculate the pixel offset using the
9848 * current size of the actor.
9853 clutter_actor_get_scale_center (ClutterActor *self,
9857 const ClutterTransformInfo *info;
9859 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9861 info = _clutter_actor_get_transform_info_or_defaults (self);
9863 clutter_anchor_coord_get_units (self, &info->scale_center,
9870 * clutter_actor_get_scale_gravity:
9871 * @self: A #ClutterActor
9873 * Retrieves the scale center as a compass direction. If the scale
9874 * center was specified in pixels or units this will return
9875 * %CLUTTER_GRAVITY_NONE.
9877 * Return value: the scale gravity
9882 clutter_actor_get_scale_gravity (ClutterActor *self)
9884 const ClutterTransformInfo *info;
9886 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9888 info = _clutter_actor_get_transform_info_or_defaults (self);
9890 return clutter_anchor_coord_get_gravity (&info->scale_center);
9894 clutter_actor_set_opacity_internal (ClutterActor *self,
9897 ClutterActorPrivate *priv = self->priv;
9899 if (priv->opacity != opacity)
9901 priv->opacity = opacity;
9903 /* Queue a redraw from the flatten effect so that it can use
9904 its cached image if available instead of having to redraw the
9905 actual actor. If it doesn't end up using the FBO then the
9906 effect is still able to continue the paint anyway. If there
9907 is no flatten effect yet then this is equivalent to queueing
9909 _clutter_actor_queue_redraw_full (self,
9912 priv->flatten_effect);
9914 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9919 * clutter_actor_set_opacity:
9920 * @self: A #ClutterActor
9921 * @opacity: New opacity value for the actor.
9923 * Sets the actor's opacity, with zero being completely transparent and
9924 * 255 (0xff) being fully opaque.
9926 * The #ClutterActor:opacity property is animatable.
9929 clutter_actor_set_opacity (ClutterActor *self,
9932 ClutterActorPrivate *priv;
9934 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9938 if (clutter_actor_get_easing_duration (self) != 0)
9940 ClutterTransition *transition;
9942 transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9943 if (transition == NULL)
9945 transition = _clutter_actor_create_transition (self,
9946 obj_props[PROP_OPACITY],
9951 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9953 clutter_actor_queue_redraw (self);
9956 clutter_actor_set_opacity_internal (self, opacity);
9960 * clutter_actor_get_paint_opacity_internal:
9961 * @self: a #ClutterActor
9963 * Retrieves the absolute opacity of the actor, as it appears on the stage
9965 * This function does not do type checks
9967 * Return value: the absolute opacity of the actor
9970 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9972 ClutterActorPrivate *priv = self->priv;
9973 ClutterActor *parent;
9975 /* override the top-level opacity to always be 255; even in
9976 * case of ClutterStage:use-alpha being TRUE we want the rest
9977 * of the scene to be painted
9979 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9982 if (priv->opacity_override >= 0)
9983 return priv->opacity_override;
9985 parent = priv->parent;
9987 /* Factor in the actual actors opacity with parents */
9990 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9992 if (opacity != 0xff)
9993 return (opacity * priv->opacity) / 0xff;
9996 return priv->opacity;
10001 * clutter_actor_get_paint_opacity:
10002 * @self: A #ClutterActor
10004 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10006 * This function traverses the hierarchy chain and composites the opacity of
10007 * the actor with that of its parents.
10009 * This function is intended for subclasses to use in the paint virtual
10010 * function, to paint themselves with the correct opacity.
10012 * Return value: The actor opacity value.
10017 clutter_actor_get_paint_opacity (ClutterActor *self)
10019 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10021 return clutter_actor_get_paint_opacity_internal (self);
10025 * clutter_actor_get_opacity:
10026 * @self: a #ClutterActor
10028 * Retrieves the opacity value of an actor, as set by
10029 * clutter_actor_set_opacity().
10031 * For retrieving the absolute opacity of the actor inside a paint
10032 * virtual function, see clutter_actor_get_paint_opacity().
10034 * Return value: the opacity of the actor
10037 clutter_actor_get_opacity (ClutterActor *self)
10039 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10041 return self->priv->opacity;
10045 * clutter_actor_set_offscreen_redirect:
10046 * @self: A #ClutterActor
10047 * @redirect: New offscreen redirect flags for the actor.
10049 * Defines the circumstances where the actor should be redirected into
10050 * an offscreen image. The offscreen image is used to flatten the
10051 * actor into a single image while painting for two main reasons.
10052 * Firstly, when the actor is painted a second time without any of its
10053 * contents changing it can simply repaint the cached image without
10054 * descending further down the actor hierarchy. Secondly, it will make
10055 * the opacity look correct even if there are overlapping primitives
10058 * Caching the actor could in some cases be a performance win and in
10059 * some cases be a performance lose so it is important to determine
10060 * which value is right for an actor before modifying this value. For
10061 * example, there is never any reason to flatten an actor that is just
10062 * a single texture (such as a #ClutterTexture) because it is
10063 * effectively already cached in an image so the offscreen would be
10064 * redundant. Also if the actor contains primitives that are far apart
10065 * with a large transparent area in the middle (such as a large
10066 * CluterGroup with a small actor in the top left and a small actor in
10067 * the bottom right) then the cached image will contain the entire
10068 * image of the large area and the paint will waste time blending all
10069 * of the transparent pixels in the middle.
10071 * The default method of implementing opacity on a container simply
10072 * forwards on the opacity to all of the children. If the children are
10073 * overlapping then it will appear as if they are two separate glassy
10074 * objects and there will be a break in the color where they
10075 * overlap. By redirecting to an offscreen buffer it will be as if the
10076 * two opaque objects are combined into one and then made transparent
10077 * which is usually what is expected.
10079 * The image below demonstrates the difference between redirecting and
10080 * not. The image shows two Clutter groups, each containing a red and
10081 * a green rectangle which overlap. The opacity on the group is set to
10082 * 128 (which is 50%). When the offscreen redirect is not used, the
10083 * red rectangle can be seen through the blue rectangle as if the two
10084 * rectangles were separately transparent. When the redirect is used
10085 * the group as a whole is transparent instead so the red rectangle is
10086 * not visible where they overlap.
10088 * <figure id="offscreen-redirect">
10089 * <title>Sample of using an offscreen redirect for transparency</title>
10090 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10093 * The default value for this property is 0, so we effectively will
10094 * never redirect an actor offscreen by default. This means that there
10095 * are times that transparent actors may look glassy as described
10096 * above. The reason this is the default is because there is a
10097 * performance trade off between quality and performance here. In many
10098 * cases the default form of glassy opacity looks good enough, but if
10099 * it's not you will need to set the
10100 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10101 * redirection for opacity.
10103 * Custom actors that don't contain any overlapping primitives are
10104 * recommended to override the has_overlaps() virtual to return %FALSE
10105 * for maximum efficiency.
10110 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10111 ClutterOffscreenRedirect redirect)
10113 ClutterActorPrivate *priv;
10115 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10119 if (priv->offscreen_redirect != redirect)
10121 priv->offscreen_redirect = redirect;
10123 /* Queue a redraw from the effect so that it can use its cached
10124 image if available instead of having to redraw the actual
10125 actor. If it doesn't end up using the FBO then the effect is
10126 still able to continue the paint anyway. If there is no
10127 effect then this is equivalent to queuing a full redraw */
10128 _clutter_actor_queue_redraw_full (self,
10131 priv->flatten_effect);
10133 g_object_notify_by_pspec (G_OBJECT (self),
10134 obj_props[PROP_OFFSCREEN_REDIRECT]);
10139 * clutter_actor_get_offscreen_redirect:
10140 * @self: a #ClutterActor
10142 * Retrieves whether to redirect the actor to an offscreen buffer, as
10143 * set by clutter_actor_set_offscreen_redirect().
10145 * Return value: the value of the offscreen-redirect property of the actor
10149 ClutterOffscreenRedirect
10150 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10152 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10154 return self->priv->offscreen_redirect;
10158 * clutter_actor_set_name:
10159 * @self: A #ClutterActor
10160 * @name: Textual tag to apply to actor
10162 * Sets the given name to @self. The name can be used to identify
10166 clutter_actor_set_name (ClutterActor *self,
10169 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10171 g_free (self->priv->name);
10172 self->priv->name = g_strdup (name);
10174 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10178 * clutter_actor_get_name:
10179 * @self: A #ClutterActor
10181 * Retrieves the name of @self.
10183 * Return value: the name of the actor, or %NULL. The returned string is
10184 * owned by the actor and should not be modified or freed.
10187 clutter_actor_get_name (ClutterActor *self)
10189 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10191 return self->priv->name;
10195 * clutter_actor_get_gid:
10196 * @self: A #ClutterActor
10198 * Retrieves the unique id for @self.
10200 * Return value: Globally unique value for this object instance.
10204 * Deprecated: 1.8: The id is not used any longer.
10207 clutter_actor_get_gid (ClutterActor *self)
10209 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10211 return self->priv->id;
10215 clutter_actor_set_depth_internal (ClutterActor *self,
10218 ClutterTransformInfo *info;
10220 info = _clutter_actor_get_transform_info (self);
10222 if (info->depth != depth)
10224 /* Sets Z value - XXX 2.0: should we invert? */
10225 info->depth = depth;
10227 self->priv->transform_valid = FALSE;
10229 /* FIXME - remove this crap; sadly, there are still containers
10230 * in Clutter that depend on this utter brain damage
10232 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10234 clutter_actor_queue_redraw (self);
10236 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10241 * clutter_actor_set_depth:
10242 * @self: a #ClutterActor
10245 * Sets the Z coordinate of @self to @depth.
10247 * The unit used by @depth is dependant on the perspective setup. See
10248 * also clutter_stage_set_perspective().
10251 clutter_actor_set_depth (ClutterActor *self,
10254 const ClutterTransformInfo *tinfo;
10256 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10258 tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10260 if (clutter_actor_get_easing_duration (self) != 0)
10262 ClutterTransition *transition;
10264 transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10265 if (transition == NULL)
10267 transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10272 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10274 clutter_actor_queue_redraw (self);
10277 clutter_actor_set_depth_internal (self, depth);
10281 * clutter_actor_get_depth:
10282 * @self: a #ClutterActor
10284 * Retrieves the depth of @self.
10286 * Return value: the depth of the actor
10289 clutter_actor_get_depth (ClutterActor *self)
10291 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10293 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10297 * clutter_actor_set_rotation:
10298 * @self: a #ClutterActor
10299 * @axis: the axis of rotation
10300 * @angle: the angle of rotation
10301 * @x: X coordinate of the rotation center
10302 * @y: Y coordinate of the rotation center
10303 * @z: Z coordinate of the rotation center
10305 * Sets the rotation angle of @self around the given axis.
10307 * The rotation center coordinates used depend on the value of @axis:
10309 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10310 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10311 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10314 * The rotation coordinates are relative to the anchor point of the
10315 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10316 * point is set, the upper left corner is assumed as the origin.
10321 clutter_actor_set_rotation (ClutterActor *self,
10322 ClutterRotateAxis axis,
10330 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10336 g_object_freeze_notify (G_OBJECT (self));
10338 clutter_actor_set_rotation_angle (self, axis, angle);
10339 clutter_actor_set_rotation_center_internal (self, axis, &v);
10341 g_object_thaw_notify (G_OBJECT (self));
10345 * clutter_actor_set_z_rotation_from_gravity:
10346 * @self: a #ClutterActor
10347 * @angle: the angle of rotation
10348 * @gravity: the center point of the rotation
10350 * Sets the rotation angle of @self around the Z axis using the center
10351 * point specified as a compass point. For example to rotate such that
10352 * the center of the actor remains static you can use
10353 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10354 * will move accordingly.
10359 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10361 ClutterGravity gravity)
10363 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10365 if (gravity == CLUTTER_GRAVITY_NONE)
10366 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10369 GObject *obj = G_OBJECT (self);
10370 ClutterTransformInfo *info;
10372 info = _clutter_actor_get_transform_info (self);
10374 g_object_freeze_notify (obj);
10376 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10378 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10379 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10380 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10382 g_object_thaw_notify (obj);
10387 * clutter_actor_get_rotation:
10388 * @self: a #ClutterActor
10389 * @axis: the axis of rotation
10390 * @x: (out): return value for the X coordinate of the center of rotation
10391 * @y: (out): return value for the Y coordinate of the center of rotation
10392 * @z: (out): return value for the Z coordinate of the center of rotation
10394 * Retrieves the angle and center of rotation on the given axis,
10395 * set using clutter_actor_set_rotation().
10397 * Return value: the angle of rotation
10402 clutter_actor_get_rotation (ClutterActor *self,
10403 ClutterRotateAxis axis,
10408 const ClutterTransformInfo *info;
10409 const AnchorCoord *anchor_coord;
10410 gdouble retval = 0;
10412 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10414 info = _clutter_actor_get_transform_info_or_defaults (self);
10418 case CLUTTER_X_AXIS:
10419 anchor_coord = &info->rx_center;
10420 retval = info->rx_angle;
10423 case CLUTTER_Y_AXIS:
10424 anchor_coord = &info->ry_center;
10425 retval = info->ry_angle;
10428 case CLUTTER_Z_AXIS:
10429 anchor_coord = &info->rz_center;
10430 retval = info->rz_angle;
10434 anchor_coord = NULL;
10439 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10445 * clutter_actor_get_z_rotation_gravity:
10446 * @self: A #ClutterActor
10448 * Retrieves the center for the rotation around the Z axis as a
10449 * compass direction. If the center was specified in pixels or units
10450 * this will return %CLUTTER_GRAVITY_NONE.
10452 * Return value: the Z rotation center
10457 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10459 const ClutterTransformInfo *info;
10461 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10463 info = _clutter_actor_get_transform_info_or_defaults (self);
10465 return clutter_anchor_coord_get_gravity (&info->rz_center);
10469 * clutter_actor_set_clip:
10470 * @self: A #ClutterActor
10471 * @xoff: X offset of the clip rectangle
10472 * @yoff: Y offset of the clip rectangle
10473 * @width: Width of the clip rectangle
10474 * @height: Height of the clip rectangle
10476 * Sets clip area for @self. The clip area is always computed from the
10477 * upper left corner of the actor, even if the anchor point is set
10483 clutter_actor_set_clip (ClutterActor *self,
10489 ClutterActorPrivate *priv;
10491 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10495 if (priv->has_clip &&
10496 priv->clip.x == xoff &&
10497 priv->clip.y == yoff &&
10498 priv->clip.width == width &&
10499 priv->clip.height == height)
10502 priv->clip.x = xoff;
10503 priv->clip.y = yoff;
10504 priv->clip.width = width;
10505 priv->clip.height = height;
10507 priv->has_clip = TRUE;
10509 clutter_actor_queue_redraw (self);
10511 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10512 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10516 * clutter_actor_remove_clip:
10517 * @self: A #ClutterActor
10519 * Removes clip area from @self.
10522 clutter_actor_remove_clip (ClutterActor *self)
10524 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10526 if (!self->priv->has_clip)
10529 self->priv->has_clip = FALSE;
10531 clutter_actor_queue_redraw (self);
10533 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10537 * clutter_actor_has_clip:
10538 * @self: a #ClutterActor
10540 * Determines whether the actor has a clip area set or not.
10542 * Return value: %TRUE if the actor has a clip area set.
10547 clutter_actor_has_clip (ClutterActor *self)
10549 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10551 return self->priv->has_clip;
10555 * clutter_actor_get_clip:
10556 * @self: a #ClutterActor
10557 * @xoff: (out) (allow-none): return location for the X offset of
10558 * the clip rectangle, or %NULL
10559 * @yoff: (out) (allow-none): return location for the Y offset of
10560 * the clip rectangle, or %NULL
10561 * @width: (out) (allow-none): return location for the width of
10562 * the clip rectangle, or %NULL
10563 * @height: (out) (allow-none): return location for the height of
10564 * the clip rectangle, or %NULL
10566 * Gets the clip area for @self, if any is set
10571 clutter_actor_get_clip (ClutterActor *self,
10577 ClutterActorPrivate *priv;
10579 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10583 if (!priv->has_clip)
10587 *xoff = priv->clip.x;
10590 *yoff = priv->clip.y;
10593 *width = priv->clip.width;
10595 if (height != NULL)
10596 *height = priv->clip.height;
10600 * clutter_actor_get_children:
10601 * @self: a #ClutterActor
10603 * Retrieves the list of children of @self.
10605 * Return value: (transfer container) (element-type ClutterActor): A newly
10606 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10612 clutter_actor_get_children (ClutterActor *self)
10614 ClutterActor *iter;
10617 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10619 /* we walk the list backward so that we can use prepend(),
10622 for (iter = self->priv->last_child, res = NULL;
10624 iter = iter->priv->prev_sibling)
10626 res = g_list_prepend (res, iter);
10633 * insert_child_at_depth:
10634 * @self: a #ClutterActor
10635 * @child: a #ClutterActor
10637 * Inserts @child inside the list of children held by @self, using
10638 * the depth as the insertion criteria.
10640 * This sadly makes the insertion not O(1), but we can keep the
10641 * list sorted so that the painters algorithm we use for painting
10642 * the children will work correctly.
10645 insert_child_at_depth (ClutterActor *self,
10646 ClutterActor *child,
10647 gpointer dummy G_GNUC_UNUSED)
10649 ClutterActor *iter;
10652 child->priv->parent = self;
10655 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10657 /* special-case the first child */
10658 if (self->priv->n_children == 0)
10660 self->priv->first_child = child;
10661 self->priv->last_child = child;
10663 child->priv->next_sibling = NULL;
10664 child->priv->prev_sibling = NULL;
10669 /* Find the right place to insert the child so that it will still be
10670 sorted and the child will be after all of the actors at the same
10672 for (iter = self->priv->first_child;
10674 iter = iter->priv->next_sibling)
10679 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10681 if (iter_depth > child_depth)
10687 ClutterActor *tmp = iter->priv->prev_sibling;
10690 tmp->priv->next_sibling = child;
10692 /* Insert the node before the found one */
10693 child->priv->prev_sibling = iter->priv->prev_sibling;
10694 child->priv->next_sibling = iter;
10695 iter->priv->prev_sibling = child;
10699 ClutterActor *tmp = self->priv->last_child;
10702 tmp->priv->next_sibling = child;
10704 /* insert the node at the end of the list */
10705 child->priv->prev_sibling = self->priv->last_child;
10706 child->priv->next_sibling = NULL;
10709 if (child->priv->prev_sibling == NULL)
10710 self->priv->first_child = child;
10712 if (child->priv->next_sibling == NULL)
10713 self->priv->last_child = child;
10717 insert_child_at_index (ClutterActor *self,
10718 ClutterActor *child,
10721 gint index_ = GPOINTER_TO_INT (data_);
10723 child->priv->parent = self;
10727 ClutterActor *tmp = self->priv->first_child;
10730 tmp->priv->prev_sibling = child;
10732 child->priv->prev_sibling = NULL;
10733 child->priv->next_sibling = tmp;
10735 else if (index_ < 0 || index_ >= self->priv->n_children)
10737 ClutterActor *tmp = self->priv->last_child;
10740 tmp->priv->next_sibling = child;
10742 child->priv->prev_sibling = tmp;
10743 child->priv->next_sibling = NULL;
10747 ClutterActor *iter;
10750 for (iter = self->priv->first_child, i = 0;
10752 iter = iter->priv->next_sibling, i += 1)
10756 ClutterActor *tmp = iter->priv->prev_sibling;
10758 child->priv->prev_sibling = tmp;
10759 child->priv->next_sibling = iter;
10761 iter->priv->prev_sibling = child;
10764 tmp->priv->next_sibling = child;
10771 if (child->priv->prev_sibling == NULL)
10772 self->priv->first_child = child;
10774 if (child->priv->next_sibling == NULL)
10775 self->priv->last_child = child;
10779 insert_child_above (ClutterActor *self,
10780 ClutterActor *child,
10783 ClutterActor *sibling = data;
10785 child->priv->parent = self;
10787 if (sibling == NULL)
10788 sibling = self->priv->last_child;
10790 child->priv->prev_sibling = sibling;
10792 if (sibling != NULL)
10794 ClutterActor *tmp = sibling->priv->next_sibling;
10796 child->priv->next_sibling = tmp;
10799 tmp->priv->prev_sibling = child;
10801 sibling->priv->next_sibling = child;
10804 child->priv->next_sibling = NULL;
10806 if (child->priv->prev_sibling == NULL)
10807 self->priv->first_child = child;
10809 if (child->priv->next_sibling == NULL)
10810 self->priv->last_child = child;
10814 insert_child_below (ClutterActor *self,
10815 ClutterActor *child,
10818 ClutterActor *sibling = data;
10820 child->priv->parent = self;
10822 if (sibling == NULL)
10823 sibling = self->priv->first_child;
10825 child->priv->next_sibling = sibling;
10827 if (sibling != NULL)
10829 ClutterActor *tmp = sibling->priv->prev_sibling;
10831 child->priv->prev_sibling = tmp;
10834 tmp->priv->next_sibling = child;
10836 sibling->priv->prev_sibling = child;
10839 child->priv->prev_sibling = NULL;
10841 if (child->priv->prev_sibling == NULL)
10842 self->priv->first_child = child;
10844 if (child->priv->next_sibling == NULL)
10845 self->priv->last_child = child;
10848 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10849 ClutterActor *child,
10853 ADD_CHILD_CREATE_META = 1 << 0,
10854 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10855 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10856 ADD_CHILD_CHECK_STATE = 1 << 3,
10857 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10859 /* default flags for public API */
10860 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10861 ADD_CHILD_EMIT_PARENT_SET |
10862 ADD_CHILD_EMIT_ACTOR_ADDED |
10863 ADD_CHILD_CHECK_STATE |
10864 ADD_CHILD_NOTIFY_FIRST_LAST,
10866 /* flags for legacy/deprecated API */
10867 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10868 ADD_CHILD_CHECK_STATE |
10869 ADD_CHILD_NOTIFY_FIRST_LAST
10870 } ClutterActorAddChildFlags;
10873 * clutter_actor_add_child_internal:
10874 * @self: a #ClutterActor
10875 * @child: a #ClutterActor
10876 * @flags: control flags for actions
10877 * @add_func: delegate function
10878 * @data: (closure): data to pass to @add_func
10880 * Adds @child to the list of children of @self.
10882 * The actual insertion inside the list is delegated to @add_func: this
10883 * function will just set up the state, perform basic checks, and emit
10886 * The @flags argument is used to perform additional operations.
10889 clutter_actor_add_child_internal (ClutterActor *self,
10890 ClutterActor *child,
10891 ClutterActorAddChildFlags flags,
10892 ClutterActorAddChildFunc add_func,
10895 ClutterTextDirection text_dir;
10896 gboolean create_meta;
10897 gboolean emit_parent_set, emit_actor_added;
10898 gboolean check_state;
10899 gboolean notify_first_last;
10900 ClutterActor *old_first_child, *old_last_child;
10902 if (child->priv->parent != NULL)
10904 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10905 "use clutter_actor_remove_child() first.",
10906 _clutter_actor_get_debug_name (child),
10907 _clutter_actor_get_debug_name (child->priv->parent));
10911 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10913 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10914 "a child of another actor.",
10915 _clutter_actor_get_debug_name (child));
10920 /* XXX - this check disallows calling methods that change the stacking
10921 * order within the destruction sequence, by triggering a critical
10922 * warning first, and leaving the actor in an undefined state, which
10923 * then ends up being caught by an assertion.
10925 * the reproducible sequence is:
10927 * - actor gets destroyed;
10928 * - another actor, linked to the first, will try to change the
10929 * stacking order of the first actor;
10930 * - changing the stacking order is a composite operation composed
10931 * by the following steps:
10932 * 1. ref() the child;
10933 * 2. remove_child_internal(), which removes the reference;
10934 * 3. add_child_internal(), which adds a reference;
10935 * - the state of the actor is not changed between (2) and (3), as
10936 * it could be an expensive recomputation;
10937 * - if (3) bails out, then the actor is in an undefined state, but
10939 * - the destruction sequence terminates, but the actor is unparented
10940 * while its state indicates being parented instead.
10941 * - assertion failure.
10943 * the obvious fix would be to decompose each set_child_*_sibling()
10944 * method into proper remove_child()/add_child(), with state validation;
10945 * this may cause excessive work, though, and trigger a cascade of other
10946 * bugs in code that assumes that a change in the stacking order is an
10947 * atomic operation.
10949 * another potential fix is to just remove this check here, and let
10950 * code doing stacking order changes inside the destruction sequence
10951 * of an actor continue doing the work.
10953 * the third fix is to silently bail out early from every
10954 * set_child_*_sibling() and set_child_at_index() method, and avoid
10957 * I have a preference for the second solution, since it involves the
10958 * least amount of work, and the least amount of code duplication.
10960 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10962 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10964 g_warning ("The actor '%s' is currently being destroyed, and "
10965 "cannot be added as a child of another actor.",
10966 _clutter_actor_get_debug_name (child));
10971 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10972 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10973 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10974 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10975 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10977 old_first_child = self->priv->first_child;
10978 old_last_child = self->priv->last_child;
10980 g_object_freeze_notify (G_OBJECT (self));
10983 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10985 g_object_ref_sink (child);
10986 child->priv->parent = NULL;
10987 child->priv->next_sibling = NULL;
10988 child->priv->prev_sibling = NULL;
10990 /* delegate the actual insertion */
10991 add_func (self, child, data);
10993 g_assert (child->priv->parent == self);
10995 self->priv->n_children += 1;
10997 self->priv->age += 1;
10999 /* if push_internal() has been called then we automatically set
11000 * the flag on the actor
11002 if (self->priv->internal_child)
11003 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11005 /* clutter_actor_reparent() will emit ::parent-set for us */
11006 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11007 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11011 /* If parent is mapped or realized, we need to also be mapped or
11012 * realized once we're inside the parent.
11014 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11016 /* propagate the parent's text direction to the child */
11017 text_dir = clutter_actor_get_text_direction (self);
11018 clutter_actor_set_text_direction (child, text_dir);
11021 if (child->priv->show_on_set_parent)
11022 clutter_actor_show (child);
11024 if (CLUTTER_ACTOR_IS_MAPPED (child))
11025 clutter_actor_queue_redraw (child);
11027 /* maintain the invariant that if an actor needs layout,
11028 * its parents do as well
11030 if (child->priv->needs_width_request ||
11031 child->priv->needs_height_request ||
11032 child->priv->needs_allocation)
11034 /* we work around the short-circuiting we do
11035 * in clutter_actor_queue_relayout() since we
11036 * want to force a relayout
11038 child->priv->needs_width_request = TRUE;
11039 child->priv->needs_height_request = TRUE;
11040 child->priv->needs_allocation = TRUE;
11042 clutter_actor_queue_relayout (child->priv->parent);
11045 if (emit_actor_added)
11046 g_signal_emit_by_name (self, "actor-added", child);
11048 if (notify_first_last)
11050 if (old_first_child != self->priv->first_child)
11051 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11053 if (old_last_child != self->priv->last_child)
11054 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11057 g_object_thaw_notify (G_OBJECT (self));
11061 * clutter_actor_add_child:
11062 * @self: a #ClutterActor
11063 * @child: a #ClutterActor
11065 * Adds @child to the children of @self.
11067 * This function will acquire a reference on @child that will only
11068 * be released when calling clutter_actor_remove_child().
11070 * This function will take into consideration the #ClutterActor:depth
11071 * of @child, and will keep the list of children sorted.
11073 * This function will emit the #ClutterContainer::actor-added signal
11079 clutter_actor_add_child (ClutterActor *self,
11080 ClutterActor *child)
11082 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11083 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11084 g_return_if_fail (self != child);
11085 g_return_if_fail (child->priv->parent == NULL);
11087 clutter_actor_add_child_internal (self, child,
11088 ADD_CHILD_DEFAULT_FLAGS,
11089 insert_child_at_depth,
11094 * clutter_actor_insert_child_at_index:
11095 * @self: a #ClutterActor
11096 * @child: a #ClutterActor
11097 * @index_: the index
11099 * Inserts @child into the list of children of @self, using the
11100 * given @index_. If @index_ is greater than the number of children
11101 * in @self, or is less than 0, then the new child is added at the end.
11103 * This function will acquire a reference on @child that will only
11104 * be released when calling clutter_actor_remove_child().
11106 * This function will not take into consideration the #ClutterActor:depth
11109 * This function will emit the #ClutterContainer::actor-added signal
11115 clutter_actor_insert_child_at_index (ClutterActor *self,
11116 ClutterActor *child,
11119 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11120 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11121 g_return_if_fail (self != child);
11122 g_return_if_fail (child->priv->parent == NULL);
11124 clutter_actor_add_child_internal (self, child,
11125 ADD_CHILD_DEFAULT_FLAGS,
11126 insert_child_at_index,
11127 GINT_TO_POINTER (index_));
11131 * clutter_actor_insert_child_above:
11132 * @self: a #ClutterActor
11133 * @child: a #ClutterActor
11134 * @sibling: (allow-none): a child of @self, or %NULL
11136 * Inserts @child into the list of children of @self, above another
11137 * child of @self or, if @sibling is %NULL, above all the children
11140 * This function will acquire a reference on @child that will only
11141 * be released when calling clutter_actor_remove_child().
11143 * This function will not take into consideration the #ClutterActor:depth
11146 * This function will emit the #ClutterContainer::actor-added signal
11152 clutter_actor_insert_child_above (ClutterActor *self,
11153 ClutterActor *child,
11154 ClutterActor *sibling)
11156 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11157 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11158 g_return_if_fail (self != child);
11159 g_return_if_fail (child != sibling);
11160 g_return_if_fail (child->priv->parent == NULL);
11161 g_return_if_fail (sibling == NULL ||
11162 (CLUTTER_IS_ACTOR (sibling) &&
11163 sibling->priv->parent == self));
11165 clutter_actor_add_child_internal (self, child,
11166 ADD_CHILD_DEFAULT_FLAGS,
11167 insert_child_above,
11172 * clutter_actor_insert_child_below:
11173 * @self: a #ClutterActor
11174 * @child: a #ClutterActor
11175 * @sibling: (allow-none): a child of @self, or %NULL
11177 * Inserts @child into the list of children of @self, below another
11178 * child of @self or, if @sibling is %NULL, below all the children
11181 * This function will acquire a reference on @child that will only
11182 * be released when calling clutter_actor_remove_child().
11184 * This function will not take into consideration the #ClutterActor:depth
11187 * This function will emit the #ClutterContainer::actor-added signal
11193 clutter_actor_insert_child_below (ClutterActor *self,
11194 ClutterActor *child,
11195 ClutterActor *sibling)
11197 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11198 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11199 g_return_if_fail (self != child);
11200 g_return_if_fail (child != sibling);
11201 g_return_if_fail (child->priv->parent == NULL);
11202 g_return_if_fail (sibling == NULL ||
11203 (CLUTTER_IS_ACTOR (sibling) &&
11204 sibling->priv->parent == self));
11206 clutter_actor_add_child_internal (self, child,
11207 ADD_CHILD_DEFAULT_FLAGS,
11208 insert_child_below,
11213 * clutter_actor_set_parent:
11214 * @self: A #ClutterActor
11215 * @parent: A new #ClutterActor parent
11217 * Sets the parent of @self to @parent.
11219 * This function will result in @parent acquiring a reference on @self,
11220 * eventually by sinking its floating reference first. The reference
11221 * will be released by clutter_actor_unparent().
11223 * This function should only be called by legacy #ClutterActor<!-- -->s
11224 * implementing the #ClutterContainer interface.
11226 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11229 clutter_actor_set_parent (ClutterActor *self,
11230 ClutterActor *parent)
11232 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11233 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11234 g_return_if_fail (self != parent);
11235 g_return_if_fail (self->priv->parent == NULL);
11237 /* as this function will be called inside ClutterContainer::add
11238 * implementations or when building up a composite actor, we have
11239 * to preserve the old behaviour, and not create child meta or
11240 * emit the ::actor-added signal, to avoid recursion or double
11243 clutter_actor_add_child_internal (parent, self,
11244 ADD_CHILD_LEGACY_FLAGS,
11245 insert_child_at_depth,
11250 * clutter_actor_get_parent:
11251 * @self: A #ClutterActor
11253 * Retrieves the parent of @self.
11255 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11256 * if no parent is set
11259 clutter_actor_get_parent (ClutterActor *self)
11261 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11263 return self->priv->parent;
11267 * clutter_actor_get_paint_visibility:
11268 * @self: A #ClutterActor
11270 * Retrieves the 'paint' visibility of an actor recursively checking for non
11273 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11275 * Return Value: %TRUE if the actor is visibile and will be painted.
11280 clutter_actor_get_paint_visibility (ClutterActor *actor)
11282 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11284 return CLUTTER_ACTOR_IS_MAPPED (actor);
11288 * clutter_actor_remove_child:
11289 * @self: a #ClutterActor
11290 * @child: a #ClutterActor
11292 * Removes @child from the children of @self.
11294 * This function will release the reference added by
11295 * clutter_actor_add_child(), so if you want to keep using @child
11296 * you will have to acquire a referenced on it before calling this
11299 * This function will emit the #ClutterContainer::actor-removed
11305 clutter_actor_remove_child (ClutterActor *self,
11306 ClutterActor *child)
11308 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11309 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11310 g_return_if_fail (self != child);
11311 g_return_if_fail (child->priv->parent != NULL);
11312 g_return_if_fail (child->priv->parent == self);
11314 clutter_actor_remove_child_internal (self, child,
11315 REMOVE_CHILD_DEFAULT_FLAGS);
11319 * clutter_actor_remove_all_children:
11320 * @self: a #ClutterActor
11322 * Removes all children of @self.
11324 * This function releases the reference added by inserting a child actor
11325 * in the list of children of @self.
11327 * If the reference count of a child drops to zero, the child will be
11328 * destroyed. If you want to ensure the destruction of all the children
11329 * of @self, use clutter_actor_destroy_all_children().
11334 clutter_actor_remove_all_children (ClutterActor *self)
11336 ClutterActorIter iter;
11338 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11340 if (self->priv->n_children == 0)
11343 g_object_freeze_notify (G_OBJECT (self));
11345 clutter_actor_iter_init (&iter, self);
11346 while (clutter_actor_iter_next (&iter, NULL))
11347 clutter_actor_iter_remove (&iter);
11349 g_object_thaw_notify (G_OBJECT (self));
11352 g_assert (self->priv->first_child == NULL);
11353 g_assert (self->priv->last_child == NULL);
11354 g_assert (self->priv->n_children == 0);
11358 * clutter_actor_destroy_all_children:
11359 * @self: a #ClutterActor
11361 * Destroys all children of @self.
11363 * This function releases the reference added by inserting a child
11364 * actor in the list of children of @self, and ensures that the
11365 * #ClutterActor::destroy signal is emitted on each child of the
11368 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11369 * when its reference count drops to 0; the default handler of the
11370 * #ClutterActor::destroy signal will destroy all the children of an
11371 * actor. This function ensures that all children are destroyed, instead
11372 * of just removed from @self, unlike clutter_actor_remove_all_children()
11373 * which will merely release the reference and remove each child.
11375 * Unless you acquired an additional reference on each child of @self
11376 * prior to calling clutter_actor_remove_all_children() and want to reuse
11377 * the actors, you should use clutter_actor_destroy_all_children() in
11378 * order to make sure that children are destroyed and signal handlers
11379 * are disconnected even in cases where circular references prevent this
11380 * from automatically happening through reference counting alone.
11385 clutter_actor_destroy_all_children (ClutterActor *self)
11387 ClutterActorIter iter;
11389 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11391 if (self->priv->n_children == 0)
11394 g_object_freeze_notify (G_OBJECT (self));
11396 clutter_actor_iter_init (&iter, self);
11397 while (clutter_actor_iter_next (&iter, NULL))
11398 clutter_actor_iter_destroy (&iter);
11400 g_object_thaw_notify (G_OBJECT (self));
11403 g_assert (self->priv->first_child == NULL);
11404 g_assert (self->priv->last_child == NULL);
11405 g_assert (self->priv->n_children == 0);
11408 typedef struct _InsertBetweenData {
11409 ClutterActor *prev_sibling;
11410 ClutterActor *next_sibling;
11411 } InsertBetweenData;
11414 insert_child_between (ClutterActor *self,
11415 ClutterActor *child,
11418 InsertBetweenData *data = data_;
11419 ClutterActor *prev_sibling = data->prev_sibling;
11420 ClutterActor *next_sibling = data->next_sibling;
11422 child->priv->parent = self;
11423 child->priv->prev_sibling = prev_sibling;
11424 child->priv->next_sibling = next_sibling;
11426 if (prev_sibling != NULL)
11427 prev_sibling->priv->next_sibling = child;
11429 if (next_sibling != NULL)
11430 next_sibling->priv->prev_sibling = child;
11432 if (child->priv->prev_sibling == NULL)
11433 self->priv->first_child = child;
11435 if (child->priv->next_sibling == NULL)
11436 self->priv->last_child = child;
11440 * clutter_actor_replace_child:
11441 * @self: a #ClutterActor
11442 * @old_child: the child of @self to replace
11443 * @new_child: the #ClutterActor to replace @old_child
11445 * Replaces @old_child with @new_child in the list of children of @self.
11450 clutter_actor_replace_child (ClutterActor *self,
11451 ClutterActor *old_child,
11452 ClutterActor *new_child)
11454 ClutterActor *prev_sibling, *next_sibling;
11455 InsertBetweenData clos;
11457 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11458 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11459 g_return_if_fail (old_child->priv->parent == self);
11460 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11461 g_return_if_fail (old_child != new_child);
11462 g_return_if_fail (new_child != self);
11463 g_return_if_fail (new_child->priv->parent == NULL);
11465 prev_sibling = old_child->priv->prev_sibling;
11466 next_sibling = old_child->priv->next_sibling;
11467 clutter_actor_remove_child_internal (self, old_child,
11468 REMOVE_CHILD_DEFAULT_FLAGS);
11470 clos.prev_sibling = prev_sibling;
11471 clos.next_sibling = next_sibling;
11472 clutter_actor_add_child_internal (self, new_child,
11473 ADD_CHILD_DEFAULT_FLAGS,
11474 insert_child_between,
11479 * clutter_actor_unparent:
11480 * @self: a #ClutterActor
11482 * Removes the parent of @self.
11484 * This will cause the parent of @self to release the reference
11485 * acquired when calling clutter_actor_set_parent(), so if you
11486 * want to keep @self you will have to acquire a reference of
11487 * your own, through g_object_ref().
11489 * This function should only be called by legacy #ClutterActor<!-- -->s
11490 * implementing the #ClutterContainer interface.
11494 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11497 clutter_actor_unparent (ClutterActor *self)
11499 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11501 if (self->priv->parent == NULL)
11504 clutter_actor_remove_child_internal (self->priv->parent, self,
11505 REMOVE_CHILD_LEGACY_FLAGS);
11509 * clutter_actor_reparent:
11510 * @self: a #ClutterActor
11511 * @new_parent: the new #ClutterActor parent
11513 * Resets the parent actor of @self.
11515 * This function is logically equivalent to calling clutter_actor_unparent()
11516 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11517 * ensures the child is not finalized when unparented, and emits the
11518 * #ClutterActor::parent-set signal only once.
11520 * In reality, calling this function is less useful than it sounds, as some
11521 * application code may rely on changes in the intermediate state between
11522 * removal and addition of the actor from its old parent to the @new_parent.
11523 * Thus, it is strongly encouraged to avoid using this function in application
11528 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11529 * clutter_actor_add_child() instead; remember to take a reference on
11530 * the actor being removed before calling clutter_actor_remove_child()
11531 * to avoid the reference count dropping to zero and the actor being
11535 clutter_actor_reparent (ClutterActor *self,
11536 ClutterActor *new_parent)
11538 ClutterActorPrivate *priv;
11540 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11541 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11542 g_return_if_fail (self != new_parent);
11544 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11546 g_warning ("Cannot set a parent on a toplevel actor");
11550 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11552 g_warning ("Cannot set a parent currently being destroyed");
11558 if (priv->parent != new_parent)
11560 ClutterActor *old_parent;
11562 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11564 old_parent = priv->parent;
11566 g_object_ref (self);
11568 if (old_parent != NULL)
11570 /* go through the Container implementation if this is a regular
11571 * child and not an internal one
11573 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11575 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11577 /* this will have to call unparent() */
11578 clutter_container_remove_actor (parent, self);
11581 clutter_actor_remove_child_internal (old_parent, self,
11582 REMOVE_CHILD_LEGACY_FLAGS);
11585 /* Note, will call set_parent() */
11586 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11587 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11589 clutter_actor_add_child_internal (new_parent, self,
11590 ADD_CHILD_LEGACY_FLAGS,
11591 insert_child_at_depth,
11594 /* we emit the ::parent-set signal once */
11595 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11597 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11599 /* the IN_REPARENT flag suspends state updates */
11600 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11602 g_object_unref (self);
11607 * clutter_actor_contains:
11608 * @self: A #ClutterActor
11609 * @descendant: A #ClutterActor, possibly contained in @self
11611 * Determines if @descendant is contained inside @self (either as an
11612 * immediate child, or as a deeper descendant). If @self and
11613 * @descendant point to the same actor then it will also return %TRUE.
11615 * Return value: whether @descendent is contained within @self
11620 clutter_actor_contains (ClutterActor *self,
11621 ClutterActor *descendant)
11623 ClutterActor *actor;
11625 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11626 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11628 for (actor = descendant; actor; actor = actor->priv->parent)
11636 * clutter_actor_set_child_above_sibling:
11637 * @self: a #ClutterActor
11638 * @child: a #ClutterActor child of @self
11639 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11641 * Sets @child to be above @sibling in the list of children of @self.
11643 * If @sibling is %NULL, @child will be the new last child of @self.
11645 * This function is logically equivalent to removing @child and using
11646 * clutter_actor_insert_child_above(), but it will not emit signals
11647 * or change state on @child.
11652 clutter_actor_set_child_above_sibling (ClutterActor *self,
11653 ClutterActor *child,
11654 ClutterActor *sibling)
11656 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11657 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11658 g_return_if_fail (child->priv->parent == self);
11659 g_return_if_fail (child != sibling);
11660 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11662 if (sibling != NULL)
11663 g_return_if_fail (sibling->priv->parent == self);
11665 /* we don't want to change the state of child, or emit signals, or
11666 * regenerate ChildMeta instances here, but we still want to follow
11667 * the correct sequence of steps encoded in remove_child() and
11668 * add_child(), so that correctness is ensured, and we only go
11669 * through one known code path.
11671 g_object_ref (child);
11672 clutter_actor_remove_child_internal (self, child, 0);
11673 clutter_actor_add_child_internal (self, child,
11674 ADD_CHILD_NOTIFY_FIRST_LAST,
11675 insert_child_above,
11678 clutter_actor_queue_relayout (self);
11682 * clutter_actor_set_child_below_sibling:
11683 * @self: a #ClutterActor
11684 * @child: a #ClutterActor child of @self
11685 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11687 * Sets @child to be below @sibling in the list of children of @self.
11689 * If @sibling is %NULL, @child will be the new first child of @self.
11691 * This function is logically equivalent to removing @self and using
11692 * clutter_actor_insert_child_below(), but it will not emit signals
11693 * or change state on @child.
11698 clutter_actor_set_child_below_sibling (ClutterActor *self,
11699 ClutterActor *child,
11700 ClutterActor *sibling)
11702 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11703 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11704 g_return_if_fail (child->priv->parent == self);
11705 g_return_if_fail (child != sibling);
11706 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11708 if (sibling != NULL)
11709 g_return_if_fail (sibling->priv->parent == self);
11711 /* see the comment in set_child_above_sibling() */
11712 g_object_ref (child);
11713 clutter_actor_remove_child_internal (self, child, 0);
11714 clutter_actor_add_child_internal (self, child,
11715 ADD_CHILD_NOTIFY_FIRST_LAST,
11716 insert_child_below,
11719 clutter_actor_queue_relayout (self);
11723 * clutter_actor_set_child_at_index:
11724 * @self: a #ClutterActor
11725 * @child: a #ClutterActor child of @self
11726 * @index_: the new index for @child
11728 * Changes the index of @child in the list of children of @self.
11730 * This function is logically equivalent to removing @child and
11731 * calling clutter_actor_insert_child_at_index(), but it will not
11732 * emit signals or change state on @child.
11737 clutter_actor_set_child_at_index (ClutterActor *self,
11738 ClutterActor *child,
11741 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11742 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11743 g_return_if_fail (child->priv->parent == self);
11744 g_return_if_fail (index_ <= self->priv->n_children);
11746 g_object_ref (child);
11747 clutter_actor_remove_child_internal (self, child, 0);
11748 clutter_actor_add_child_internal (self, child,
11749 ADD_CHILD_NOTIFY_FIRST_LAST,
11750 insert_child_at_index,
11751 GINT_TO_POINTER (index_));
11753 clutter_actor_queue_relayout (self);
11757 * clutter_actor_raise:
11758 * @self: A #ClutterActor
11759 * @below: (allow-none): A #ClutterActor to raise above.
11761 * Puts @self above @below.
11763 * Both actors must have the same parent, and the parent must implement
11764 * the #ClutterContainer interface
11766 * This function calls clutter_container_raise_child() internally.
11768 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11771 clutter_actor_raise (ClutterActor *self,
11772 ClutterActor *below)
11774 ClutterActor *parent;
11776 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11778 parent = clutter_actor_get_parent (self);
11779 if (parent == NULL)
11781 g_warning ("%s: Actor '%s' is not inside a container",
11783 _clutter_actor_get_debug_name (self));
11789 if (parent != clutter_actor_get_parent (below))
11791 g_warning ("%s Actor '%s' is not in the same container as "
11794 _clutter_actor_get_debug_name (self),
11795 _clutter_actor_get_debug_name (below));
11800 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11804 * clutter_actor_lower:
11805 * @self: A #ClutterActor
11806 * @above: (allow-none): A #ClutterActor to lower below
11808 * Puts @self below @above.
11810 * Both actors must have the same parent, and the parent must implement
11811 * the #ClutterContainer interface.
11813 * This function calls clutter_container_lower_child() internally.
11815 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11818 clutter_actor_lower (ClutterActor *self,
11819 ClutterActor *above)
11821 ClutterActor *parent;
11823 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11825 parent = clutter_actor_get_parent (self);
11826 if (parent == NULL)
11828 g_warning ("%s: Actor of type %s is not inside a container",
11830 _clutter_actor_get_debug_name (self));
11836 if (parent != clutter_actor_get_parent (above))
11838 g_warning ("%s: Actor '%s' is not in the same container as "
11841 _clutter_actor_get_debug_name (self),
11842 _clutter_actor_get_debug_name (above));
11847 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11851 * clutter_actor_raise_top:
11852 * @self: A #ClutterActor
11854 * Raises @self to the top.
11856 * This function calls clutter_actor_raise() internally.
11858 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11859 * a %NULL sibling, instead.
11862 clutter_actor_raise_top (ClutterActor *self)
11864 clutter_actor_raise (self, NULL);
11868 * clutter_actor_lower_bottom:
11869 * @self: A #ClutterActor
11871 * Lowers @self to the bottom.
11873 * This function calls clutter_actor_lower() internally.
11875 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11876 * a %NULL sibling, instead.
11879 clutter_actor_lower_bottom (ClutterActor *self)
11881 clutter_actor_lower (self, NULL);
11889 * clutter_actor_event:
11890 * @actor: a #ClutterActor
11891 * @event: a #ClutterEvent
11892 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11894 * This function is used to emit an event on the main stage.
11895 * You should rarely need to use this function, except for
11896 * synthetising events.
11898 * Return value: the return value from the signal emission: %TRUE
11899 * if the actor handled the event, or %FALSE if the event was
11905 clutter_actor_event (ClutterActor *actor,
11906 ClutterEvent *event,
11909 gboolean retval = FALSE;
11910 gint signal_num = -1;
11912 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11913 g_return_val_if_fail (event != NULL, FALSE);
11915 g_object_ref (actor);
11919 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11925 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11929 switch (event->type)
11931 case CLUTTER_NOTHING:
11933 case CLUTTER_BUTTON_PRESS:
11934 signal_num = BUTTON_PRESS_EVENT;
11936 case CLUTTER_BUTTON_RELEASE:
11937 signal_num = BUTTON_RELEASE_EVENT;
11939 case CLUTTER_SCROLL:
11940 signal_num = SCROLL_EVENT;
11942 case CLUTTER_KEY_PRESS:
11943 signal_num = KEY_PRESS_EVENT;
11945 case CLUTTER_KEY_RELEASE:
11946 signal_num = KEY_RELEASE_EVENT;
11948 case CLUTTER_MOTION:
11949 signal_num = MOTION_EVENT;
11951 case CLUTTER_ENTER:
11952 signal_num = ENTER_EVENT;
11954 case CLUTTER_LEAVE:
11955 signal_num = LEAVE_EVENT;
11957 case CLUTTER_DELETE:
11958 case CLUTTER_DESTROY_NOTIFY:
11959 case CLUTTER_CLIENT_MESSAGE:
11965 if (signal_num != -1)
11966 g_signal_emit (actor, actor_signals[signal_num], 0,
11971 g_object_unref (actor);
11977 * clutter_actor_set_reactive:
11978 * @actor: a #ClutterActor
11979 * @reactive: whether the actor should be reactive to events
11981 * Sets @actor as reactive. Reactive actors will receive events.
11986 clutter_actor_set_reactive (ClutterActor *actor,
11989 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11991 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11995 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11997 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11999 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12003 * clutter_actor_get_reactive:
12004 * @actor: a #ClutterActor
12006 * Checks whether @actor is marked as reactive.
12008 * Return value: %TRUE if the actor is reactive
12013 clutter_actor_get_reactive (ClutterActor *actor)
12015 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12017 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12021 * clutter_actor_get_anchor_point:
12022 * @self: a #ClutterActor
12023 * @anchor_x: (out): return location for the X coordinate of the anchor point
12024 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12026 * Gets the current anchor point of the @actor in pixels.
12031 clutter_actor_get_anchor_point (ClutterActor *self,
12035 const ClutterTransformInfo *info;
12037 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12039 info = _clutter_actor_get_transform_info_or_defaults (self);
12040 clutter_anchor_coord_get_units (self, &info->anchor,
12047 * clutter_actor_set_anchor_point:
12048 * @self: a #ClutterActor
12049 * @anchor_x: X coordinate of the anchor point
12050 * @anchor_y: Y coordinate of the anchor point
12052 * Sets an anchor point for @self. The anchor point is a point in the
12053 * coordinate space of an actor to which the actor position within its
12054 * parent is relative; the default is (0, 0), i.e. the top-left corner
12060 clutter_actor_set_anchor_point (ClutterActor *self,
12064 ClutterTransformInfo *info;
12065 ClutterActorPrivate *priv;
12066 gboolean changed = FALSE;
12067 gfloat old_anchor_x, old_anchor_y;
12070 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12072 obj = G_OBJECT (self);
12074 info = _clutter_actor_get_transform_info (self);
12076 g_object_freeze_notify (obj);
12078 clutter_anchor_coord_get_units (self, &info->anchor,
12083 if (info->anchor.is_fractional)
12084 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12086 if (old_anchor_x != anchor_x)
12088 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12092 if (old_anchor_y != anchor_y)
12094 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12098 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12102 priv->transform_valid = FALSE;
12103 clutter_actor_queue_redraw (self);
12106 g_object_thaw_notify (obj);
12110 * clutter_actor_get_anchor_point_gravity:
12111 * @self: a #ClutterActor
12113 * Retrieves the anchor position expressed as a #ClutterGravity. If
12114 * the anchor point was specified using pixels or units this will
12115 * return %CLUTTER_GRAVITY_NONE.
12117 * Return value: the #ClutterGravity used by the anchor point
12122 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12124 const ClutterTransformInfo *info;
12126 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12128 info = _clutter_actor_get_transform_info_or_defaults (self);
12130 return clutter_anchor_coord_get_gravity (&info->anchor);
12134 * clutter_actor_move_anchor_point:
12135 * @self: a #ClutterActor
12136 * @anchor_x: X coordinate of the anchor point
12137 * @anchor_y: Y coordinate of the anchor point
12139 * Sets an anchor point for the actor, and adjusts the actor postion so that
12140 * the relative position of the actor toward its parent remains the same.
12145 clutter_actor_move_anchor_point (ClutterActor *self,
12149 gfloat old_anchor_x, old_anchor_y;
12150 const ClutterTransformInfo *info;
12152 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12154 info = _clutter_actor_get_transform_info (self);
12155 clutter_anchor_coord_get_units (self, &info->anchor,
12160 g_object_freeze_notify (G_OBJECT (self));
12162 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12164 if (self->priv->position_set)
12165 clutter_actor_move_by (self,
12166 anchor_x - old_anchor_x,
12167 anchor_y - old_anchor_y);
12169 g_object_thaw_notify (G_OBJECT (self));
12173 * clutter_actor_move_anchor_point_from_gravity:
12174 * @self: a #ClutterActor
12175 * @gravity: #ClutterGravity.
12177 * Sets an anchor point on the actor based on the given gravity, adjusting the
12178 * actor postion so that its relative position within its parent remains
12181 * Since version 1.0 the anchor point will be stored as a gravity so
12182 * that if the actor changes size then the anchor point will move. For
12183 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12184 * and later double the size of the actor, the anchor point will move
12185 * to the bottom right.
12190 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12191 ClutterGravity gravity)
12193 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12194 const ClutterTransformInfo *info;
12195 ClutterActorPrivate *priv;
12197 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12200 info = _clutter_actor_get_transform_info (self);
12202 g_object_freeze_notify (G_OBJECT (self));
12204 clutter_anchor_coord_get_units (self, &info->anchor,
12208 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12209 clutter_anchor_coord_get_units (self, &info->anchor,
12214 if (priv->position_set)
12215 clutter_actor_move_by (self,
12216 new_anchor_x - old_anchor_x,
12217 new_anchor_y - old_anchor_y);
12219 g_object_thaw_notify (G_OBJECT (self));
12223 * clutter_actor_set_anchor_point_from_gravity:
12224 * @self: a #ClutterActor
12225 * @gravity: #ClutterGravity.
12227 * Sets an anchor point on the actor, based on the given gravity (this is a
12228 * convenience function wrapping clutter_actor_set_anchor_point()).
12230 * Since version 1.0 the anchor point will be stored as a gravity so
12231 * that if the actor changes size then the anchor point will move. For
12232 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12233 * and later double the size of the actor, the anchor point will move
12234 * to the bottom right.
12239 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12240 ClutterGravity gravity)
12242 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12244 if (gravity == CLUTTER_GRAVITY_NONE)
12245 clutter_actor_set_anchor_point (self, 0, 0);
12248 GObject *obj = G_OBJECT (self);
12249 ClutterTransformInfo *info;
12251 g_object_freeze_notify (obj);
12253 info = _clutter_actor_get_transform_info (self);
12254 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12256 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12257 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12258 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12260 self->priv->transform_valid = FALSE;
12262 clutter_actor_queue_redraw (self);
12264 g_object_thaw_notify (obj);
12269 clutter_container_iface_init (ClutterContainerIface *iface)
12271 /* we don't override anything, as ClutterContainer already has a default
12272 * implementation that we can use, and which calls into our own API.
12287 parse_units (ClutterActor *self,
12288 ParseDimension dimension,
12291 GValue value = G_VALUE_INIT;
12294 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12297 json_node_get_value (node, &value);
12299 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12301 retval = (gfloat) g_value_get_int64 (&value);
12303 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12305 retval = g_value_get_double (&value);
12307 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12309 ClutterUnits units;
12312 res = clutter_units_from_string (&units, g_value_get_string (&value));
12314 retval = clutter_units_to_pixels (&units);
12317 g_warning ("Invalid value '%s': integers, strings or floating point "
12318 "values can be used for the x, y, width and height "
12319 "properties. Valid modifiers for strings are 'px', 'mm', "
12321 g_value_get_string (&value));
12327 g_warning ("Invalid value of type '%s': integers, strings of floating "
12328 "point values can be used for the x, y, width, height "
12329 "anchor-x and anchor-y properties.",
12330 g_type_name (G_VALUE_TYPE (&value)));
12333 g_value_unset (&value);
12339 ClutterRotateAxis axis;
12348 static inline gboolean
12349 parse_rotation_array (ClutterActor *actor,
12351 RotationInfo *info)
12355 if (json_array_get_length (array) != 2)
12359 element = json_array_get_element (array, 0);
12360 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12361 info->angle = json_node_get_double (element);
12366 element = json_array_get_element (array, 1);
12367 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12369 JsonArray *center = json_node_get_array (element);
12371 if (json_array_get_length (center) != 2)
12374 switch (info->axis)
12376 case CLUTTER_X_AXIS:
12377 info->center_y = parse_units (actor, PARSE_Y,
12378 json_array_get_element (center, 0));
12379 info->center_z = parse_units (actor, PARSE_Y,
12380 json_array_get_element (center, 1));
12383 case CLUTTER_Y_AXIS:
12384 info->center_x = parse_units (actor, PARSE_X,
12385 json_array_get_element (center, 0));
12386 info->center_z = parse_units (actor, PARSE_X,
12387 json_array_get_element (center, 1));
12390 case CLUTTER_Z_AXIS:
12391 info->center_x = parse_units (actor, PARSE_X,
12392 json_array_get_element (center, 0));
12393 info->center_y = parse_units (actor, PARSE_Y,
12394 json_array_get_element (center, 1));
12403 parse_rotation (ClutterActor *actor,
12405 RotationInfo *info)
12409 gboolean retval = FALSE;
12411 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12413 g_warning ("Invalid node of type '%s' found, expecting an array",
12414 json_node_type_name (node));
12418 array = json_node_get_array (node);
12419 len = json_array_get_length (array);
12421 for (i = 0; i < len; i++)
12423 JsonNode *element = json_array_get_element (array, i);
12424 JsonObject *object;
12427 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12429 g_warning ("Invalid node of type '%s' found, expecting an object",
12430 json_node_type_name (element));
12434 object = json_node_get_object (element);
12436 if (json_object_has_member (object, "x-axis"))
12438 member = json_object_get_member (object, "x-axis");
12440 info->axis = CLUTTER_X_AXIS;
12442 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12444 info->angle = json_node_get_double (member);
12447 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12448 retval = parse_rotation_array (actor,
12449 json_node_get_array (member),
12454 else if (json_object_has_member (object, "y-axis"))
12456 member = json_object_get_member (object, "y-axis");
12458 info->axis = CLUTTER_Y_AXIS;
12460 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12462 info->angle = json_node_get_double (member);
12465 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12466 retval = parse_rotation_array (actor,
12467 json_node_get_array (member),
12472 else if (json_object_has_member (object, "z-axis"))
12474 member = json_object_get_member (object, "z-axis");
12476 info->axis = CLUTTER_Z_AXIS;
12478 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12480 info->angle = json_node_get_double (member);
12483 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12484 retval = parse_rotation_array (actor,
12485 json_node_get_array (member),
12496 parse_actor_metas (ClutterScript *script,
12497 ClutterActor *actor,
12500 GList *elements, *l;
12501 GSList *retval = NULL;
12503 if (!JSON_NODE_HOLDS_ARRAY (node))
12506 elements = json_array_get_elements (json_node_get_array (node));
12508 for (l = elements; l != NULL; l = l->next)
12510 JsonNode *element = l->data;
12511 const gchar *id_ = _clutter_script_get_id_from_node (element);
12514 if (id_ == NULL || *id_ == '\0')
12517 meta = clutter_script_get_object (script, id_);
12521 retval = g_slist_prepend (retval, meta);
12524 g_list_free (elements);
12526 return g_slist_reverse (retval);
12530 parse_behaviours (ClutterScript *script,
12531 ClutterActor *actor,
12534 GList *elements, *l;
12535 GSList *retval = NULL;
12537 if (!JSON_NODE_HOLDS_ARRAY (node))
12540 elements = json_array_get_elements (json_node_get_array (node));
12542 for (l = elements; l != NULL; l = l->next)
12544 JsonNode *element = l->data;
12545 const gchar *id_ = _clutter_script_get_id_from_node (element);
12546 GObject *behaviour;
12548 if (id_ == NULL || *id_ == '\0')
12551 behaviour = clutter_script_get_object (script, id_);
12552 if (behaviour == NULL)
12555 retval = g_slist_prepend (retval, behaviour);
12558 g_list_free (elements);
12560 return g_slist_reverse (retval);
12564 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12565 ClutterScript *script,
12570 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12571 gboolean retval = FALSE;
12573 if ((name[0] == 'x' && name[1] == '\0') ||
12574 (name[0] == 'y' && name[1] == '\0') ||
12575 (strcmp (name, "width") == 0) ||
12576 (strcmp (name, "height") == 0) ||
12577 (strcmp (name, "anchor_x") == 0) ||
12578 (strcmp (name, "anchor_y") == 0))
12580 ParseDimension dimension;
12583 if (name[0] == 'x')
12584 dimension = PARSE_X;
12585 else if (name[0] == 'y')
12586 dimension = PARSE_Y;
12587 else if (name[0] == 'w')
12588 dimension = PARSE_WIDTH;
12589 else if (name[0] == 'h')
12590 dimension = PARSE_HEIGHT;
12591 else if (name[0] == 'a' && name[7] == 'x')
12592 dimension = PARSE_ANCHOR_X;
12593 else if (name[0] == 'a' && name[7] == 'y')
12594 dimension = PARSE_ANCHOR_Y;
12598 units = parse_units (actor, dimension, node);
12600 /* convert back to pixels: all properties are pixel-based */
12601 g_value_init (value, G_TYPE_FLOAT);
12602 g_value_set_float (value, units);
12606 else if (strcmp (name, "rotation") == 0)
12608 RotationInfo *info;
12610 info = g_slice_new0 (RotationInfo);
12611 retval = parse_rotation (actor, node, info);
12615 g_value_init (value, G_TYPE_POINTER);
12616 g_value_set_pointer (value, info);
12619 g_slice_free (RotationInfo, info);
12621 else if (strcmp (name, "behaviours") == 0)
12625 #ifdef CLUTTER_ENABLE_DEBUG
12626 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12627 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12628 "and it should not be used in newly "
12629 "written ClutterScript definitions.");
12632 l = parse_behaviours (script, actor, node);
12634 g_value_init (value, G_TYPE_POINTER);
12635 g_value_set_pointer (value, l);
12639 else if (strcmp (name, "actions") == 0 ||
12640 strcmp (name, "constraints") == 0 ||
12641 strcmp (name, "effects") == 0)
12645 l = parse_actor_metas (script, actor, node);
12647 g_value_init (value, G_TYPE_POINTER);
12648 g_value_set_pointer (value, l);
12657 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12658 ClutterScript *script,
12660 const GValue *value)
12662 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12664 #ifdef CLUTTER_ENABLE_DEBUG
12665 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12667 gchar *tmp = g_strdup_value_contents (value);
12669 CLUTTER_NOTE (SCRIPT,
12670 "in ClutterActor::set_custom_property('%s') = %s",
12676 #endif /* CLUTTER_ENABLE_DEBUG */
12678 if (strcmp (name, "rotation") == 0)
12680 RotationInfo *info;
12682 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12685 info = g_value_get_pointer (value);
12687 clutter_actor_set_rotation (actor,
12688 info->axis, info->angle,
12693 g_slice_free (RotationInfo, info);
12698 if (strcmp (name, "behaviours") == 0)
12700 GSList *behaviours, *l;
12702 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12705 behaviours = g_value_get_pointer (value);
12706 for (l = behaviours; l != NULL; l = l->next)
12708 ClutterBehaviour *behaviour = l->data;
12710 clutter_behaviour_apply (behaviour, actor);
12713 g_slist_free (behaviours);
12718 if (strcmp (name, "actions") == 0 ||
12719 strcmp (name, "constraints") == 0 ||
12720 strcmp (name, "effects") == 0)
12724 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12727 metas = g_value_get_pointer (value);
12728 for (l = metas; l != NULL; l = l->next)
12730 if (name[0] == 'a')
12731 clutter_actor_add_action (actor, l->data);
12733 if (name[0] == 'c')
12734 clutter_actor_add_constraint (actor, l->data);
12736 if (name[0] == 'e')
12737 clutter_actor_add_effect (actor, l->data);
12740 g_slist_free (metas);
12745 g_object_set_property (G_OBJECT (scriptable), name, value);
12749 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12751 iface->parse_custom_node = clutter_actor_parse_custom_node;
12752 iface->set_custom_property = clutter_actor_set_custom_property;
12755 static ClutterActorMeta *
12756 get_meta_from_animation_property (ClutterActor *actor,
12760 ClutterActorPrivate *priv = actor->priv;
12761 ClutterActorMeta *meta = NULL;
12764 /* if this is not a special property, fall through */
12765 if (name[0] != '@')
12768 /* detect the properties named using the following spec:
12770 * @<section>.<meta-name>.<property-name>
12772 * where <section> can be one of the following:
12778 * and <meta-name> is the name set on a specific ActorMeta
12781 tokens = g_strsplit (name + 1, ".", -1);
12782 if (tokens == NULL || g_strv_length (tokens) != 3)
12784 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12786 g_strfreev (tokens);
12790 if (strcmp (tokens[0], "actions") == 0)
12791 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12793 if (strcmp (tokens[0], "constraints") == 0)
12794 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12796 if (strcmp (tokens[0], "effects") == 0)
12797 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12799 if (name_p != NULL)
12800 *name_p = g_strdup (tokens[2]);
12802 CLUTTER_NOTE (ANIMATION,
12803 "Looking for property '%s' of object '%s' in section '%s'",
12808 g_strfreev (tokens);
12813 static GParamSpec *
12814 clutter_actor_find_property (ClutterAnimatable *animatable,
12815 const gchar *property_name)
12817 ClutterActorMeta *meta = NULL;
12818 GObjectClass *klass = NULL;
12819 GParamSpec *pspec = NULL;
12820 gchar *p_name = NULL;
12822 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12828 klass = G_OBJECT_GET_CLASS (meta);
12830 pspec = g_object_class_find_property (klass, p_name);
12834 klass = G_OBJECT_GET_CLASS (animatable);
12836 pspec = g_object_class_find_property (klass, property_name);
12845 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12846 const gchar *property_name,
12849 ClutterActorMeta *meta = NULL;
12850 gchar *p_name = NULL;
12852 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12857 g_object_get_property (G_OBJECT (meta), p_name, initial);
12859 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12865 * clutter_actor_set_animatable_property:
12866 * @actor: a #ClutterActor
12867 * @prop_id: the paramspec id
12868 * @value: the value to set
12869 * @pspec: the paramspec
12871 * Sets values of animatable properties.
12873 * This is a variant of clutter_actor_set_property() that gets called
12874 * by the #ClutterAnimatable implementation of #ClutterActor for the
12875 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12878 * Unlike the implementation of #GObjectClass.set_property(), this
12879 * function will not update the interval if a transition involving an
12880 * animatable property is in progress - this avoids cycles with the
12881 * transition API calling the public API.
12884 clutter_actor_set_animatable_property (ClutterActor *actor,
12886 const GValue *value,
12892 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12896 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12900 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12904 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12908 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12912 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12915 case PROP_BACKGROUND_COLOR:
12916 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12920 clutter_actor_set_scale_factor_internal (actor,
12921 g_value_get_double (value),
12926 clutter_actor_set_scale_factor_internal (actor,
12927 g_value_get_double (value),
12931 case PROP_ROTATION_ANGLE_X:
12932 clutter_actor_set_rotation_angle_internal (actor,
12934 g_value_get_double (value));
12937 case PROP_ROTATION_ANGLE_Y:
12938 clutter_actor_set_rotation_angle_internal (actor,
12940 g_value_get_double (value));
12943 case PROP_ROTATION_ANGLE_Z:
12944 clutter_actor_set_rotation_angle_internal (actor,
12946 g_value_get_double (value));
12950 g_object_set_property (G_OBJECT (actor), pspec->name, value);
12956 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12957 const gchar *property_name,
12958 const GValue *final)
12960 ClutterActor *actor = CLUTTER_ACTOR (animatable);
12961 ClutterActorMeta *meta = NULL;
12962 gchar *p_name = NULL;
12964 meta = get_meta_from_animation_property (actor,
12968 g_object_set_property (G_OBJECT (meta), p_name, final);
12971 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12974 pspec = g_object_class_find_property (obj_class, property_name);
12976 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12978 /* XXX - I'm going to the special hell for this */
12979 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12982 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
12989 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12991 iface->find_property = clutter_actor_find_property;
12992 iface->get_initial_state = clutter_actor_get_initial_state;
12993 iface->set_final_state = clutter_actor_set_final_state;
12997 * clutter_actor_transform_stage_point:
12998 * @self: A #ClutterActor
12999 * @x: (in): x screen coordinate of the point to unproject
13000 * @y: (in): y screen coordinate of the point to unproject
13001 * @x_out: (out): return location for the unprojected x coordinance
13002 * @y_out: (out): return location for the unprojected y coordinance
13004 * This function translates screen coordinates (@x, @y) to
13005 * coordinates relative to the actor. For example, it can be used to translate
13006 * screen events from global screen coordinates into actor-local coordinates.
13008 * The conversion can fail, notably if the transform stack results in the
13009 * actor being projected on the screen as a mere line.
13011 * The conversion should not be expected to be pixel-perfect due to the
13012 * nature of the operation. In general the error grows when the skewing
13013 * of the actor rectangle on screen increases.
13015 * <note><para>This function can be computationally intensive.</para></note>
13017 * <note><para>This function only works when the allocation is up-to-date,
13018 * i.e. inside of paint().</para></note>
13020 * Return value: %TRUE if conversion was successful.
13025 clutter_actor_transform_stage_point (ClutterActor *self,
13031 ClutterVertex v[4];
13034 int du, dv, xi, yi;
13036 float xf, yf, wf, det;
13037 ClutterActorPrivate *priv;
13039 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13043 /* This implementation is based on the quad -> quad projection algorithm
13044 * described by Paul Heckbert in:
13046 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13048 * and the sample implementation at:
13050 * http://www.cs.cmu.edu/~ph/src/texfund/
13052 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13053 * quad to rectangle only, which significantly simplifies things; the
13054 * function calls have been unrolled, and most of the math is done in fixed
13058 clutter_actor_get_abs_allocation_vertices (self, v);
13060 /* Keeping these as ints simplifies the multiplication (no significant
13061 * loss of precision here).
13063 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13064 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13069 #define UX2FP(x) (x)
13070 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13072 /* First, find mapping from unit uv square to xy quadrilateral; this
13073 * equivalent to the pmap_square_quad() functions in the sample
13074 * implementation, which we can simplify, since our target is always
13077 px = v[0].x - v[1].x + v[3].x - v[2].x;
13078 py = v[0].y - v[1].y + v[3].y - v[2].y;
13082 /* affine transform */
13083 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13084 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13085 RQ[2][0] = UX2FP (v[0].x);
13086 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13087 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13088 RQ[2][1] = UX2FP (v[0].y);
13095 /* projective transform */
13096 double dx1, dx2, dy1, dy2, del;
13098 dx1 = UX2FP (v[1].x - v[3].x);
13099 dx2 = UX2FP (v[2].x - v[3].x);
13100 dy1 = UX2FP (v[1].y - v[3].y);
13101 dy2 = UX2FP (v[2].y - v[3].y);
13103 del = DET2FP (dx1, dx2, dy1, dy2);
13108 * The division here needs to be done in floating point for
13109 * precisions reasons.
13111 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13112 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13113 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13115 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13116 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13117 RQ[2][0] = UX2FP (v[0].x);
13118 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13119 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13120 RQ[2][1] = UX2FP (v[0].y);
13124 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13125 * square. Since our rectangle is based at 0,0 we only need to scale.
13135 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13138 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13139 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13140 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13141 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13142 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13143 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13144 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13145 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13146 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13149 * Check the resulting matrix is OK.
13151 det = (RQ[0][0] * ST[0][0])
13152 + (RQ[0][1] * ST[0][1])
13153 + (RQ[0][2] * ST[0][2]);
13158 * Now transform our point with the ST matrix; the notional w
13159 * coordinate is 1, hence the last part is simply added.
13164 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13165 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13166 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13184 static ClutterGeometry*
13185 clutter_geometry_copy (const ClutterGeometry *geometry)
13187 return g_slice_dup (ClutterGeometry, geometry);
13191 clutter_geometry_free (ClutterGeometry *geometry)
13193 if (G_LIKELY (geometry != NULL))
13194 g_slice_free (ClutterGeometry, geometry);
13198 * clutter_geometry_union:
13199 * @geometry_a: a #ClutterGeometry
13200 * @geometry_b: another #ClutterGeometry
13201 * @result: (out): location to store the result
13203 * Find the union of two rectangles represented as #ClutterGeometry.
13208 clutter_geometry_union (const ClutterGeometry *geometry_a,
13209 const ClutterGeometry *geometry_b,
13210 ClutterGeometry *result)
13212 /* We don't try to handle rectangles that can't be represented
13213 * as a signed integer box */
13214 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13215 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13216 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13217 geometry_b->x + (gint)geometry_b->width);
13218 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13219 geometry_b->y + (gint)geometry_b->height);
13222 result->width = x_2 - x_1;
13223 result->height = y_2 - y_1;
13227 * clutter_geometry_intersects:
13228 * @geometry0: The first geometry to test
13229 * @geometry1: The second geometry to test
13231 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13232 * they do else %FALSE.
13234 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13240 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13241 const ClutterGeometry *geometry1)
13243 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13244 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13245 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13246 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13253 clutter_geometry_progress (const GValue *a,
13258 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13259 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13260 ClutterGeometry res = { 0, };
13261 gint a_width = a_geom->width;
13262 gint b_width = b_geom->width;
13263 gint a_height = a_geom->height;
13264 gint b_height = b_geom->height;
13266 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13267 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13269 res.width = a_width + (b_width - a_width) * progress;
13270 res.height = a_height + (b_height - a_height) * progress;
13272 g_value_set_boxed (retval, &res);
13277 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13278 clutter_geometry_copy,
13279 clutter_geometry_free,
13280 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13287 * clutter_vertex_new:
13292 * Creates a new #ClutterVertex for the point in 3D space
13293 * identified by the 3 coordinates @x, @y, @z
13295 * Return value: the newly allocate #ClutterVertex. Use
13296 * clutter_vertex_free() to free the resources
13301 clutter_vertex_new (gfloat x,
13305 ClutterVertex *vertex;
13307 vertex = g_slice_new (ClutterVertex);
13308 clutter_vertex_init (vertex, x, y, z);
13314 * clutter_vertex_init:
13315 * @vertex: a #ClutterVertex
13320 * Initializes @vertex with the given coordinates.
13325 clutter_vertex_init (ClutterVertex *vertex,
13330 g_return_if_fail (vertex != NULL);
13338 * clutter_vertex_copy:
13339 * @vertex: a #ClutterVertex
13343 * Return value: a newly allocated copy of #ClutterVertex. Use
13344 * clutter_vertex_free() to free the allocated resources
13349 clutter_vertex_copy (const ClutterVertex *vertex)
13351 if (G_LIKELY (vertex != NULL))
13352 return g_slice_dup (ClutterVertex, vertex);
13358 * clutter_vertex_free:
13359 * @vertex: a #ClutterVertex
13361 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13366 clutter_vertex_free (ClutterVertex *vertex)
13368 if (G_UNLIKELY (vertex != NULL))
13369 g_slice_free (ClutterVertex, vertex);
13373 * clutter_vertex_equal:
13374 * @vertex_a: a #ClutterVertex
13375 * @vertex_b: a #ClutterVertex
13377 * Compares @vertex_a and @vertex_b for equality
13379 * Return value: %TRUE if the passed #ClutterVertex are equal
13384 clutter_vertex_equal (const ClutterVertex *vertex_a,
13385 const ClutterVertex *vertex_b)
13387 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13389 if (vertex_a == vertex_b)
13392 return vertex_a->x == vertex_b->x &&
13393 vertex_a->y == vertex_b->y &&
13394 vertex_a->z == vertex_b->z;
13398 clutter_vertex_progress (const GValue *a,
13403 const ClutterVertex *av = g_value_get_boxed (a);
13404 const ClutterVertex *bv = g_value_get_boxed (b);
13405 ClutterVertex res = { 0, };
13407 res.x = av->x + (bv->x - av->x) * progress;
13408 res.y = av->y + (bv->y - av->y) * progress;
13409 res.z = av->z + (bv->z - av->z) * progress;
13411 g_value_set_boxed (retval, &res);
13416 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13417 clutter_vertex_copy,
13418 clutter_vertex_free,
13419 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13422 * clutter_actor_is_rotated:
13423 * @self: a #ClutterActor
13425 * Checks whether any rotation is applied to the actor.
13427 * Return value: %TRUE if the actor is rotated.
13432 clutter_actor_is_rotated (ClutterActor *self)
13434 const ClutterTransformInfo *info;
13436 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13438 info = _clutter_actor_get_transform_info_or_defaults (self);
13440 if (info->rx_angle || info->ry_angle || info->rz_angle)
13447 * clutter_actor_is_scaled:
13448 * @self: a #ClutterActor
13450 * Checks whether the actor is scaled in either dimension.
13452 * Return value: %TRUE if the actor is scaled.
13457 clutter_actor_is_scaled (ClutterActor *self)
13459 const ClutterTransformInfo *info;
13461 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13463 info = _clutter_actor_get_transform_info_or_defaults (self);
13465 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13472 _clutter_actor_get_stage_internal (ClutterActor *actor)
13474 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13475 actor = actor->priv->parent;
13481 * clutter_actor_get_stage:
13482 * @actor: a #ClutterActor
13484 * Retrieves the #ClutterStage where @actor is contained.
13486 * Return value: (transfer none) (type Clutter.Stage): the stage
13487 * containing the actor, or %NULL
13492 clutter_actor_get_stage (ClutterActor *actor)
13494 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13496 return _clutter_actor_get_stage_internal (actor);
13500 * clutter_actor_allocate_available_size:
13501 * @self: a #ClutterActor
13502 * @x: the actor's X coordinate
13503 * @y: the actor's Y coordinate
13504 * @available_width: the maximum available width, or -1 to use the
13505 * actor's natural width
13506 * @available_height: the maximum available height, or -1 to use the
13507 * actor's natural height
13508 * @flags: flags controlling the allocation
13510 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13511 * preferred size, but limiting it to the maximum available width
13512 * and height provided.
13514 * This function will do the right thing when dealing with the
13515 * actor's request mode.
13517 * The implementation of this function is equivalent to:
13520 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13522 * clutter_actor_get_preferred_width (self, available_height,
13524 * &natural_width);
13525 * width = CLAMP (natural_width, min_width, available_width);
13527 * clutter_actor_get_preferred_height (self, width,
13529 * &natural_height);
13530 * height = CLAMP (natural_height, min_height, available_height);
13534 * clutter_actor_get_preferred_height (self, available_width,
13536 * &natural_height);
13537 * height = CLAMP (natural_height, min_height, available_height);
13539 * clutter_actor_get_preferred_width (self, height,
13541 * &natural_width);
13542 * width = CLAMP (natural_width, min_width, available_width);
13545 * box.x1 = x; box.y1 = y;
13546 * box.x2 = box.x1 + available_width;
13547 * box.y2 = box.y1 + available_height;
13548 * clutter_actor_allocate (self, &box, flags);
13551 * This function can be used by fluid layout managers to allocate
13552 * an actor's preferred size without making it bigger than the area
13553 * available for the container.
13558 clutter_actor_allocate_available_size (ClutterActor *self,
13561 gfloat available_width,
13562 gfloat available_height,
13563 ClutterAllocationFlags flags)
13565 ClutterActorPrivate *priv;
13566 gfloat width, height;
13567 gfloat min_width, min_height;
13568 gfloat natural_width, natural_height;
13569 ClutterActorBox box;
13571 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13575 width = height = 0.0;
13577 switch (priv->request_mode)
13579 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13580 clutter_actor_get_preferred_width (self, available_height,
13583 width = CLAMP (natural_width, min_width, available_width);
13585 clutter_actor_get_preferred_height (self, width,
13588 height = CLAMP (natural_height, min_height, available_height);
13591 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13592 clutter_actor_get_preferred_height (self, available_width,
13595 height = CLAMP (natural_height, min_height, available_height);
13597 clutter_actor_get_preferred_width (self, height,
13600 width = CLAMP (natural_width, min_width, available_width);
13607 box.x2 = box.x1 + width;
13608 box.y2 = box.y1 + height;
13609 clutter_actor_allocate (self, &box, flags);
13613 * clutter_actor_allocate_preferred_size:
13614 * @self: a #ClutterActor
13615 * @flags: flags controlling the allocation
13617 * Allocates the natural size of @self.
13619 * This function is a utility call for #ClutterActor implementations
13620 * that allocates the actor's preferred natural size. It can be used
13621 * by fixed layout managers (like #ClutterGroup or so called
13622 * 'composite actors') inside the ClutterActor::allocate
13623 * implementation to give each child exactly how much space it
13626 * This function is not meant to be used by applications. It is also
13627 * not meant to be used outside the implementation of the
13628 * ClutterActor::allocate virtual function.
13633 clutter_actor_allocate_preferred_size (ClutterActor *self,
13634 ClutterAllocationFlags flags)
13636 gfloat actor_x, actor_y;
13637 gfloat natural_width, natural_height;
13638 ClutterActorBox actor_box;
13640 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13642 actor_x = clutter_actor_get_x (self);
13643 actor_y = clutter_actor_get_y (self);
13645 clutter_actor_get_preferred_size (self,
13650 actor_box.x1 = actor_x;
13651 actor_box.y1 = actor_y;
13652 actor_box.x2 = actor_box.x1 + natural_width;
13653 actor_box.y2 = actor_box.y1 + natural_height;
13655 clutter_actor_allocate (self, &actor_box, flags);
13659 * clutter_actor_allocate_align_fill:
13660 * @self: a #ClutterActor
13661 * @box: a #ClutterActorBox, containing the available width and height
13662 * @x_align: the horizontal alignment, between 0 and 1
13663 * @y_align: the vertical alignment, between 0 and 1
13664 * @x_fill: whether the actor should fill horizontally
13665 * @y_fill: whether the actor should fill vertically
13666 * @flags: allocation flags to be passed to clutter_actor_allocate()
13668 * Allocates @self by taking into consideration the available allocation
13669 * area; an alignment factor on either axis; and whether the actor should
13670 * fill the allocation on either axis.
13672 * The @box should contain the available allocation width and height;
13673 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13674 * allocation will be offset by their value.
13676 * This function takes into consideration the geometry request specified by
13677 * the #ClutterActor:request-mode property, and the text direction.
13679 * This function is useful for fluid layout managers, like #ClutterBinLayout
13680 * or #ClutterTableLayout
13685 clutter_actor_allocate_align_fill (ClutterActor *self,
13686 const ClutterActorBox *box,
13691 ClutterAllocationFlags flags)
13693 ClutterActorPrivate *priv;
13694 ClutterActorBox allocation = { 0, };
13695 gfloat x_offset, y_offset;
13696 gfloat available_width, available_height;
13697 gfloat child_width, child_height;
13699 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13700 g_return_if_fail (box != NULL);
13701 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13702 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13706 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13707 clutter_actor_box_get_size (box, &available_width, &available_height);
13709 if (available_width < 0)
13710 available_width = 0;
13712 if (available_height < 0)
13713 available_height = 0;
13717 allocation.x1 = x_offset;
13718 allocation.x2 = allocation.x1 + available_width;
13723 allocation.y1 = y_offset;
13724 allocation.y2 = allocation.y1 + available_height;
13727 /* if we are filling horizontally and vertically then we're done */
13728 if (x_fill && y_fill)
13731 child_width = child_height = 0.0f;
13733 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13735 gfloat min_width, natural_width;
13736 gfloat min_height, natural_height;
13738 clutter_actor_get_preferred_width (self, available_height,
13742 child_width = CLAMP (natural_width, min_width, available_width);
13746 clutter_actor_get_preferred_height (self, child_width,
13750 child_height = CLAMP (natural_height, min_height, available_height);
13755 gfloat min_width, natural_width;
13756 gfloat min_height, natural_height;
13758 clutter_actor_get_preferred_height (self, available_width,
13762 child_height = CLAMP (natural_height, min_height, available_height);
13766 clutter_actor_get_preferred_width (self, child_height,
13770 child_width = CLAMP (natural_width, min_width, available_width);
13774 /* invert the horizontal alignment for RTL languages */
13775 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13776 x_align = 1.0 - x_align;
13780 allocation.x1 = x_offset
13781 + ((available_width - child_width) * x_align);
13782 allocation.x2 = allocation.x1 + child_width;
13787 allocation.y1 = y_offset
13788 + ((available_height - child_height) * y_align);
13789 allocation.y2 = allocation.y1 + child_height;
13793 clutter_actor_box_clamp_to_pixel (&allocation);
13794 clutter_actor_allocate (self, &allocation, flags);
13798 * clutter_actor_grab_key_focus:
13799 * @self: a #ClutterActor
13801 * Sets the key focus of the #ClutterStage including @self
13802 * to this #ClutterActor.
13807 clutter_actor_grab_key_focus (ClutterActor *self)
13809 ClutterActor *stage;
13811 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13813 stage = _clutter_actor_get_stage_internal (self);
13815 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13819 * clutter_actor_get_pango_context:
13820 * @self: a #ClutterActor
13822 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13823 * is already configured using the appropriate font map, resolution
13824 * and font options.
13826 * Unlike clutter_actor_create_pango_context(), this context is owend
13827 * by the #ClutterActor and it will be updated each time the options
13828 * stored by the #ClutterBackend change.
13830 * You can use the returned #PangoContext to create a #PangoLayout
13831 * and render text using cogl_pango_render_layout() to reuse the
13832 * glyphs cache also used by Clutter.
13834 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13835 * The returned #PangoContext is owned by the actor and should not be
13836 * unreferenced by the application code
13841 clutter_actor_get_pango_context (ClutterActor *self)
13843 ClutterActorPrivate *priv;
13845 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13849 if (priv->pango_context != NULL)
13850 return priv->pango_context;
13852 priv->pango_context = _clutter_context_get_pango_context ();
13853 g_object_ref (priv->pango_context);
13855 return priv->pango_context;
13859 * clutter_actor_create_pango_context:
13860 * @self: a #ClutterActor
13862 * Creates a #PangoContext for the given actor. The #PangoContext
13863 * is already configured using the appropriate font map, resolution
13864 * and font options.
13866 * See also clutter_actor_get_pango_context().
13868 * Return value: (transfer full): the newly created #PangoContext.
13869 * Use g_object_unref() on the returned value to deallocate its
13875 clutter_actor_create_pango_context (ClutterActor *self)
13877 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13879 return _clutter_context_create_pango_context ();
13883 * clutter_actor_create_pango_layout:
13884 * @self: a #ClutterActor
13885 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13887 * Creates a new #PangoLayout from the same #PangoContext used
13888 * by the #ClutterActor. The #PangoLayout is already configured
13889 * with the font map, resolution and font options, and the
13892 * If you want to keep around a #PangoLayout created by this
13893 * function you will have to connect to the #ClutterBackend::font-changed
13894 * and #ClutterBackend::resolution-changed signals, and call
13895 * pango_layout_context_changed() in response to them.
13897 * Return value: (transfer full): the newly created #PangoLayout.
13898 * Use g_object_unref() when done
13903 clutter_actor_create_pango_layout (ClutterActor *self,
13906 PangoContext *context;
13907 PangoLayout *layout;
13909 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13911 context = clutter_actor_get_pango_context (self);
13912 layout = pango_layout_new (context);
13915 pango_layout_set_text (layout, text, -1);
13920 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13921 * ClutterOffscreenEffect.
13924 _clutter_actor_set_opacity_override (ClutterActor *self,
13927 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13929 self->priv->opacity_override = opacity;
13933 _clutter_actor_get_opacity_override (ClutterActor *self)
13935 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13937 return self->priv->opacity_override;
13940 /* Allows you to disable applying the actors model view transform during
13941 * a paint. Used by ClutterClone. */
13943 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13946 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13948 self->priv->enable_model_view_transform = enable;
13952 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13955 ClutterActorPrivate *priv;
13957 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13961 priv->enable_paint_unmapped = enable;
13963 if (priv->enable_paint_unmapped)
13965 /* Make sure that the parents of the widget are realized first;
13966 * otherwise checks in clutter_actor_update_map_state() will
13969 clutter_actor_realize (self);
13971 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13975 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13980 clutter_anchor_coord_get_units (ClutterActor *self,
13981 const AnchorCoord *coord,
13986 if (coord->is_fractional)
13988 gfloat actor_width, actor_height;
13990 clutter_actor_get_size (self, &actor_width, &actor_height);
13993 *x = actor_width * coord->v.fraction.x;
13996 *y = actor_height * coord->v.fraction.y;
14004 *x = coord->v.units.x;
14007 *y = coord->v.units.y;
14010 *z = coord->v.units.z;
14015 clutter_anchor_coord_set_units (AnchorCoord *coord,
14020 coord->is_fractional = FALSE;
14021 coord->v.units.x = x;
14022 coord->v.units.y = y;
14023 coord->v.units.z = z;
14026 static ClutterGravity
14027 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14029 if (coord->is_fractional)
14031 if (coord->v.fraction.x == 0.0)
14033 if (coord->v.fraction.y == 0.0)
14034 return CLUTTER_GRAVITY_NORTH_WEST;
14035 else if (coord->v.fraction.y == 0.5)
14036 return CLUTTER_GRAVITY_WEST;
14037 else if (coord->v.fraction.y == 1.0)
14038 return CLUTTER_GRAVITY_SOUTH_WEST;
14040 return CLUTTER_GRAVITY_NONE;
14042 else if (coord->v.fraction.x == 0.5)
14044 if (coord->v.fraction.y == 0.0)
14045 return CLUTTER_GRAVITY_NORTH;
14046 else if (coord->v.fraction.y == 0.5)
14047 return CLUTTER_GRAVITY_CENTER;
14048 else if (coord->v.fraction.y == 1.0)
14049 return CLUTTER_GRAVITY_SOUTH;
14051 return CLUTTER_GRAVITY_NONE;
14053 else if (coord->v.fraction.x == 1.0)
14055 if (coord->v.fraction.y == 0.0)
14056 return CLUTTER_GRAVITY_NORTH_EAST;
14057 else if (coord->v.fraction.y == 0.5)
14058 return CLUTTER_GRAVITY_EAST;
14059 else if (coord->v.fraction.y == 1.0)
14060 return CLUTTER_GRAVITY_SOUTH_EAST;
14062 return CLUTTER_GRAVITY_NONE;
14065 return CLUTTER_GRAVITY_NONE;
14068 return CLUTTER_GRAVITY_NONE;
14072 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14073 ClutterGravity gravity)
14077 case CLUTTER_GRAVITY_NORTH:
14078 coord->v.fraction.x = 0.5;
14079 coord->v.fraction.y = 0.0;
14082 case CLUTTER_GRAVITY_NORTH_EAST:
14083 coord->v.fraction.x = 1.0;
14084 coord->v.fraction.y = 0.0;
14087 case CLUTTER_GRAVITY_EAST:
14088 coord->v.fraction.x = 1.0;
14089 coord->v.fraction.y = 0.5;
14092 case CLUTTER_GRAVITY_SOUTH_EAST:
14093 coord->v.fraction.x = 1.0;
14094 coord->v.fraction.y = 1.0;
14097 case CLUTTER_GRAVITY_SOUTH:
14098 coord->v.fraction.x = 0.5;
14099 coord->v.fraction.y = 1.0;
14102 case CLUTTER_GRAVITY_SOUTH_WEST:
14103 coord->v.fraction.x = 0.0;
14104 coord->v.fraction.y = 1.0;
14107 case CLUTTER_GRAVITY_WEST:
14108 coord->v.fraction.x = 0.0;
14109 coord->v.fraction.y = 0.5;
14112 case CLUTTER_GRAVITY_NORTH_WEST:
14113 coord->v.fraction.x = 0.0;
14114 coord->v.fraction.y = 0.0;
14117 case CLUTTER_GRAVITY_CENTER:
14118 coord->v.fraction.x = 0.5;
14119 coord->v.fraction.y = 0.5;
14123 coord->v.fraction.x = 0.0;
14124 coord->v.fraction.y = 0.0;
14128 coord->is_fractional = TRUE;
14132 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14134 if (coord->is_fractional)
14135 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14137 return (coord->v.units.x == 0.0
14138 && coord->v.units.y == 0.0
14139 && coord->v.units.z == 0.0);
14143 * clutter_actor_get_flags:
14144 * @self: a #ClutterActor
14146 * Retrieves the flags set on @self
14148 * Return value: a bitwise or of #ClutterActorFlags or 0
14153 clutter_actor_get_flags (ClutterActor *self)
14155 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14157 return self->flags;
14161 * clutter_actor_set_flags:
14162 * @self: a #ClutterActor
14163 * @flags: the flags to set
14165 * Sets @flags on @self
14167 * This function will emit notifications for the changed properties
14172 clutter_actor_set_flags (ClutterActor *self,
14173 ClutterActorFlags flags)
14175 ClutterActorFlags old_flags;
14177 gboolean was_reactive_set, reactive_set;
14178 gboolean was_realized_set, realized_set;
14179 gboolean was_mapped_set, mapped_set;
14180 gboolean was_visible_set, visible_set;
14182 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14184 if (self->flags == flags)
14187 obj = G_OBJECT (self);
14188 g_object_ref (obj);
14189 g_object_freeze_notify (obj);
14191 old_flags = self->flags;
14193 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14194 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14195 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14196 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14198 self->flags |= flags;
14200 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14201 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14202 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14203 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14205 if (reactive_set != was_reactive_set)
14206 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14208 if (realized_set != was_realized_set)
14209 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14211 if (mapped_set != was_mapped_set)
14212 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14214 if (visible_set != was_visible_set)
14215 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14217 g_object_thaw_notify (obj);
14218 g_object_unref (obj);
14222 * clutter_actor_unset_flags:
14223 * @self: a #ClutterActor
14224 * @flags: the flags to unset
14226 * Unsets @flags on @self
14228 * This function will emit notifications for the changed properties
14233 clutter_actor_unset_flags (ClutterActor *self,
14234 ClutterActorFlags flags)
14236 ClutterActorFlags old_flags;
14238 gboolean was_reactive_set, reactive_set;
14239 gboolean was_realized_set, realized_set;
14240 gboolean was_mapped_set, mapped_set;
14241 gboolean was_visible_set, visible_set;
14243 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14245 obj = G_OBJECT (self);
14246 g_object_freeze_notify (obj);
14248 old_flags = self->flags;
14250 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14251 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14252 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14253 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14255 self->flags &= ~flags;
14257 if (self->flags == old_flags)
14260 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14261 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14262 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14263 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14265 if (reactive_set != was_reactive_set)
14266 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14268 if (realized_set != was_realized_set)
14269 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14271 if (mapped_set != was_mapped_set)
14272 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14274 if (visible_set != was_visible_set)
14275 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14277 g_object_thaw_notify (obj);
14281 * clutter_actor_get_transformation_matrix:
14282 * @self: a #ClutterActor
14283 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14285 * Retrieves the transformations applied to @self relative to its
14291 clutter_actor_get_transformation_matrix (ClutterActor *self,
14292 CoglMatrix *matrix)
14294 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14296 cogl_matrix_init_identity (matrix);
14298 _clutter_actor_apply_modelview_transform (self, matrix);
14302 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14303 gboolean is_in_clone_paint)
14305 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14306 self->priv->in_clone_paint = is_in_clone_paint;
14310 * clutter_actor_is_in_clone_paint:
14311 * @self: a #ClutterActor
14313 * Checks whether @self is being currently painted by a #ClutterClone
14315 * This function is useful only inside the ::paint virtual function
14316 * implementations or within handlers for the #ClutterActor::paint
14319 * This function should not be used by applications
14321 * Return value: %TRUE if the #ClutterActor is currently being painted
14322 * by a #ClutterClone, and %FALSE otherwise
14327 clutter_actor_is_in_clone_paint (ClutterActor *self)
14329 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14331 return self->priv->in_clone_paint;
14335 set_direction_recursive (ClutterActor *actor,
14336 gpointer user_data)
14338 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14340 clutter_actor_set_text_direction (actor, text_dir);
14346 * clutter_actor_set_text_direction:
14347 * @self: a #ClutterActor
14348 * @text_dir: the text direction for @self
14350 * Sets the #ClutterTextDirection for an actor
14352 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14354 * If @self implements #ClutterContainer then this function will recurse
14355 * inside all the children of @self (including the internal ones).
14357 * Composite actors not implementing #ClutterContainer, or actors requiring
14358 * special handling when the text direction changes, should connect to
14359 * the #GObject::notify signal for the #ClutterActor:text-direction property
14364 clutter_actor_set_text_direction (ClutterActor *self,
14365 ClutterTextDirection text_dir)
14367 ClutterActorPrivate *priv;
14369 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14370 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14374 if (priv->text_direction != text_dir)
14376 priv->text_direction = text_dir;
14378 /* we need to emit the notify::text-direction first, so that
14379 * the sub-classes can catch that and do specific handling of
14380 * the text direction; see clutter_text_direction_changed_cb()
14381 * inside clutter-text.c
14383 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14385 _clutter_actor_foreach_child (self, set_direction_recursive,
14386 GINT_TO_POINTER (text_dir));
14388 clutter_actor_queue_relayout (self);
14393 _clutter_actor_set_has_pointer (ClutterActor *self,
14394 gboolean has_pointer)
14396 ClutterActorPrivate *priv = self->priv;
14398 if (priv->has_pointer != has_pointer)
14400 priv->has_pointer = has_pointer;
14402 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14407 * clutter_actor_get_text_direction:
14408 * @self: a #ClutterActor
14410 * Retrieves the value set using clutter_actor_set_text_direction()
14412 * If no text direction has been previously set, the default text
14413 * direction, as returned by clutter_get_default_text_direction(), will
14414 * be returned instead
14416 * Return value: the #ClutterTextDirection for the actor
14420 ClutterTextDirection
14421 clutter_actor_get_text_direction (ClutterActor *self)
14423 ClutterActorPrivate *priv;
14425 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14426 CLUTTER_TEXT_DIRECTION_LTR);
14430 /* if no direction has been set yet use the default */
14431 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14432 priv->text_direction = clutter_get_default_text_direction ();
14434 return priv->text_direction;
14438 * clutter_actor_push_internal:
14439 * @self: a #ClutterActor
14441 * Should be used by actors implementing the #ClutterContainer and with
14442 * internal children added through clutter_actor_set_parent(), for instance:
14446 * my_actor_init (MyActor *self)
14448 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14450 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14452 * /* calling clutter_actor_set_parent() now will result in
14453 * * the internal flag being set on a child of MyActor
14456 * /* internal child - a background texture */
14457 * self->priv->background_tex = clutter_texture_new ();
14458 * clutter_actor_set_parent (self->priv->background_tex,
14459 * CLUTTER_ACTOR (self));
14461 * /* internal child - a label */
14462 * self->priv->label = clutter_text_new ();
14463 * clutter_actor_set_parent (self->priv->label,
14464 * CLUTTER_ACTOR (self));
14466 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14468 * /* calling clutter_actor_set_parent() now will not result in
14469 * * the internal flag being set on a child of MyActor
14474 * This function will be used by Clutter to toggle an "internal child"
14475 * flag whenever clutter_actor_set_parent() is called; internal children
14476 * are handled differently by Clutter, specifically when destroying their
14479 * Call clutter_actor_pop_internal() when you finished adding internal
14482 * Nested calls to clutter_actor_push_internal() are allowed, but each
14483 * one must by followed by a clutter_actor_pop_internal() call.
14487 * Deprecated: 1.10: All children of an actor are accessible through
14488 * the #ClutterActor API, and #ClutterActor implements the
14489 * #ClutterContainer interface, so this function is only useful
14490 * for legacy containers overriding the default implementation.
14493 clutter_actor_push_internal (ClutterActor *self)
14495 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14497 self->priv->internal_child += 1;
14501 * clutter_actor_pop_internal:
14502 * @self: a #ClutterActor
14504 * Disables the effects of clutter_actor_push_internal().
14508 * Deprecated: 1.10: All children of an actor are accessible through
14509 * the #ClutterActor API. This function is only useful for legacy
14510 * containers overriding the default implementation of the
14511 * #ClutterContainer interface.
14514 clutter_actor_pop_internal (ClutterActor *self)
14516 ClutterActorPrivate *priv;
14518 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14522 if (priv->internal_child == 0)
14524 g_warning ("Mismatched %s: you need to call "
14525 "clutter_actor_push_composite() at least once before "
14526 "calling this function", G_STRFUNC);
14530 priv->internal_child -= 1;
14534 * clutter_actor_has_pointer:
14535 * @self: a #ClutterActor
14537 * Checks whether an actor contains the pointer of a
14538 * #ClutterInputDevice
14540 * Return value: %TRUE if the actor contains the pointer, and
14546 clutter_actor_has_pointer (ClutterActor *self)
14548 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14550 return self->priv->has_pointer;
14553 /* XXX: This is a workaround for not being able to break the ABI of
14554 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14555 * clutter_actor_queue_clipped_redraw() for details.
14557 ClutterPaintVolume *
14558 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14560 return g_object_get_data (G_OBJECT (self),
14561 "-clutter-actor-queue-redraw-clip");
14565 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14566 ClutterPaintVolume *clip)
14568 g_object_set_data (G_OBJECT (self),
14569 "-clutter-actor-queue-redraw-clip",
14574 * clutter_actor_has_allocation:
14575 * @self: a #ClutterActor
14577 * Checks if the actor has an up-to-date allocation assigned to
14578 * it. This means that the actor should have an allocation: it's
14579 * visible and has a parent. It also means that there is no
14580 * outstanding relayout request in progress for the actor or its
14581 * children (There might be other outstanding layout requests in
14582 * progress that will cause the actor to get a new allocation
14583 * when the stage is laid out, however).
14585 * If this function returns %FALSE, then the actor will normally
14586 * be allocated before it is next drawn on the screen.
14588 * Return value: %TRUE if the actor has an up-to-date allocation
14593 clutter_actor_has_allocation (ClutterActor *self)
14595 ClutterActorPrivate *priv;
14597 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14601 return priv->parent != NULL &&
14602 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14603 !priv->needs_allocation;
14607 * clutter_actor_add_action:
14608 * @self: a #ClutterActor
14609 * @action: a #ClutterAction
14611 * Adds @action to the list of actions applied to @self
14613 * A #ClutterAction can only belong to one actor at a time
14615 * The #ClutterActor will hold a reference on @action until either
14616 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14622 clutter_actor_add_action (ClutterActor *self,
14623 ClutterAction *action)
14625 ClutterActorPrivate *priv;
14627 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14628 g_return_if_fail (CLUTTER_IS_ACTION (action));
14632 if (priv->actions == NULL)
14634 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14635 priv->actions->actor = self;
14638 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14640 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14644 * clutter_actor_add_action_with_name:
14645 * @self: a #ClutterActor
14646 * @name: the name to set on the action
14647 * @action: a #ClutterAction
14649 * A convenience function for setting the name of a #ClutterAction
14650 * while adding it to the list of actions applied to @self
14652 * This function is the logical equivalent of:
14655 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14656 * clutter_actor_add_action (self, action);
14662 clutter_actor_add_action_with_name (ClutterActor *self,
14664 ClutterAction *action)
14666 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14667 g_return_if_fail (name != NULL);
14668 g_return_if_fail (CLUTTER_IS_ACTION (action));
14670 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14671 clutter_actor_add_action (self, action);
14675 * clutter_actor_remove_action:
14676 * @self: a #ClutterActor
14677 * @action: a #ClutterAction
14679 * Removes @action from the list of actions applied to @self
14681 * The reference held by @self on the #ClutterAction will be released
14686 clutter_actor_remove_action (ClutterActor *self,
14687 ClutterAction *action)
14689 ClutterActorPrivate *priv;
14691 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14692 g_return_if_fail (CLUTTER_IS_ACTION (action));
14696 if (priv->actions == NULL)
14699 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14701 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14705 * clutter_actor_remove_action_by_name:
14706 * @self: a #ClutterActor
14707 * @name: the name of the action to remove
14709 * Removes the #ClutterAction with the given name from the list
14710 * of actions applied to @self
14715 clutter_actor_remove_action_by_name (ClutterActor *self,
14718 ClutterActorPrivate *priv;
14719 ClutterActorMeta *meta;
14721 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14722 g_return_if_fail (name != NULL);
14726 if (priv->actions == NULL)
14729 meta = _clutter_meta_group_get_meta (priv->actions, name);
14733 _clutter_meta_group_remove_meta (priv->actions, meta);
14735 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14739 * clutter_actor_get_actions:
14740 * @self: a #ClutterActor
14742 * Retrieves the list of actions applied to @self
14744 * Return value: (transfer container) (element-type Clutter.Action): a copy
14745 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14746 * owned by the #ClutterActor. Use g_list_free() to free the resources
14747 * allocated by the returned #GList
14752 clutter_actor_get_actions (ClutterActor *self)
14754 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14756 if (self->priv->actions == NULL)
14759 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14763 * clutter_actor_get_action:
14764 * @self: a #ClutterActor
14765 * @name: the name of the action to retrieve
14767 * Retrieves the #ClutterAction with the given name in the list
14768 * of actions applied to @self
14770 * Return value: (transfer none): a #ClutterAction for the given
14771 * name, or %NULL. The returned #ClutterAction is owned by the
14772 * actor and it should not be unreferenced directly
14777 clutter_actor_get_action (ClutterActor *self,
14780 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14781 g_return_val_if_fail (name != NULL, NULL);
14783 if (self->priv->actions == NULL)
14786 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14790 * clutter_actor_clear_actions:
14791 * @self: a #ClutterActor
14793 * Clears the list of actions applied to @self
14798 clutter_actor_clear_actions (ClutterActor *self)
14800 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14802 if (self->priv->actions == NULL)
14805 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14809 * clutter_actor_add_constraint:
14810 * @self: a #ClutterActor
14811 * @constraint: a #ClutterConstraint
14813 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14816 * The #ClutterActor will hold a reference on the @constraint until
14817 * either clutter_actor_remove_constraint() or
14818 * clutter_actor_clear_constraints() is called.
14823 clutter_actor_add_constraint (ClutterActor *self,
14824 ClutterConstraint *constraint)
14826 ClutterActorPrivate *priv;
14828 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14829 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14833 if (priv->constraints == NULL)
14835 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14836 priv->constraints->actor = self;
14839 _clutter_meta_group_add_meta (priv->constraints,
14840 CLUTTER_ACTOR_META (constraint));
14841 clutter_actor_queue_relayout (self);
14843 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14847 * clutter_actor_add_constraint_with_name:
14848 * @self: a #ClutterActor
14849 * @name: the name to set on the constraint
14850 * @constraint: a #ClutterConstraint
14852 * A convenience function for setting the name of a #ClutterConstraint
14853 * while adding it to the list of constraints applied to @self
14855 * This function is the logical equivalent of:
14858 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14859 * clutter_actor_add_constraint (self, constraint);
14865 clutter_actor_add_constraint_with_name (ClutterActor *self,
14867 ClutterConstraint *constraint)
14869 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14870 g_return_if_fail (name != NULL);
14871 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14873 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14874 clutter_actor_add_constraint (self, constraint);
14878 * clutter_actor_remove_constraint:
14879 * @self: a #ClutterActor
14880 * @constraint: a #ClutterConstraint
14882 * Removes @constraint from the list of constraints applied to @self
14884 * The reference held by @self on the #ClutterConstraint will be released
14889 clutter_actor_remove_constraint (ClutterActor *self,
14890 ClutterConstraint *constraint)
14892 ClutterActorPrivate *priv;
14894 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14895 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14899 if (priv->constraints == NULL)
14902 _clutter_meta_group_remove_meta (priv->constraints,
14903 CLUTTER_ACTOR_META (constraint));
14904 clutter_actor_queue_relayout (self);
14906 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14910 * clutter_actor_remove_constraint_by_name:
14911 * @self: a #ClutterActor
14912 * @name: the name of the constraint to remove
14914 * Removes the #ClutterConstraint with the given name from the list
14915 * of constraints applied to @self
14920 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14923 ClutterActorPrivate *priv;
14924 ClutterActorMeta *meta;
14926 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14927 g_return_if_fail (name != NULL);
14931 if (priv->constraints == NULL)
14934 meta = _clutter_meta_group_get_meta (priv->constraints, name);
14938 _clutter_meta_group_remove_meta (priv->constraints, meta);
14939 clutter_actor_queue_relayout (self);
14943 * clutter_actor_get_constraints:
14944 * @self: a #ClutterActor
14946 * Retrieves the list of constraints applied to @self
14948 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14949 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14950 * owned by the #ClutterActor. Use g_list_free() to free the resources
14951 * allocated by the returned #GList
14956 clutter_actor_get_constraints (ClutterActor *self)
14958 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14960 if (self->priv->constraints == NULL)
14963 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14967 * clutter_actor_get_constraint:
14968 * @self: a #ClutterActor
14969 * @name: the name of the constraint to retrieve
14971 * Retrieves the #ClutterConstraint with the given name in the list
14972 * of constraints applied to @self
14974 * Return value: (transfer none): a #ClutterConstraint for the given
14975 * name, or %NULL. The returned #ClutterConstraint is owned by the
14976 * actor and it should not be unreferenced directly
14980 ClutterConstraint *
14981 clutter_actor_get_constraint (ClutterActor *self,
14984 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14985 g_return_val_if_fail (name != NULL, NULL);
14987 if (self->priv->constraints == NULL)
14990 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14994 * clutter_actor_clear_constraints:
14995 * @self: a #ClutterActor
14997 * Clears the list of constraints applied to @self
15002 clutter_actor_clear_constraints (ClutterActor *self)
15004 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15006 if (self->priv->constraints == NULL)
15009 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15011 clutter_actor_queue_relayout (self);
15015 * clutter_actor_set_clip_to_allocation:
15016 * @self: a #ClutterActor
15017 * @clip_set: %TRUE to apply a clip tracking the allocation
15019 * Sets whether @self should be clipped to the same size as its
15025 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15028 ClutterActorPrivate *priv;
15030 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15032 clip_set = !!clip_set;
15036 if (priv->clip_to_allocation != clip_set)
15038 priv->clip_to_allocation = clip_set;
15040 clutter_actor_queue_redraw (self);
15042 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15047 * clutter_actor_get_clip_to_allocation:
15048 * @self: a #ClutterActor
15050 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15052 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15057 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15059 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15061 return self->priv->clip_to_allocation;
15065 * clutter_actor_add_effect:
15066 * @self: a #ClutterActor
15067 * @effect: a #ClutterEffect
15069 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15071 * The #ClutterActor will hold a reference on the @effect until either
15072 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15078 clutter_actor_add_effect (ClutterActor *self,
15079 ClutterEffect *effect)
15081 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15082 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15084 _clutter_actor_add_effect_internal (self, effect);
15086 clutter_actor_queue_redraw (self);
15088 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15092 * clutter_actor_add_effect_with_name:
15093 * @self: a #ClutterActor
15094 * @name: the name to set on the effect
15095 * @effect: a #ClutterEffect
15097 * A convenience function for setting the name of a #ClutterEffect
15098 * while adding it to the list of effectss applied to @self
15100 * This function is the logical equivalent of:
15103 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15104 * clutter_actor_add_effect (self, effect);
15110 clutter_actor_add_effect_with_name (ClutterActor *self,
15112 ClutterEffect *effect)
15114 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15115 g_return_if_fail (name != NULL);
15116 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15118 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15119 clutter_actor_add_effect (self, effect);
15123 * clutter_actor_remove_effect:
15124 * @self: a #ClutterActor
15125 * @effect: a #ClutterEffect
15127 * Removes @effect from the list of effects applied to @self
15129 * The reference held by @self on the #ClutterEffect will be released
15134 clutter_actor_remove_effect (ClutterActor *self,
15135 ClutterEffect *effect)
15137 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15138 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15140 _clutter_actor_remove_effect_internal (self, effect);
15142 clutter_actor_queue_redraw (self);
15144 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15148 * clutter_actor_remove_effect_by_name:
15149 * @self: a #ClutterActor
15150 * @name: the name of the effect to remove
15152 * Removes the #ClutterEffect with the given name from the list
15153 * of effects applied to @self
15158 clutter_actor_remove_effect_by_name (ClutterActor *self,
15161 ClutterActorPrivate *priv;
15162 ClutterActorMeta *meta;
15164 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15165 g_return_if_fail (name != NULL);
15169 if (priv->effects == NULL)
15172 meta = _clutter_meta_group_get_meta (priv->effects, name);
15176 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15180 * clutter_actor_get_effects:
15181 * @self: a #ClutterActor
15183 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15185 * Return value: (transfer container) (element-type Clutter.Effect): a list
15186 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15187 * list are owned by Clutter and they should not be freed. You should
15188 * free the returned list using g_list_free() when done
15193 clutter_actor_get_effects (ClutterActor *self)
15195 ClutterActorPrivate *priv;
15197 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15201 if (priv->effects == NULL)
15204 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15208 * clutter_actor_get_effect:
15209 * @self: a #ClutterActor
15210 * @name: the name of the effect to retrieve
15212 * Retrieves the #ClutterEffect with the given name in the list
15213 * of effects applied to @self
15215 * Return value: (transfer none): a #ClutterEffect for the given
15216 * name, or %NULL. The returned #ClutterEffect is owned by the
15217 * actor and it should not be unreferenced directly
15222 clutter_actor_get_effect (ClutterActor *self,
15225 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15226 g_return_val_if_fail (name != NULL, NULL);
15228 if (self->priv->effects == NULL)
15231 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15235 * clutter_actor_clear_effects:
15236 * @self: a #ClutterActor
15238 * Clears the list of effects applied to @self
15243 clutter_actor_clear_effects (ClutterActor *self)
15245 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15247 if (self->priv->effects == NULL)
15250 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15252 clutter_actor_queue_redraw (self);
15256 * clutter_actor_has_key_focus:
15257 * @self: a #ClutterActor
15259 * Checks whether @self is the #ClutterActor that has key focus
15261 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15266 clutter_actor_has_key_focus (ClutterActor *self)
15268 ClutterActor *stage;
15270 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15272 stage = _clutter_actor_get_stage_internal (self);
15276 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15280 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15281 ClutterPaintVolume *pv)
15283 ClutterActorPrivate *priv = self->priv;
15285 /* Actors are only expected to report a valid paint volume
15286 * while they have a valid allocation. */
15287 if (G_UNLIKELY (priv->needs_allocation))
15289 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15290 "Actor needs allocation",
15291 _clutter_actor_get_debug_name (self));
15295 /* Check if there are any handlers connected to the paint
15296 * signal. If there are then all bets are off for what the paint
15297 * volume for this actor might possibly be!
15299 * XXX: It's expected that this is going to end up being quite a
15300 * costly check to have to do here, but we haven't come up with
15301 * another solution that can reliably catch paint signal handlers at
15302 * the right time to either avoid artefacts due to invalid stage
15303 * clipping or due to incorrect culling.
15305 * Previously we checked in clutter_actor_paint(), but at that time
15306 * we may already be using a stage clip that could be derived from
15307 * an invalid paint-volume. We used to try and handle that by
15308 * queuing a follow up, unclipped, redraw but still the previous
15309 * checking wasn't enough to catch invalid volumes involved in
15310 * culling (considering that containers may derive their volume from
15311 * children that haven't yet been painted)
15313 * Longer term, improved solutions could be:
15314 * - Disallow painting in the paint signal, only allow using it
15315 * for tracking when paints happen. We can add another API that
15316 * allows monkey patching the paint of arbitrary actors but in a
15317 * more controlled way and that also supports modifying the
15319 * - If we could be notified somehow when signal handlers are
15320 * connected we wouldn't have to poll for handlers like this.
15322 if (g_signal_has_handler_pending (self,
15323 actor_signals[PAINT],
15327 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15328 "Actor has \"paint\" signal handlers",
15329 _clutter_actor_get_debug_name (self));
15333 _clutter_paint_volume_init_static (pv, self);
15335 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15337 clutter_paint_volume_free (pv);
15338 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15339 "Actor failed to report a volume",
15340 _clutter_actor_get_debug_name (self));
15344 /* since effects can modify the paint volume, we allow them to actually
15345 * do this by making get_paint_volume() "context sensitive"
15347 if (priv->effects != NULL)
15349 if (priv->current_effect != NULL)
15351 const GList *effects, *l;
15353 /* if we are being called from within the paint sequence of
15354 * an actor, get the paint volume up to the current effect
15356 effects = _clutter_meta_group_peek_metas (priv->effects);
15358 l != NULL || (l != NULL && l->data != priv->current_effect);
15361 if (!_clutter_effect_get_paint_volume (l->data, pv))
15363 clutter_paint_volume_free (pv);
15364 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15365 "Effect (%s) failed to report a volume",
15366 _clutter_actor_get_debug_name (self),
15367 _clutter_actor_meta_get_debug_name (l->data));
15374 const GList *effects, *l;
15376 /* otherwise, get the cumulative volume */
15377 effects = _clutter_meta_group_peek_metas (priv->effects);
15378 for (l = effects; l != NULL; l = l->next)
15379 if (!_clutter_effect_get_paint_volume (l->data, pv))
15381 clutter_paint_volume_free (pv);
15382 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15383 "Effect (%s) failed to report a volume",
15384 _clutter_actor_get_debug_name (self),
15385 _clutter_actor_meta_get_debug_name (l->data));
15394 /* The public clutter_actor_get_paint_volume API returns a const
15395 * pointer since we return a pointer directly to the cached
15396 * PaintVolume associated with the actor and don't want the user to
15397 * inadvertently modify it, but for internal uses we sometimes need
15398 * access to the same PaintVolume but need to apply some book-keeping
15399 * modifications to it so we don't want a const pointer.
15401 static ClutterPaintVolume *
15402 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15404 ClutterActorPrivate *priv;
15408 if (priv->paint_volume_valid)
15409 clutter_paint_volume_free (&priv->paint_volume);
15411 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15413 priv->paint_volume_valid = TRUE;
15414 return &priv->paint_volume;
15418 priv->paint_volume_valid = FALSE;
15424 * clutter_actor_get_paint_volume:
15425 * @self: a #ClutterActor
15427 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15428 * when a paint volume can't be determined.
15430 * The paint volume is defined as the 3D space occupied by an actor
15431 * when being painted.
15433 * This function will call the <function>get_paint_volume()</function>
15434 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15435 * should not usually care about overriding the default implementation,
15436 * unless they are, for instance: painting outside their allocation, or
15437 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15440 * <note>2D actors overriding <function>get_paint_volume()</function>
15441 * ensure their volume has a depth of 0. (This will be true so long as
15442 * you don't call clutter_paint_volume_set_depth().)</note>
15444 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15445 * or %NULL if no volume could be determined. The returned pointer
15446 * is not guaranteed to be valid across multiple frames; if you want
15447 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15451 const ClutterPaintVolume *
15452 clutter_actor_get_paint_volume (ClutterActor *self)
15454 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15456 return _clutter_actor_get_paint_volume_mutable (self);
15460 * clutter_actor_get_transformed_paint_volume:
15461 * @self: a #ClutterActor
15462 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15463 * (or %NULL for the stage)
15465 * Retrieves the 3D paint volume of an actor like
15466 * clutter_actor_get_paint_volume() does (Please refer to the
15467 * documentation of clutter_actor_get_paint_volume() for more
15468 * details.) and it additionally transforms the paint volume into the
15469 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15470 * is passed for @relative_to_ancestor)
15472 * This can be used by containers that base their paint volume on
15473 * the volume of their children. Such containers can query the
15474 * transformed paint volume of all of its children and union them
15475 * together using clutter_paint_volume_union().
15477 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15478 * or %NULL if no volume could be determined. The returned pointer is
15479 * not guaranteed to be valid across multiple frames; if you wish to
15480 * keep it, you will have to copy it using clutter_paint_volume_copy().
15484 const ClutterPaintVolume *
15485 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15486 ClutterActor *relative_to_ancestor)
15488 const ClutterPaintVolume *volume;
15489 ClutterActor *stage;
15490 ClutterPaintVolume *transformed_volume;
15492 stage = _clutter_actor_get_stage_internal (self);
15493 if (G_UNLIKELY (stage == NULL))
15496 if (relative_to_ancestor == NULL)
15497 relative_to_ancestor = stage;
15499 volume = clutter_actor_get_paint_volume (self);
15500 if (volume == NULL)
15503 transformed_volume =
15504 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15506 _clutter_paint_volume_copy_static (volume, transformed_volume);
15508 _clutter_paint_volume_transform_relative (transformed_volume,
15509 relative_to_ancestor);
15511 return transformed_volume;
15515 * clutter_actor_get_paint_box:
15516 * @self: a #ClutterActor
15517 * @box: (out): return location for a #ClutterActorBox
15519 * Retrieves the paint volume of the passed #ClutterActor, and
15520 * transforms it into a 2D bounding box in stage coordinates.
15522 * This function is useful to determine the on screen area occupied by
15523 * the actor. The box is only an approximation and may often be
15524 * considerably larger due to the optimizations used to calculate the
15525 * box. The box is never smaller though, so it can reliably be used
15528 * There are times when a 2D paint box can't be determined, e.g.
15529 * because the actor isn't yet parented under a stage or because
15530 * the actor is unable to determine a paint volume.
15532 * Return value: %TRUE if a 2D paint box could be determined, else
15538 clutter_actor_get_paint_box (ClutterActor *self,
15539 ClutterActorBox *box)
15541 ClutterActor *stage;
15542 ClutterPaintVolume *pv;
15544 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15545 g_return_val_if_fail (box != NULL, FALSE);
15547 stage = _clutter_actor_get_stage_internal (self);
15548 if (G_UNLIKELY (!stage))
15551 pv = _clutter_actor_get_paint_volume_mutable (self);
15552 if (G_UNLIKELY (!pv))
15555 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15561 * clutter_actor_has_overlaps:
15562 * @self: A #ClutterActor
15564 * Asks the actor's implementation whether it may contain overlapping
15567 * For example; Clutter may use this to determine whether the painting
15568 * should be redirected to an offscreen buffer to correctly implement
15569 * the opacity property.
15571 * Custom actors can override the default response by implementing the
15572 * #ClutterActor <function>has_overlaps</function> virtual function. See
15573 * clutter_actor_set_offscreen_redirect() for more information.
15575 * Return value: %TRUE if the actor may have overlapping primitives, and
15581 clutter_actor_has_overlaps (ClutterActor *self)
15583 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15585 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15589 * clutter_actor_has_effects:
15590 * @self: A #ClutterActor
15592 * Returns whether the actor has any effects applied.
15594 * Return value: %TRUE if the actor has any effects,
15600 clutter_actor_has_effects (ClutterActor *self)
15602 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15604 if (self->priv->effects == NULL)
15607 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15611 * clutter_actor_has_constraints:
15612 * @self: A #ClutterActor
15614 * Returns whether the actor has any constraints applied.
15616 * Return value: %TRUE if the actor has any constraints,
15622 clutter_actor_has_constraints (ClutterActor *self)
15624 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15626 return self->priv->constraints != NULL;
15630 * clutter_actor_has_actions:
15631 * @self: A #ClutterActor
15633 * Returns whether the actor has any actions applied.
15635 * Return value: %TRUE if the actor has any actions,
15641 clutter_actor_has_actions (ClutterActor *self)
15643 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15645 return self->priv->actions != NULL;
15649 * clutter_actor_get_n_children:
15650 * @self: a #ClutterActor
15652 * Retrieves the number of children of @self.
15654 * Return value: the number of children of an actor
15659 clutter_actor_get_n_children (ClutterActor *self)
15661 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15663 return self->priv->n_children;
15667 * clutter_actor_get_child_at_index:
15668 * @self: a #ClutterActor
15669 * @index_: the position in the list of children
15671 * Retrieves the actor at the given @index_ inside the list of
15672 * children of @self.
15674 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15679 clutter_actor_get_child_at_index (ClutterActor *self,
15682 ClutterActor *iter;
15685 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15686 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15688 for (iter = self->priv->first_child, i = 0;
15689 iter != NULL && i < index_;
15690 iter = iter->priv->next_sibling, i += 1)
15697 * _clutter_actor_foreach_child:
15698 * @actor: The actor whos children you want to iterate
15699 * @callback: The function to call for each child
15700 * @user_data: Private data to pass to @callback
15702 * Calls a given @callback once for each child of the specified @actor and
15703 * passing the @user_data pointer each time.
15705 * Return value: returns %TRUE if all children were iterated, else
15706 * %FALSE if a callback broke out of iteration early.
15709 _clutter_actor_foreach_child (ClutterActor *self,
15710 ClutterForeachCallback callback,
15711 gpointer user_data)
15713 ClutterActorPrivate *priv = self->priv;
15714 ClutterActor *iter;
15717 for (cont = TRUE, iter = priv->first_child;
15718 cont && iter != NULL;
15719 iter = iter->priv->next_sibling)
15721 cont = callback (iter, user_data);
15728 /* For debugging purposes this gives us a simple way to print out
15729 * the scenegraph e.g in gdb using:
15731 * _clutter_actor_traverse (stage,
15733 * clutter_debug_print_actor_cb,
15738 static ClutterActorTraverseVisitFlags
15739 clutter_debug_print_actor_cb (ClutterActor *actor,
15743 g_print ("%*s%s:%p\n",
15745 _clutter_actor_get_debug_name (actor),
15748 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15753 _clutter_actor_traverse_breadth (ClutterActor *actor,
15754 ClutterTraverseCallback callback,
15755 gpointer user_data)
15757 GQueue *queue = g_queue_new ();
15758 ClutterActor dummy;
15759 int current_depth = 0;
15761 g_queue_push_tail (queue, actor);
15762 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15764 while ((actor = g_queue_pop_head (queue)))
15766 ClutterActorTraverseVisitFlags flags;
15768 if (actor == &dummy)
15771 g_queue_push_tail (queue, &dummy);
15775 flags = callback (actor, current_depth, user_data);
15776 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15778 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15780 ClutterActor *iter;
15782 for (iter = actor->priv->first_child;
15784 iter = iter->priv->next_sibling)
15786 g_queue_push_tail (queue, iter);
15791 g_queue_free (queue);
15794 static ClutterActorTraverseVisitFlags
15795 _clutter_actor_traverse_depth (ClutterActor *actor,
15796 ClutterTraverseCallback before_children_callback,
15797 ClutterTraverseCallback after_children_callback,
15799 gpointer user_data)
15801 ClutterActorTraverseVisitFlags flags;
15803 flags = before_children_callback (actor, current_depth, user_data);
15804 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15805 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15807 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15809 ClutterActor *iter;
15811 for (iter = actor->priv->first_child;
15813 iter = iter->priv->next_sibling)
15815 flags = _clutter_actor_traverse_depth (iter,
15816 before_children_callback,
15817 after_children_callback,
15821 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15822 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15826 if (after_children_callback)
15827 return after_children_callback (actor, current_depth, user_data);
15829 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15832 /* _clutter_actor_traverse:
15833 * @actor: The actor to start traversing the graph from
15834 * @flags: These flags may affect how the traversal is done
15835 * @before_children_callback: A function to call before visiting the
15836 * children of the current actor.
15837 * @after_children_callback: A function to call after visiting the
15838 * children of the current actor. (Ignored if
15839 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15840 * @user_data: The private data to pass to the callbacks
15842 * Traverses the scenegraph starting at the specified @actor and
15843 * descending through all its children and its children's children.
15844 * For each actor traversed @before_children_callback and
15845 * @after_children_callback are called with the specified
15846 * @user_data, before and after visiting that actor's children.
15848 * The callbacks can return flags that affect the ongoing traversal
15849 * such as by skipping over an actors children or bailing out of
15850 * any further traversing.
15853 _clutter_actor_traverse (ClutterActor *actor,
15854 ClutterActorTraverseFlags flags,
15855 ClutterTraverseCallback before_children_callback,
15856 ClutterTraverseCallback after_children_callback,
15857 gpointer user_data)
15859 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15860 _clutter_actor_traverse_breadth (actor,
15861 before_children_callback,
15863 else /* DEPTH_FIRST */
15864 _clutter_actor_traverse_depth (actor,
15865 before_children_callback,
15866 after_children_callback,
15867 0, /* start depth */
15872 on_layout_manager_changed (ClutterLayoutManager *manager,
15873 ClutterActor *self)
15875 clutter_actor_queue_relayout (self);
15879 * clutter_actor_set_layout_manager:
15880 * @self: a #ClutterActor
15881 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15883 * Sets the #ClutterLayoutManager delegate object that will be used to
15884 * lay out the children of @self.
15886 * The #ClutterActor will take a reference on the passed @manager which
15887 * will be released either when the layout manager is removed, or when
15888 * the actor is destroyed.
15893 clutter_actor_set_layout_manager (ClutterActor *self,
15894 ClutterLayoutManager *manager)
15896 ClutterActorPrivate *priv;
15898 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15899 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15903 if (priv->layout_manager != NULL)
15905 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15906 G_CALLBACK (on_layout_manager_changed),
15908 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15909 g_clear_object (&priv->layout_manager);
15912 priv->layout_manager = manager;
15914 if (priv->layout_manager != NULL)
15916 g_object_ref_sink (priv->layout_manager);
15917 clutter_layout_manager_set_container (priv->layout_manager,
15918 CLUTTER_CONTAINER (self));
15919 g_signal_connect (priv->layout_manager, "layout-changed",
15920 G_CALLBACK (on_layout_manager_changed),
15924 clutter_actor_queue_relayout (self);
15926 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15930 * clutter_actor_get_layout_manager:
15931 * @self: a #ClutterActor
15933 * Retrieves the #ClutterLayoutManager used by @self.
15935 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15940 ClutterLayoutManager *
15941 clutter_actor_get_layout_manager (ClutterActor *self)
15943 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15945 return self->priv->layout_manager;
15948 static const ClutterLayoutInfo default_layout_info = {
15951 { 0, 0, 0, 0 }, /* margin */
15952 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
15953 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
15954 0.f, 0.f, /* min_width, natural_width */
15955 0.f, 0.f, /* natual_width, natural_height */
15959 layout_info_free (gpointer data)
15961 if (G_LIKELY (data != NULL))
15962 g_slice_free (ClutterLayoutInfo, data);
15966 * _clutter_actor_get_layout_info:
15967 * @self: a #ClutterActor
15969 * Retrieves a pointer to the ClutterLayoutInfo structure.
15971 * If the actor does not have a ClutterLayoutInfo associated to it, one
15972 * will be created and initialized to the default values.
15974 * This function should be used for setters.
15976 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15979 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15981 ClutterLayoutInfo *
15982 _clutter_actor_get_layout_info (ClutterActor *self)
15984 ClutterLayoutInfo *retval;
15986 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15987 if (retval == NULL)
15989 retval = g_slice_new (ClutterLayoutInfo);
15991 *retval = default_layout_info;
15993 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16002 * _clutter_actor_get_layout_info_or_defaults:
16003 * @self: a #ClutterActor
16005 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16007 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16008 * then the default structure will be returned.
16010 * This function should only be used for getters.
16012 * Return value: a const pointer to the ClutterLayoutInfo structure
16014 const ClutterLayoutInfo *
16015 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16017 const ClutterLayoutInfo *info;
16019 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16021 return &default_layout_info;
16027 * clutter_actor_set_x_align:
16028 * @self: a #ClutterActor
16029 * @x_align: the horizontal alignment policy
16031 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16032 * actor received extra horizontal space.
16034 * See also the #ClutterActor:x-align property.
16039 clutter_actor_set_x_align (ClutterActor *self,
16040 ClutterActorAlign x_align)
16042 ClutterLayoutInfo *info;
16044 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16046 info = _clutter_actor_get_layout_info (self);
16048 if (info->x_align != x_align)
16050 info->x_align = x_align;
16052 clutter_actor_queue_relayout (self);
16054 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16059 * clutter_actor_get_x_align:
16060 * @self: a #ClutterActor
16062 * Retrieves the horizontal alignment policy set using
16063 * clutter_actor_set_x_align().
16065 * Return value: the horizontal alignment policy.
16070 clutter_actor_get_x_align (ClutterActor *self)
16072 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16074 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16078 * clutter_actor_set_y_align:
16079 * @self: a #ClutterActor
16080 * @y_align: the vertical alignment policy
16082 * Sets the vertical alignment policy of a #ClutterActor, in case the
16083 * actor received extra vertical space.
16085 * See also the #ClutterActor:y-align property.
16090 clutter_actor_set_y_align (ClutterActor *self,
16091 ClutterActorAlign y_align)
16093 ClutterLayoutInfo *info;
16095 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16097 info = _clutter_actor_get_layout_info (self);
16099 if (info->y_align != y_align)
16101 info->y_align = y_align;
16103 clutter_actor_queue_relayout (self);
16105 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16110 * clutter_actor_get_y_align:
16111 * @self: a #ClutterActor
16113 * Retrieves the vertical alignment policy set using
16114 * clutter_actor_set_y_align().
16116 * Return value: the vertical alignment policy.
16121 clutter_actor_get_y_align (ClutterActor *self)
16123 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16125 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16130 * clutter_margin_new:
16132 * Creates a new #ClutterMargin.
16134 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16135 * clutter_margin_free() to free the resources associated with it when
16141 clutter_margin_new (void)
16143 return g_slice_new0 (ClutterMargin);
16147 * clutter_margin_copy:
16148 * @margin_: a #ClutterMargin
16150 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16151 * the newly created structure.
16153 * Return value: (transfer full): a copy of the #ClutterMargin.
16158 clutter_margin_copy (const ClutterMargin *margin_)
16160 if (G_LIKELY (margin_ != NULL))
16161 return g_slice_dup (ClutterMargin, margin_);
16167 * clutter_margin_free:
16168 * @margin_: a #ClutterMargin
16170 * Frees the resources allocated by clutter_margin_new() and
16171 * clutter_margin_copy().
16176 clutter_margin_free (ClutterMargin *margin_)
16178 if (G_LIKELY (margin_ != NULL))
16179 g_slice_free (ClutterMargin, margin_);
16182 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16183 clutter_margin_copy,
16184 clutter_margin_free)
16187 * clutter_actor_set_margin:
16188 * @self: a #ClutterActor
16189 * @margin: a #ClutterMargin
16191 * Sets all the components of the margin of a #ClutterActor.
16196 clutter_actor_set_margin (ClutterActor *self,
16197 const ClutterMargin *margin)
16199 ClutterLayoutInfo *info;
16203 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16204 g_return_if_fail (margin != NULL);
16206 obj = G_OBJECT (self);
16209 g_object_freeze_notify (obj);
16211 info = _clutter_actor_get_layout_info (self);
16213 if (info->margin.top != margin->top)
16215 info->margin.top = margin->top;
16216 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16220 if (info->margin.right != margin->right)
16222 info->margin.right = margin->right;
16223 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16227 if (info->margin.bottom != margin->bottom)
16229 info->margin.bottom = margin->bottom;
16230 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16234 if (info->margin.left != margin->left)
16236 info->margin.left = margin->left;
16237 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16242 clutter_actor_queue_relayout (self);
16244 g_object_thaw_notify (obj);
16248 * clutter_actor_get_margin:
16249 * @self: a #ClutterActor
16250 * @margin: (out caller-allocates): return location for a #ClutterMargin
16252 * Retrieves all the components of the margin of a #ClutterActor.
16257 clutter_actor_get_margin (ClutterActor *self,
16258 ClutterMargin *margin)
16260 const ClutterLayoutInfo *info;
16262 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16263 g_return_if_fail (margin != NULL);
16265 info = _clutter_actor_get_layout_info_or_defaults (self);
16267 *margin = info->margin;
16271 * clutter_actor_set_margin_top:
16272 * @self: a #ClutterActor
16273 * @margin: the top margin
16275 * Sets the margin from the top of a #ClutterActor.
16280 clutter_actor_set_margin_top (ClutterActor *self,
16283 ClutterLayoutInfo *info;
16285 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16286 g_return_if_fail (margin >= 0.f);
16288 info = _clutter_actor_get_layout_info (self);
16290 if (info->margin.top == margin)
16293 info->margin.top = margin;
16295 clutter_actor_queue_relayout (self);
16297 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16301 * clutter_actor_get_margin_top:
16302 * @self: a #ClutterActor
16304 * Retrieves the top margin of a #ClutterActor.
16306 * Return value: the top margin
16311 clutter_actor_get_margin_top (ClutterActor *self)
16313 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16315 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16319 * clutter_actor_set_margin_bottom:
16320 * @self: a #ClutterActor
16321 * @margin: the bottom margin
16323 * Sets the margin from the bottom of a #ClutterActor.
16328 clutter_actor_set_margin_bottom (ClutterActor *self,
16331 ClutterLayoutInfo *info;
16333 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16334 g_return_if_fail (margin >= 0.f);
16336 info = _clutter_actor_get_layout_info (self);
16338 if (info->margin.bottom == margin)
16341 info->margin.bottom = margin;
16343 clutter_actor_queue_relayout (self);
16345 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16349 * clutter_actor_get_margin_bottom:
16350 * @self: a #ClutterActor
16352 * Retrieves the bottom margin of a #ClutterActor.
16354 * Return value: the bottom margin
16359 clutter_actor_get_margin_bottom (ClutterActor *self)
16361 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16363 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16367 * clutter_actor_set_margin_left:
16368 * @self: a #ClutterActor
16369 * @margin: the left margin
16371 * Sets the margin from the left of a #ClutterActor.
16376 clutter_actor_set_margin_left (ClutterActor *self,
16379 ClutterLayoutInfo *info;
16381 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16382 g_return_if_fail (margin >= 0.f);
16384 info = _clutter_actor_get_layout_info (self);
16386 if (info->margin.left == margin)
16389 info->margin.left = margin;
16391 clutter_actor_queue_relayout (self);
16393 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16397 * clutter_actor_get_margin_left:
16398 * @self: a #ClutterActor
16400 * Retrieves the left margin of a #ClutterActor.
16402 * Return value: the left margin
16407 clutter_actor_get_margin_left (ClutterActor *self)
16409 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16411 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16415 * clutter_actor_set_margin_right:
16416 * @self: a #ClutterActor
16417 * @margin: the right margin
16419 * Sets the margin from the right of a #ClutterActor.
16424 clutter_actor_set_margin_right (ClutterActor *self,
16427 ClutterLayoutInfo *info;
16429 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16430 g_return_if_fail (margin >= 0.f);
16432 info = _clutter_actor_get_layout_info (self);
16434 if (info->margin.right == margin)
16437 info->margin.right = margin;
16439 clutter_actor_queue_relayout (self);
16441 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16445 * clutter_actor_get_margin_right:
16446 * @self: a #ClutterActor
16448 * Retrieves the right margin of a #ClutterActor.
16450 * Return value: the right margin
16455 clutter_actor_get_margin_right (ClutterActor *self)
16457 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16459 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16463 clutter_actor_set_background_color_internal (ClutterActor *self,
16464 const ClutterColor *color)
16466 ClutterActorPrivate *priv = self->priv;
16469 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16472 obj = G_OBJECT (self);
16474 priv->bg_color = *color;
16475 priv->bg_color_set = TRUE;
16477 clutter_actor_queue_redraw (self);
16479 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16480 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16484 * clutter_actor_set_background_color:
16485 * @self: a #ClutterActor
16486 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16489 * Sets the background color of a #ClutterActor.
16491 * The background color will be used to cover the whole allocation of the
16492 * actor. The default background color of an actor is transparent.
16494 * To check whether an actor has a background color, you can use the
16495 * #ClutterActor:background-color-set actor property.
16497 * The #ClutterActor:background-color property is animatable.
16502 clutter_actor_set_background_color (ClutterActor *self,
16503 const ClutterColor *color)
16505 ClutterActorPrivate *priv;
16507 GParamSpec *bg_color_pspec;
16509 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16511 obj = G_OBJECT (self);
16517 priv->bg_color_set = FALSE;
16518 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16519 clutter_actor_queue_redraw (self);
16523 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16524 if (clutter_actor_get_easing_duration (self) != 0)
16526 ClutterTransition *transition;
16528 transition = _clutter_actor_get_transition (self, bg_color_pspec);
16529 if (transition == NULL)
16531 transition = _clutter_actor_create_transition (self, bg_color_pspec,
16536 _clutter_actor_update_transition (self, bg_color_pspec, color);
16538 clutter_actor_queue_redraw (self);
16541 clutter_actor_set_background_color_internal (self, color);
16545 * clutter_actor_get_background_color:
16546 * @self: a #ClutterActor
16547 * @color: (out caller-allocates): return location for a #ClutterColor
16549 * Retrieves the color set using clutter_actor_set_background_color().
16554 clutter_actor_get_background_color (ClutterActor *self,
16555 ClutterColor *color)
16557 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16558 g_return_if_fail (color != NULL);
16560 *color = self->priv->bg_color;
16564 * clutter_actor_get_previous_sibling:
16565 * @self: a #ClutterActor
16567 * Retrieves the sibling of @self that comes before it in the list
16568 * of children of @self's parent.
16570 * The returned pointer is only valid until the scene graph changes; it
16571 * is not safe to modify the list of children of @self while iterating
16574 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16579 clutter_actor_get_previous_sibling (ClutterActor *self)
16581 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16583 return self->priv->prev_sibling;
16587 * clutter_actor_get_next_sibling:
16588 * @self: a #ClutterActor
16590 * Retrieves the sibling of @self that comes after it in the list
16591 * of children of @self's parent.
16593 * The returned pointer is only valid until the scene graph changes; it
16594 * is not safe to modify the list of children of @self while iterating
16597 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16602 clutter_actor_get_next_sibling (ClutterActor *self)
16604 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16606 return self->priv->next_sibling;
16610 * clutter_actor_get_first_child:
16611 * @self: a #ClutterActor
16613 * Retrieves the first child of @self.
16615 * The returned pointer is only valid until the scene graph changes; it
16616 * is not safe to modify the list of children of @self while iterating
16619 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16624 clutter_actor_get_first_child (ClutterActor *self)
16626 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16628 return self->priv->first_child;
16632 * clutter_actor_get_last_child:
16633 * @self: a #ClutterActor
16635 * Retrieves the last child of @self.
16637 * The returned pointer is only valid until the scene graph changes; it
16638 * is not safe to modify the list of children of @self while iterating
16641 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16646 clutter_actor_get_last_child (ClutterActor *self)
16648 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16650 return self->priv->last_child;
16653 /* easy way to have properly named fields instead of the dummy ones
16654 * we use in the public structure
16656 typedef struct _RealActorIter
16658 ClutterActor *root; /* dummy1 */
16659 ClutterActor *current; /* dummy2 */
16660 gpointer padding_1; /* dummy3 */
16661 gint age; /* dummy4 */
16662 gpointer padding_2; /* dummy5 */
16666 * clutter_actor_iter_init:
16667 * @iter: a #ClutterActorIter
16668 * @root: a #ClutterActor
16670 * Initializes a #ClutterActorIter, which can then be used to iterate
16671 * efficiently over a section of the scene graph, and associates it
16674 * Modifying the scene graph section that contains @root will invalidate
16678 * ClutterActorIter iter;
16679 * ClutterActor *child;
16681 * clutter_actor_iter_init (&iter, container);
16682 * while (clutter_actor_iter_next (&iter, &child))
16684 * /* do something with child */
16691 clutter_actor_iter_init (ClutterActorIter *iter,
16692 ClutterActor *root)
16694 RealActorIter *ri = (RealActorIter *) iter;
16696 g_return_if_fail (iter != NULL);
16697 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16700 ri->current = NULL;
16701 ri->age = root->priv->age;
16705 * clutter_actor_iter_next:
16706 * @iter: a #ClutterActorIter
16707 * @child: (out): return location for a #ClutterActor
16709 * Advances the @iter and retrieves the next child of the root #ClutterActor
16710 * that was used to initialize the #ClutterActorIterator.
16712 * If the iterator can advance, this function returns %TRUE and sets the
16715 * If the iterator cannot advance, this function returns %FALSE, and
16716 * the contents of @child are undefined.
16718 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16723 clutter_actor_iter_next (ClutterActorIter *iter,
16724 ClutterActor **child)
16726 RealActorIter *ri = (RealActorIter *) iter;
16728 g_return_val_if_fail (iter != NULL, FALSE);
16729 g_return_val_if_fail (ri->root != NULL, FALSE);
16730 #ifndef G_DISABLE_ASSERT
16731 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16734 if (ri->current == NULL)
16735 ri->current = ri->root->priv->first_child;
16737 ri->current = ri->current->priv->next_sibling;
16740 *child = ri->current;
16742 return ri->current != NULL;
16746 * clutter_actor_iter_prev:
16747 * @iter: a #ClutterActorIter
16748 * @child: (out): return location for a #ClutterActor
16750 * Advances the @iter and retrieves the previous child of the root
16751 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16753 * If the iterator can advance, this function returns %TRUE and sets the
16756 * If the iterator cannot advance, this function returns %FALSE, and
16757 * the contents of @child are undefined.
16759 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16764 clutter_actor_iter_prev (ClutterActorIter *iter,
16765 ClutterActor **child)
16767 RealActorIter *ri = (RealActorIter *) iter;
16769 g_return_val_if_fail (iter != NULL, FALSE);
16770 g_return_val_if_fail (ri->root != NULL, FALSE);
16771 #ifndef G_DISABLE_ASSERT
16772 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16775 if (ri->current == NULL)
16776 ri->current = ri->root->priv->last_child;
16778 ri->current = ri->current->priv->prev_sibling;
16781 *child = ri->current;
16783 return ri->current != NULL;
16787 * clutter_actor_iter_remove:
16788 * @iter: a #ClutterActorIter
16790 * Safely removes the #ClutterActor currently pointer to by the iterator
16793 * This function can only be called after clutter_actor_iter_next() or
16794 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16795 * than once for the same actor.
16797 * This function will call clutter_actor_remove_child() internally.
16802 clutter_actor_iter_remove (ClutterActorIter *iter)
16804 RealActorIter *ri = (RealActorIter *) iter;
16807 g_return_if_fail (iter != NULL);
16808 g_return_if_fail (ri->root != NULL);
16809 #ifndef G_DISABLE_ASSERT
16810 g_return_if_fail (ri->age == ri->root->priv->age);
16812 g_return_if_fail (ri->current != NULL);
16818 ri->current = cur->priv->prev_sibling;
16820 clutter_actor_remove_child_internal (ri->root, cur,
16821 REMOVE_CHILD_DEFAULT_FLAGS);
16828 * clutter_actor_iter_destroy:
16829 * @iter: a #ClutterActorIter
16831 * Safely destroys the #ClutterActor currently pointer to by the iterator
16834 * This function can only be called after clutter_actor_iter_next() or
16835 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16836 * than once for the same actor.
16838 * This function will call clutter_actor_destroy() internally.
16843 clutter_actor_iter_destroy (ClutterActorIter *iter)
16845 RealActorIter *ri = (RealActorIter *) iter;
16848 g_return_if_fail (iter != NULL);
16849 g_return_if_fail (ri->root != NULL);
16850 #ifndef G_DISABLE_ASSERT
16851 g_return_if_fail (ri->age == ri->root->priv->age);
16853 g_return_if_fail (ri->current != NULL);
16859 ri->current = cur->priv->prev_sibling;
16861 clutter_actor_destroy (cur);
16867 static const ClutterAnimationInfo default_animation_info = {
16868 NULL, /* transitions */
16870 NULL, /* cur_state */
16874 clutter_animation_info_free (gpointer data)
16878 ClutterAnimationInfo *info = data;
16880 if (info->transitions != NULL)
16881 g_hash_table_unref (info->transitions);
16883 if (info->states != NULL)
16884 g_array_unref (info->states);
16886 g_slice_free (ClutterAnimationInfo, info);
16890 const ClutterAnimationInfo *
16891 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16893 const ClutterAnimationInfo *res;
16894 GObject *obj = G_OBJECT (self);
16896 res = g_object_get_qdata (obj, quark_actor_animation_info);
16900 return &default_animation_info;
16903 ClutterAnimationInfo *
16904 _clutter_actor_get_animation_info (ClutterActor *self)
16906 GObject *obj = G_OBJECT (self);
16907 ClutterAnimationInfo *res;
16909 res = g_object_get_qdata (obj, quark_actor_animation_info);
16912 res = g_slice_new (ClutterAnimationInfo);
16914 *res = default_animation_info;
16916 g_object_set_qdata_full (obj, quark_actor_animation_info,
16918 clutter_animation_info_free);
16924 ClutterTransition *
16925 _clutter_actor_get_transition (ClutterActor *actor,
16928 const ClutterAnimationInfo *info;
16930 info = _clutter_actor_get_animation_info_or_defaults (actor);
16932 if (info->transitions == NULL)
16935 return g_hash_table_lookup (info->transitions, pspec->name);
16938 typedef struct _TransitionClosure
16940 ClutterActor *actor;
16941 ClutterTransition *transition;
16943 gulong completed_id;
16944 } TransitionClosure;
16947 transition_closure_free (gpointer data)
16949 if (G_LIKELY (data != NULL))
16951 TransitionClosure *clos = data;
16953 if (clutter_timeline_is_playing (CLUTTER_TIMELINE (clos->transition)))
16954 clutter_timeline_stop (CLUTTER_TIMELINE (clos->transition));
16956 g_signal_handler_disconnect (clos->transition, clos->completed_id);
16958 g_object_unref (clos->transition);
16959 g_free (clos->name);
16961 g_slice_free (TransitionClosure, clos);
16966 on_transition_completed (ClutterTransition *transition,
16967 TransitionClosure *clos)
16969 ClutterActor *actor = clos->actor;
16970 ClutterAnimationInfo *info;
16972 info = _clutter_actor_get_animation_info (actor);
16974 /* this will take care of cleaning clos for us */
16975 if (clutter_transition_get_remove_on_complete (transition))
16977 /* we take a reference here because removing the closure
16978 * will release the reference on the transition, and we
16979 * want the transition to survive the signal emission;
16980 * the master clock will release the laste reference at
16981 * the end of the frame processing.
16983 g_object_ref (transition);
16984 g_hash_table_remove (info->transitions, clos->name);
16987 /* if it's the last transition then we clean up */
16988 if (g_hash_table_size (info->transitions) == 0)
16990 g_hash_table_unref (info->transitions);
16991 info->transitions = NULL;
16993 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
16994 _clutter_actor_get_debug_name (actor));
16996 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17001 _clutter_actor_update_transition (ClutterActor *actor,
17005 TransitionClosure *clos;
17006 ClutterInterval *interval;
17007 const ClutterAnimationInfo *info;
17010 GValue initial = G_VALUE_INIT;
17011 GValue final = G_VALUE_INIT;
17012 char *error = NULL;
17014 info = _clutter_actor_get_animation_info_or_defaults (actor);
17016 if (info->transitions == NULL)
17019 clos = g_hash_table_lookup (info->transitions, pspec->name);
17023 va_start (var_args, pspec);
17025 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17027 g_value_init (&initial, ptype);
17028 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17032 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17035 g_critical ("%s: %s", G_STRLOC, error);
17040 interval = clutter_transition_get_interval (clos->transition);
17041 clutter_interval_set_initial_value (interval, &initial);
17042 clutter_interval_set_final_value (interval, &final);
17044 clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
17047 g_value_unset (&initial);
17048 g_value_unset (&final);
17054 * _clutter_actor_create_transition:
17055 * @actor: a #ClutterActor
17056 * @pspec: the property used for the transition
17057 * @...: initial and final state
17059 * Creates a #ClutterTransition for the property represented by @pspec.
17061 * Return value: a #ClutterTransition
17063 ClutterTransition *
17064 _clutter_actor_create_transition (ClutterActor *actor,
17068 ClutterAnimationInfo *info;
17069 ClutterTransition *res = NULL;
17070 gboolean call_restore = FALSE;
17071 TransitionClosure *clos;
17074 info = _clutter_actor_get_animation_info (actor);
17076 if (info->states == NULL)
17078 clutter_actor_save_easing_state (actor);
17079 call_restore = TRUE;
17082 if (info->transitions == NULL)
17083 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17085 transition_closure_free);
17087 va_start (var_args, pspec);
17089 clos = g_hash_table_lookup (info->transitions, pspec->name);
17092 ClutterInterval *interval;
17093 GValue initial = G_VALUE_INIT;
17094 GValue final = G_VALUE_INIT;
17098 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17100 G_VALUE_COLLECT_INIT (&initial, ptype,
17105 g_critical ("%s: %s", G_STRLOC, error);
17110 G_VALUE_COLLECT_INIT (&final, ptype,
17116 g_critical ("%s: %s", G_STRLOC, error);
17117 g_value_unset (&initial);
17122 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17124 g_value_unset (&initial);
17125 g_value_unset (&final);
17127 res = clutter_property_transition_new (pspec->name);
17129 clutter_transition_set_interval (res, interval);
17130 clutter_transition_set_remove_on_complete (res, TRUE);
17132 /* this will start the transition as well */
17133 clutter_actor_add_transition (actor, pspec->name, res);
17135 /* the actor now owns the transition */
17136 g_object_unref (res);
17139 res = clos->transition;
17143 clutter_actor_restore_easing_state (actor);
17151 * clutter_actor_add_transition:
17152 * @self: a #ClutterActor
17153 * @name: the name of the transition to add
17154 * @transition: the #ClutterTransition to add
17156 * Adds a @transition to the #ClutterActor's list of animations.
17158 * The @name string is a per-actor unique identifier of the @transition: only
17159 * one #ClutterTransition can be associated to the specified @name.
17161 * The @transition will be given the easing duration, mode, and delay
17162 * associated to the actor's current easing state; it is possible to modify
17163 * these values after calling clutter_actor_add_transition().
17165 * The @transition will be started once added.
17167 * This function will take a reference on the @transition.
17169 * This function is usually called implicitly when modifying an animatable
17175 clutter_actor_add_transition (ClutterActor *self,
17177 ClutterTransition *transition)
17179 ClutterTimeline *timeline;
17180 TransitionClosure *clos;
17181 ClutterAnimationInfo *info;
17183 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17184 g_return_if_fail (name != NULL);
17185 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17187 info = _clutter_actor_get_animation_info (self);
17189 if (info->cur_state == NULL)
17191 g_warning ("No easing state is defined for the actor '%s'; you "
17192 "must call clutter_actor_save_easing_state() before "
17193 "calling clutter_actor_add_transition().",
17194 _clutter_actor_get_debug_name (self));
17198 if (info->transitions == NULL)
17199 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17201 transition_closure_free);
17203 if (g_hash_table_lookup (info->transitions, name) != NULL)
17205 g_warning ("A transition with name '%s' already exists for "
17208 _clutter_actor_get_debug_name (self));
17212 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17214 timeline = CLUTTER_TIMELINE (transition);
17216 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17217 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17218 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17220 clos = g_slice_new (TransitionClosure);
17221 clos->actor = self;
17222 clos->transition = g_object_ref (transition);
17223 clos->name = g_strdup (name);
17224 clos->completed_id = g_signal_connect (timeline, "completed",
17225 G_CALLBACK (on_transition_completed),
17228 g_hash_table_insert (info->transitions, clos->name, clos);
17229 clutter_timeline_start (timeline);
17233 * clutter_actor_remove_transition:
17234 * @self: a #ClutterActor
17235 * @name: the name of the transition to remove
17237 * Removes the transition stored inside a #ClutterActor using @name
17240 * If the transition is currently in progress, it will be stopped.
17242 * This function releases the reference acquired when the transition
17243 * was added to the #ClutterActor.
17248 clutter_actor_remove_transition (ClutterActor *self,
17251 const ClutterAnimationInfo *info;
17253 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17254 g_return_if_fail (name != NULL);
17256 info = _clutter_actor_get_animation_info_or_defaults (self);
17258 if (info->transitions == NULL)
17261 g_hash_table_remove (info->transitions, name);
17265 * clutter_actor_remove_all_transitions:
17266 * @self: a #ClutterActor
17268 * Removes all transitions associated to @self.
17273 clutter_actor_remove_all_transitions (ClutterActor *self)
17275 const ClutterAnimationInfo *info;
17277 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17279 info = _clutter_actor_get_animation_info_or_defaults (self);
17280 if (info->transitions == NULL)
17283 g_hash_table_remove_all (info->transitions);
17287 * clutter_actor_set_easing_duration:
17288 * @self: a #ClutterActor
17289 * @msecs: the duration of the easing, or %NULL
17291 * Sets the duration of the tweening for animatable properties
17292 * of @self for the current easing state.
17297 clutter_actor_set_easing_duration (ClutterActor *self,
17300 ClutterAnimationInfo *info;
17302 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17304 info = _clutter_actor_get_animation_info (self);
17306 if (info->cur_state == NULL)
17308 g_warning ("You must call clutter_actor_save_easing_state() prior "
17309 "to calling clutter_actor_set_easing_duration().");
17313 if (info->cur_state->easing_duration != msecs)
17314 info->cur_state->easing_duration = msecs;
17318 * clutter_actor_get_easing_duration:
17319 * @self: a #ClutterActor
17321 * Retrieves the duration of the tweening for animatable
17322 * properties of @self for the current easing state.
17324 * Return value: the duration of the tweening, in milliseconds
17329 clutter_actor_get_easing_duration (ClutterActor *self)
17331 const ClutterAnimationInfo *info;
17333 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17335 info = _clutter_actor_get_animation_info_or_defaults (self);
17337 if (info->cur_state != NULL)
17338 return info->cur_state->easing_duration;
17344 * clutter_actor_set_easing_mode:
17345 * @self: a #ClutterActor
17346 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17348 * Sets the easing mode for the tweening of animatable properties
17354 clutter_actor_set_easing_mode (ClutterActor *self,
17355 ClutterAnimationMode mode)
17357 ClutterAnimationInfo *info;
17359 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17360 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17361 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17363 info = _clutter_actor_get_animation_info (self);
17365 if (info->cur_state == NULL)
17367 g_warning ("You must call clutter_actor_save_easing_state() prior "
17368 "to calling clutter_actor_set_easing_mode().");
17372 if (info->cur_state->easing_mode != mode)
17373 info->cur_state->easing_mode = mode;
17377 * clutter_actor_get_easing_mode:
17378 * @self: a #ClutterActor
17380 * Retrieves the easing mode for the tweening of animatable properties
17381 * of @self for the current easing state.
17383 * Return value: an easing mode
17387 ClutterAnimationMode
17388 clutter_actor_get_easing_mode (ClutterActor *self)
17390 const ClutterAnimationInfo *info;
17392 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17394 info = _clutter_actor_get_animation_info_or_defaults (self);
17396 if (info->cur_state != NULL)
17397 return info->cur_state->easing_mode;
17399 return CLUTTER_EASE_OUT_CUBIC;
17403 * clutter_actor_set_easing_delay:
17404 * @self: a #ClutterActor
17405 * @msecs: the delay before the start of the tweening, in milliseconds
17407 * Sets the delay that should be applied before tweening animatable
17413 clutter_actor_set_easing_delay (ClutterActor *self,
17416 ClutterAnimationInfo *info;
17418 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17420 info = _clutter_actor_get_animation_info (self);
17422 if (info->cur_state == NULL)
17424 g_warning ("You must call clutter_actor_save_easing_state() prior "
17425 "to calling clutter_actor_set_easing_delay().");
17429 if (info->cur_state->easing_delay != msecs)
17430 info->cur_state->easing_delay = msecs;
17434 * clutter_actor_get_easing_delay:
17435 * @self: a #ClutterActor
17437 * Retrieves the delay that should be applied when tweening animatable
17440 * Return value: a delay, in milliseconds
17445 clutter_actor_get_easing_delay (ClutterActor *self)
17447 const ClutterAnimationInfo *info;
17449 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17451 info = _clutter_actor_get_animation_info_or_defaults (self);
17453 if (info->cur_state != NULL)
17454 return info->cur_state->easing_delay;
17460 * clutter_actor_get_transition:
17461 * @self: a #ClutterActor
17462 * @name: the name of the transition
17464 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17465 * transition @name.
17467 * Transitions created for animatable properties use the name of the
17468 * property itself, for instance the code below:
17471 * clutter_actor_set_easing_duration (actor, 1000);
17472 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17474 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17475 * g_signal_connect (transition, "completed",
17476 * G_CALLBACK (on_transition_complete),
17480 * will call the <function>on_transition_complete</function> callback when
17481 * the transition is complete.
17483 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17484 * was found to match the passed name; the returned instance is owned
17485 * by Clutter and it should not be freed
17489 ClutterTransition *
17490 clutter_actor_get_transition (ClutterActor *self,
17493 TransitionClosure *clos;
17494 const ClutterAnimationInfo *info;
17496 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17497 g_return_val_if_fail (name != NULL, NULL);
17499 info = _clutter_actor_get_animation_info_or_defaults (self);
17501 if (info->transitions == NULL)
17504 clos = g_hash_table_lookup (info->transitions, name);
17508 return clos->transition;
17512 * clutter_actor_save_easing_state:
17513 * @self: a #ClutterActor
17515 * Saves the current easing state for animatable properties, and creates
17516 * a new state with the default values for easing mode and duration.
17521 clutter_actor_save_easing_state (ClutterActor *self)
17523 ClutterAnimationInfo *info;
17526 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17528 info = _clutter_actor_get_animation_info (self);
17530 if (info->states == NULL)
17531 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17533 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17534 new_state.easing_duration = 250;
17535 new_state.easing_delay = 0;
17537 g_array_append_val (info->states, new_state);
17539 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17543 * clutter_actor_restore_easing_state:
17544 * @self: a #ClutterActor
17546 * Restores the easing state as it was prior to a call to
17547 * clutter_actor_save_easing_state().
17552 clutter_actor_restore_easing_state (ClutterActor *self)
17554 ClutterAnimationInfo *info;
17556 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17558 info = _clutter_actor_get_animation_info (self);
17560 if (info->states == NULL)
17562 g_critical ("The function clutter_actor_restore_easing_state() has "
17563 "called without a previous call to "
17564 "clutter_actor_save_easing_state().");
17568 g_array_remove_index (info->states, info->states->len - 1);
17570 if (info->states->len > 0)
17571 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17574 g_array_unref (info->states);
17575 info->states = NULL;
17580 * clutter_actor_set_content:
17581 * @self: a #ClutterActor
17582 * @content: (allow-none): a #ClutterContent, or %NULL
17584 * Sets the contents of a #ClutterActor.
17589 clutter_actor_set_content (ClutterActor *self,
17590 ClutterContent *content)
17592 ClutterActorPrivate *priv;
17594 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17595 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17599 if (priv->content != NULL)
17601 _clutter_content_detached (priv->content, self);
17602 g_clear_object (&priv->content);
17605 priv->content = content;
17607 if (priv->content != NULL)
17609 g_object_ref (priv->content);
17610 _clutter_content_attached (priv->content, self);
17613 /* given that the content is always painted within the allocation,
17614 * we only need to queue a redraw here
17616 clutter_actor_queue_redraw (self);
17618 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17620 /* if the content gravity is not resize-fill, and the new content has a
17621 * different preferred size than the previous one, then the content box
17622 * may have been changed. since we compute that lazily, we just notify
17623 * here, and let whomever watches :content-box do whatever they need to
17626 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17627 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17631 * clutter_actor_get_content:
17632 * @self: a #ClutterActor
17634 * Retrieves the contents of @self.
17636 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17637 * or %NULL if none was set
17642 clutter_actor_get_content (ClutterActor *self)
17644 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17646 return self->priv->content;
17650 * clutter_actor_set_content_gravity:
17651 * @self: a #ClutterActor
17652 * @gravity: the #ClutterContentGravity
17654 * Sets the gravity of the #ClutterContent used by @self.
17656 * See the description of the #ClutterActor:content-gravity property for
17657 * more information.
17662 clutter_actor_set_content_gravity (ClutterActor *self,
17663 ClutterContentGravity gravity)
17665 ClutterActorPrivate *priv;
17667 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17671 if (priv->content_gravity == gravity)
17674 priv->content_gravity = gravity;
17676 clutter_actor_queue_redraw (self);
17678 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17679 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17683 * clutter_actor_get_content_gravity:
17684 * @self: a #ClutterActor
17686 * Retrieves the content gravity as set using
17687 * clutter_actor_get_content_gravity().
17689 * Return value: the content gravity
17693 ClutterContentGravity
17694 clutter_actor_get_content_gravity (ClutterActor *self)
17696 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17697 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17699 return self->priv->content_gravity;
17703 * clutter_actor_get_content_box:
17704 * @self: a #ClutterActor
17705 * @box: (out caller-allocates): the return location for the bounding
17706 * box for the #ClutterContent
17708 * Retrieves the bounding box for the #ClutterContent of @self.
17710 * The bounding box is relative to the actor's allocation.
17712 * If no #ClutterContent is set for @self, or if @self has not been
17713 * allocated yet, then the result is undefined.
17715 * The content box is guaranteed to be, at most, as big as the allocation
17716 * of the #ClutterActor.
17718 * If the #ClutterContent used by the actor has a preferred size, then
17719 * it is possible to modify the content box by using the
17720 * #ClutterActor:content-gravity property.
17725 clutter_actor_get_content_box (ClutterActor *self,
17726 ClutterActorBox *box)
17728 ClutterActorPrivate *priv;
17729 gfloat content_w, content_h;
17730 gfloat alloc_w, alloc_h;
17732 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17733 g_return_if_fail (box != NULL);
17739 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17740 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17742 if (priv->content == NULL)
17745 /* no need to do any more work */
17746 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17749 /* if the content does not have a preferred size then there is
17750 * no point in computing the content box
17752 if (!clutter_content_get_preferred_size (priv->content,
17760 switch (priv->content_gravity)
17762 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17763 box->x2 = box->x1 + MIN (content_w, alloc_w);
17764 box->y2 = box->y1 + MIN (content_h, alloc_h);
17767 case CLUTTER_CONTENT_GRAVITY_TOP:
17768 if (alloc_w > content_w)
17770 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17771 box->x2 = box->x1 + content_w;
17773 box->y2 = box->y1 + MIN (content_h, alloc_h);
17776 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17777 if (alloc_w > content_w)
17779 box->x1 += (alloc_w - content_w);
17780 box->x2 = box->x1 + content_w;
17782 box->y2 = box->y1 + MIN (content_h, alloc_h);
17785 case CLUTTER_CONTENT_GRAVITY_LEFT:
17786 box->x2 = box->x1 + MIN (content_w, alloc_w);
17787 if (alloc_h > content_h)
17789 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17790 box->y2 = box->y1 + content_h;
17794 case CLUTTER_CONTENT_GRAVITY_CENTER:
17795 if (alloc_w > content_w)
17797 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17798 box->x2 = box->x1 + content_w;
17800 if (alloc_h > content_h)
17802 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17803 box->y2 = box->y1 + content_h;
17807 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17808 if (alloc_w > content_w)
17810 box->x1 += (alloc_w - content_w);
17811 box->x2 = box->x1 + content_w;
17813 if (alloc_h > content_h)
17815 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17816 box->y2 = box->y1 + content_h;
17820 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17821 box->x2 = box->x1 + MIN (content_w, alloc_w);
17822 if (alloc_h > content_h)
17824 box->y1 += (alloc_h - content_h);
17825 box->y2 = box->y1 + content_h;
17829 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17830 if (alloc_w > content_w)
17832 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17833 box->x2 = box->x1 + content_w;
17835 if (alloc_h > content_h)
17837 box->y1 += (alloc_h - content_h);
17838 box->y2 = box->y1 + content_h;
17842 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17843 if (alloc_w > content_w)
17845 box->x1 += (alloc_w - content_w);
17846 box->x2 = box->x1 + content_w;
17848 if (alloc_h > content_h)
17850 box->y1 += (alloc_h - content_h);
17851 box->y2 = box->y1 + content_h;
17855 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17856 g_assert_not_reached ();
17859 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17861 double r_c = content_w / content_h;
17862 double r_a = alloc_w / alloc_h;
17871 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17872 box->y2 = box->y1 + (alloc_w * r_c);
17879 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17880 box->x2 = box->x1 + (alloc_h * r_c);
17890 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17891 box->x2 = box->x1 + (alloc_h * r_c);
17898 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17899 box->y2 = box->y1 + (alloc_w * r_c);
17908 * clutter_actor_set_content_scaling_filters:
17909 * @self: a #ClutterActor
17910 * @min_filter: the minification filter for the content
17911 * @mag_filter: the magnification filter for the content
17913 * Sets the minification and magnification filter to be applied when
17914 * scaling the #ClutterActor:content of a #ClutterActor.
17916 * The #ClutterActor:minification-filter will be used when reducing
17917 * the size of the content; the #ClutterActor:magnification-filter
17918 * will be used when increasing the size of the content.
17923 clutter_actor_set_content_scaling_filters (ClutterActor *self,
17924 ClutterScalingFilter min_filter,
17925 ClutterScalingFilter mag_filter)
17927 ClutterActorPrivate *priv;
17931 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17934 obj = G_OBJECT (self);
17936 g_object_freeze_notify (obj);
17940 if (priv->min_filter != min_filter)
17942 priv->min_filter = min_filter;
17945 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17948 if (priv->mag_filter != mag_filter)
17950 priv->mag_filter = mag_filter;
17953 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17957 clutter_actor_queue_redraw (self);
17959 g_object_thaw_notify (obj);
17963 * clutter_actor_get_content_scaling_filters:
17964 * @self: a #ClutterActor
17965 * @min_filter: (out) (allow-none): return location for the minification
17967 * @mag_filter: (out) (allow-none): return location for the magnification
17970 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
17975 clutter_actor_get_content_scaling_filters (ClutterActor *self,
17976 ClutterScalingFilter *min_filter,
17977 ClutterScalingFilter *mag_filter)
17979 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17981 if (min_filter != NULL)
17982 *min_filter = self->priv->min_filter;
17984 if (mag_filter != NULL)
17985 *mag_filter = self->priv->mag_filter;