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_object_unref (priv->flatten_effect);
3184 priv->flatten_effect = NULL;
3190 clutter_actor_real_paint (ClutterActor *actor)
3192 ClutterActorPrivate *priv = actor->priv;
3195 for (iter = priv->first_child;
3197 iter = iter->priv->next_sibling)
3199 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3200 _clutter_actor_get_debug_name (iter),
3201 _clutter_actor_get_debug_name (actor),
3202 iter->priv->allocation.x1,
3203 iter->priv->allocation.y1,
3204 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3205 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3207 clutter_actor_paint (iter);
3212 clutter_actor_paint_node (ClutterActor *actor,
3213 ClutterPaintNode *root)
3215 ClutterActorPrivate *priv = actor->priv;
3220 if (priv->bg_color_set &&
3221 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3223 ClutterPaintNode *node;
3224 ClutterColor bg_color;
3225 ClutterActorBox box;
3229 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3230 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3232 bg_color = priv->bg_color;
3233 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3234 * priv->bg_color.alpha
3237 node = clutter_color_node_new (&bg_color);
3238 clutter_paint_node_set_name (node, "backgroundColor");
3239 clutter_paint_node_add_rectangle (node, &box);
3240 clutter_paint_node_add_child (root, node);
3241 clutter_paint_node_unref (node);
3244 if (priv->content != NULL)
3245 _clutter_content_paint_content (priv->content, actor, root);
3247 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3248 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3250 if (clutter_paint_node_get_n_children (root) == 0)
3253 #ifdef CLUTTER_ENABLE_DEBUG
3254 if (CLUTTER_HAS_DEBUG (PAINT))
3256 /* dump the tree only if we have one */
3257 _clutter_paint_node_dump_tree (root);
3259 #endif /* CLUTTER_ENABLE_DEBUG */
3261 _clutter_paint_node_paint (root);
3264 /* XXX: Uncomment this when we disable emitting the paint signal */
3265 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3272 * clutter_actor_paint:
3273 * @self: A #ClutterActor
3275 * Renders the actor to display.
3277 * This function should not be called directly by applications.
3278 * Call clutter_actor_queue_redraw() to queue paints, instead.
3280 * This function is context-aware, and will either cause a
3281 * regular paint or a pick paint.
3283 * This function will emit the #ClutterActor::paint signal or
3284 * the #ClutterActor::pick signal, depending on the context.
3286 * This function does not paint the actor if the actor is set to 0,
3287 * unless it is performing a pick paint.
3290 clutter_actor_paint (ClutterActor *self)
3292 ClutterActorPrivate *priv;
3293 ClutterPickMode pick_mode;
3294 gboolean clip_set = FALSE;
3295 gboolean shader_applied = FALSE;
3297 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3298 "Actor real-paint counter",
3299 "Increments each time any actor is painted",
3300 0 /* no application private data */);
3301 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3302 "Actor pick-paint counter",
3303 "Increments each time any actor is painted "
3305 0 /* no application private data */);
3307 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3309 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3314 pick_mode = _clutter_context_get_pick_mode ();
3316 if (pick_mode == CLUTTER_PICK_NONE)
3317 priv->propagated_one_redraw = FALSE;
3319 /* It's an important optimization that we consider painting of
3320 * actors with 0 opacity to be a NOP... */
3321 if (pick_mode == CLUTTER_PICK_NONE &&
3322 /* ignore top-levels, since they might be transparent */
3323 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3324 /* Use the override opacity if its been set */
3325 ((priv->opacity_override >= 0) ?
3326 priv->opacity_override : priv->opacity) == 0)
3329 /* if we aren't paintable (not in a toplevel with all
3330 * parents paintable) then do nothing.
3332 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3335 /* mark that we are in the paint process */
3336 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3340 if (priv->enable_model_view_transform)
3344 /* XXX: It could be better to cache the modelview with the actor
3345 * instead of progressively building up the transformations on
3346 * the matrix stack every time we paint. */
3347 cogl_get_modelview_matrix (&matrix);
3348 _clutter_actor_apply_modelview_transform (self, &matrix);
3350 #ifdef CLUTTER_ENABLE_DEBUG
3351 /* Catch when out-of-band transforms have been made by actors not as part
3352 * of an apply_transform vfunc... */
3353 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3355 CoglMatrix expected_matrix;
3357 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3360 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3362 GString *buf = g_string_sized_new (1024);
3363 ClutterActor *parent;
3366 while (parent != NULL)
3368 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3370 if (parent->priv->parent != NULL)
3371 g_string_append (buf, "->");
3373 parent = parent->priv->parent;
3376 g_warning ("Unexpected transform found when painting actor "
3377 "\"%s\". This will be caused by one of the actor's "
3378 "ancestors (%s) using the Cogl API directly to transform "
3379 "children instead of using ::apply_transform().",
3380 _clutter_actor_get_debug_name (self),
3383 g_string_free (buf, TRUE);
3386 #endif /* CLUTTER_ENABLE_DEBUG */
3388 cogl_set_modelview_matrix (&matrix);
3393 cogl_clip_push_rectangle (priv->clip.x,
3395 priv->clip.x + priv->clip.width,
3396 priv->clip.y + priv->clip.height);
3399 else if (priv->clip_to_allocation)
3401 gfloat width, height;
3403 width = priv->allocation.x2 - priv->allocation.x1;
3404 height = priv->allocation.y2 - priv->allocation.y1;
3406 cogl_clip_push_rectangle (0, 0, width, height);
3410 if (pick_mode == CLUTTER_PICK_NONE)
3412 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3414 /* We check whether we need to add the flatten effect before
3415 each paint so that we can avoid having a mechanism for
3416 applications to notify when the value of the
3417 has_overlaps virtual changes. */
3418 add_or_remove_flatten_effect (self);
3421 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3423 /* We save the current paint volume so that the next time the
3424 * actor queues a redraw we can constrain the redraw to just
3425 * cover the union of the new bounding box and the old.
3427 * We also fetch the current paint volume to perform culling so
3428 * we can avoid painting actors outside the current clip region.
3430 * If we are painting inside a clone, we should neither update
3431 * the paint volume or use it to cull painting, since the paint
3432 * box represents the location of the source actor on the
3435 * XXX: We are starting to do a lot of vertex transforms on
3436 * the CPU in a typical paint, so at some point we should
3437 * audit these and consider caching some things.
3439 * NB: We don't perform culling while picking at this point because
3440 * clutter-stage.c doesn't setup the clipping planes appropriately.
3442 * NB: We don't want to update the last-paint-volume during picking
3443 * because the last-paint-volume is used to determine the old screen
3444 * space location of an actor that has moved so we can know the
3445 * minimal region to redraw to clear an old view of the actor. If we
3446 * update this during picking then by the time we come around to
3447 * paint then the last-paint-volume would likely represent the new
3448 * actor position not the old.
3450 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3453 /* annoyingly gcc warns if uninitialized even though
3454 * the initialization is redundant :-( */
3455 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3457 if (G_LIKELY ((clutter_paint_debug_flags &
3458 (CLUTTER_DEBUG_DISABLE_CULLING |
3459 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3460 (CLUTTER_DEBUG_DISABLE_CULLING |
3461 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3462 _clutter_actor_update_last_paint_volume (self);
3464 success = cull_actor (self, &result);
3466 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3467 _clutter_actor_paint_cull_result (self, success, result);
3468 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3472 if (priv->effects == NULL)
3474 if (pick_mode == CLUTTER_PICK_NONE &&
3475 actor_has_shader_data (self))
3477 _clutter_actor_shader_pre_paint (self, FALSE);
3478 shader_applied = TRUE;
3481 priv->next_effect_to_paint = NULL;
3484 priv->next_effect_to_paint =
3485 _clutter_meta_group_peek_metas (priv->effects);
3487 clutter_actor_continue_paint (self);
3490 _clutter_actor_shader_post_paint (self);
3492 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3493 pick_mode == CLUTTER_PICK_NONE))
3494 _clutter_actor_draw_paint_volume (self);
3497 /* If we make it here then the actor has run through a complete
3498 paint run including all the effects so it's no longer dirty */
3499 if (pick_mode == CLUTTER_PICK_NONE)
3500 priv->is_dirty = FALSE;
3507 /* paint sequence complete */
3508 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3512 * clutter_actor_continue_paint:
3513 * @self: A #ClutterActor
3515 * Run the next stage of the paint sequence. This function should only
3516 * be called within the implementation of the ‘run’ virtual of a
3517 * #ClutterEffect. It will cause the run method of the next effect to
3518 * be applied, or it will paint the actual actor if the current effect
3519 * is the last effect in the chain.
3524 clutter_actor_continue_paint (ClutterActor *self)
3526 ClutterActorPrivate *priv;
3528 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3529 /* This should only be called from with in the ‘run’ implementation
3530 of a ClutterEffect */
3531 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3535 /* Skip any effects that are disabled */
3536 while (priv->next_effect_to_paint &&
3537 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3538 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3540 /* If this has come from the last effect then we'll just paint the
3542 if (priv->next_effect_to_paint == NULL)
3544 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3546 ClutterPaintNode *dummy;
3548 /* XXX - this will go away in 2.0, when we can get rid of this
3549 * stuff and switch to a pure retained render tree of PaintNodes
3550 * for the entire frame, starting from the Stage; the paint()
3551 * virtual function can then be called directly.
3553 dummy = _clutter_dummy_node_new (self);
3554 clutter_paint_node_set_name (dummy, "Root");
3556 /* XXX - for 1.12, we use the return value of paint_node() to
3557 * decide whether we should emit the ::paint signal.
3559 clutter_actor_paint_node (self, dummy);
3560 clutter_paint_node_unref (dummy);
3562 g_signal_emit (self, actor_signals[PAINT], 0);
3566 ClutterColor col = { 0, };
3568 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3570 /* Actor will then paint silhouette of itself in supplied
3571 * color. See clutter_stage_get_actor_at_pos() for where
3572 * picking is enabled.
3574 g_signal_emit (self, actor_signals[PICK], 0, &col);
3579 ClutterEffect *old_current_effect;
3580 ClutterEffectPaintFlags run_flags = 0;
3582 /* Cache the current effect so that we can put it back before
3584 old_current_effect = priv->current_effect;
3586 priv->current_effect = priv->next_effect_to_paint->data;
3587 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3589 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3593 /* If there's an effect queued with this redraw then all
3594 effects up to that one will be considered dirty. It
3595 is expected the queued effect will paint the cached
3596 image and not call clutter_actor_continue_paint again
3597 (although it should work ok if it does) */
3598 if (priv->effect_to_redraw == NULL ||
3599 priv->current_effect != priv->effect_to_redraw)
3600 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3603 _clutter_effect_paint (priv->current_effect, run_flags);
3607 /* We can't determine when an actor has been modified since
3608 its last pick so lets just assume it has always been
3610 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3612 _clutter_effect_pick (priv->current_effect, run_flags);
3615 priv->current_effect = old_current_effect;
3619 static ClutterActorTraverseVisitFlags
3620 invalidate_queue_redraw_entry (ClutterActor *self,
3624 ClutterActorPrivate *priv = self->priv;
3626 if (priv->queue_redraw_entry != NULL)
3628 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3629 priv->queue_redraw_entry = NULL;
3632 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3636 remove_child (ClutterActor *self,
3637 ClutterActor *child)
3639 ClutterActor *prev_sibling, *next_sibling;
3641 prev_sibling = child->priv->prev_sibling;
3642 next_sibling = child->priv->next_sibling;
3644 if (prev_sibling != NULL)
3645 prev_sibling->priv->next_sibling = next_sibling;
3647 if (next_sibling != NULL)
3648 next_sibling->priv->prev_sibling = prev_sibling;
3650 if (self->priv->first_child == child)
3651 self->priv->first_child = next_sibling;
3653 if (self->priv->last_child == child)
3654 self->priv->last_child = prev_sibling;
3656 child->priv->parent = NULL;
3657 child->priv->prev_sibling = NULL;
3658 child->priv->next_sibling = NULL;
3662 REMOVE_CHILD_DESTROY_META = 1 << 0,
3663 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3664 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3665 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3666 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3667 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3669 /* default flags for public API */
3670 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3671 REMOVE_CHILD_EMIT_PARENT_SET |
3672 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3673 REMOVE_CHILD_CHECK_STATE |
3674 REMOVE_CHILD_FLUSH_QUEUE |
3675 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3677 /* flags for legacy/deprecated API */
3678 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3679 REMOVE_CHILD_FLUSH_QUEUE |
3680 REMOVE_CHILD_EMIT_PARENT_SET |
3681 REMOVE_CHILD_NOTIFY_FIRST_LAST
3682 } ClutterActorRemoveChildFlags;
3685 * clutter_actor_remove_child_internal:
3686 * @self: a #ClutterActor
3687 * @child: the child of @self that has to be removed
3688 * @flags: control the removal operations
3690 * Removes @child from the list of children of @self.
3693 clutter_actor_remove_child_internal (ClutterActor *self,
3694 ClutterActor *child,
3695 ClutterActorRemoveChildFlags flags)
3697 ClutterActor *old_first, *old_last;
3698 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3699 gboolean flush_queue;
3700 gboolean notify_first_last;
3701 gboolean was_mapped;
3703 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3704 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3705 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3706 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3707 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3708 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3710 g_object_freeze_notify (G_OBJECT (self));
3713 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3717 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3719 /* we need to unrealize *before* we set parent_actor to NULL,
3720 * because in an unrealize method actors are dissociating from the
3721 * stage, which means they need to be able to
3722 * clutter_actor_get_stage().
3724 * yhis should unmap and unrealize, unless we're reparenting.
3726 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3733 /* We take this opportunity to invalidate any queue redraw entry
3734 * associated with the actor and descendants since we won't be able to
3735 * determine the appropriate stage after this.
3737 * we do this after we updated the mapped state because actors might
3738 * end up queueing redraws inside their mapped/unmapped virtual
3739 * functions, and if we invalidate the redraw entry we could end up
3740 * with an inconsistent state and weird memory corruption. see
3743 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3744 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3746 _clutter_actor_traverse (child,
3748 invalidate_queue_redraw_entry,
3753 old_first = self->priv->first_child;
3754 old_last = self->priv->last_child;
3756 remove_child (self, child);
3758 self->priv->n_children -= 1;
3760 self->priv->age += 1;
3762 /* clutter_actor_reparent() will emit ::parent-set for us */
3763 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3764 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3766 /* if the child was mapped then we need to relayout ourselves to account
3767 * for the removed child
3770 clutter_actor_queue_relayout (self);
3772 /* we need to emit the signal before dropping the reference */
3773 if (emit_actor_removed)
3774 g_signal_emit_by_name (self, "actor-removed", child);
3776 if (notify_first_last)
3778 if (old_first != self->priv->first_child)
3779 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3781 if (old_last != self->priv->last_child)
3782 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3785 g_object_thaw_notify (G_OBJECT (self));
3787 /* remove the reference we acquired in clutter_actor_add_child() */
3788 g_object_unref (child);
3791 static const ClutterTransformInfo default_transform_info = {
3792 0.0, { 0, }, /* rotation-x */
3793 0.0, { 0, }, /* rotation-y */
3794 0.0, { 0, }, /* rotation-z */
3796 1.0, 1.0, { 0, }, /* scale */
3798 { 0, }, /* anchor */
3804 * _clutter_actor_get_transform_info_or_defaults:
3805 * @self: a #ClutterActor
3807 * Retrieves the ClutterTransformInfo structure associated to an actor.
3809 * If the actor does not have a ClutterTransformInfo structure associated
3810 * to it, then the default structure will be returned.
3812 * This function should only be used for getters.
3814 * Return value: a const pointer to the ClutterTransformInfo structure
3816 const ClutterTransformInfo *
3817 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3819 ClutterTransformInfo *info;
3821 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3825 return &default_transform_info;
3829 clutter_transform_info_free (gpointer data)
3832 g_slice_free (ClutterTransformInfo, data);
3836 * _clutter_actor_get_transform_info:
3837 * @self: a #ClutterActor
3839 * Retrieves a pointer to the ClutterTransformInfo structure.
3841 * If the actor does not have a ClutterTransformInfo associated to it, one
3842 * will be created and initialized to the default values.
3844 * This function should be used for setters.
3846 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3849 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3852 ClutterTransformInfo *
3853 _clutter_actor_get_transform_info (ClutterActor *self)
3855 ClutterTransformInfo *info;
3857 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3860 info = g_slice_new (ClutterTransformInfo);
3862 *info = default_transform_info;
3864 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3866 clutter_transform_info_free);
3873 * clutter_actor_set_rotation_angle_internal:
3874 * @self: a #ClutterActor
3875 * @axis: the axis of the angle to change
3876 * @angle: the angle of rotation
3878 * Sets the rotation angle on the given axis without affecting the
3879 * rotation center point.
3882 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3883 ClutterRotateAxis axis,
3886 GObject *obj = G_OBJECT (self);
3887 ClutterTransformInfo *info;
3889 info = _clutter_actor_get_transform_info (self);
3891 g_object_freeze_notify (obj);
3895 case CLUTTER_X_AXIS:
3896 info->rx_angle = angle;
3897 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3900 case CLUTTER_Y_AXIS:
3901 info->ry_angle = angle;
3902 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3905 case CLUTTER_Z_AXIS:
3906 info->rz_angle = angle;
3907 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3911 self->priv->transform_valid = FALSE;
3913 g_object_thaw_notify (obj);
3915 clutter_actor_queue_redraw (self);
3919 clutter_actor_set_rotation_angle (ClutterActor *self,
3920 ClutterRotateAxis axis,
3923 ClutterTransformInfo *info;
3925 info = _clutter_actor_get_transform_info (self);
3927 if (clutter_actor_get_easing_duration (self) != 0)
3929 ClutterTransition *transition;
3930 GParamSpec *pspec = NULL;
3931 double *cur_angle_p = NULL;
3935 case CLUTTER_X_AXIS:
3936 cur_angle_p = &info->rx_angle;
3937 pspec = obj_props[PROP_ROTATION_ANGLE_X];
3940 case CLUTTER_Y_AXIS:
3941 cur_angle_p = &info->ry_angle;
3942 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3945 case CLUTTER_Z_AXIS:
3946 cur_angle_p = &info->rz_angle;
3947 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3951 g_assert (pspec != NULL);
3952 g_assert (cur_angle_p != NULL);
3954 transition = _clutter_actor_get_transition (self, pspec);
3955 if (transition == NULL)
3957 transition = _clutter_actor_create_transition (self, pspec,
3960 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3963 _clutter_actor_update_transition (self, pspec, angle);
3965 self->priv->transform_valid = FALSE;
3966 clutter_actor_queue_redraw (self);
3969 clutter_actor_set_rotation_angle_internal (self, axis, angle);
3973 * clutter_actor_set_rotation_center_internal:
3974 * @self: a #ClutterActor
3975 * @axis: the axis of the center to change
3976 * @center: the coordinates of the rotation center
3978 * Sets the rotation center on the given axis without affecting the
3982 clutter_actor_set_rotation_center_internal (ClutterActor *self,
3983 ClutterRotateAxis axis,
3984 const ClutterVertex *center)
3986 GObject *obj = G_OBJECT (self);
3987 ClutterTransformInfo *info;
3988 ClutterVertex v = { 0, 0, 0 };
3990 info = _clutter_actor_get_transform_info (self);
3995 g_object_freeze_notify (obj);
3999 case CLUTTER_X_AXIS:
4000 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4001 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4004 case CLUTTER_Y_AXIS:
4005 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4006 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4009 case CLUTTER_Z_AXIS:
4010 /* if the previously set rotation center was fractional, then
4011 * setting explicit coordinates will have to notify the
4012 * :rotation-center-z-gravity property as well
4014 if (info->rz_center.is_fractional)
4015 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4017 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4018 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4022 self->priv->transform_valid = FALSE;
4024 g_object_thaw_notify (obj);
4026 clutter_actor_queue_redraw (self);
4030 clutter_actor_animate_scale_factor (ClutterActor *self,
4035 ClutterTransition *transition;
4037 transition = _clutter_actor_get_transition (self, pspec);
4038 if (transition == NULL)
4040 transition = _clutter_actor_create_transition (self, pspec,
4043 clutter_timeline_start (CLUTTER_TIMELINE (transition));
4046 _clutter_actor_update_transition (self, pspec, new_factor);
4049 self->priv->transform_valid = FALSE;
4050 clutter_actor_queue_redraw (self);
4054 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4058 GObject *obj = G_OBJECT (self);
4059 ClutterTransformInfo *info;
4061 info = _clutter_actor_get_transform_info (self);
4063 if (pspec == obj_props[PROP_SCALE_X])
4064 info->scale_x = factor;
4066 info->scale_y = factor;
4068 self->priv->transform_valid = FALSE;
4069 clutter_actor_queue_redraw (self);
4070 g_object_notify_by_pspec (obj, pspec);
4074 clutter_actor_set_scale_factor (ClutterActor *self,
4075 ClutterRotateAxis axis,
4078 GObject *obj = G_OBJECT (self);
4079 ClutterTransformInfo *info;
4082 info = _clutter_actor_get_transform_info (self);
4084 g_object_freeze_notify (obj);
4088 case CLUTTER_X_AXIS:
4089 pspec = obj_props[PROP_SCALE_X];
4091 if (clutter_actor_get_easing_duration (self) != 0)
4092 clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4094 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4097 case CLUTTER_Y_AXIS:
4098 pspec = obj_props[PROP_SCALE_Y];
4100 if (clutter_actor_get_easing_duration (self) != 0)
4101 clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4103 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4107 g_assert_not_reached ();
4110 g_object_thaw_notify (obj);
4114 clutter_actor_set_scale_center (ClutterActor *self,
4115 ClutterRotateAxis axis,
4118 GObject *obj = G_OBJECT (self);
4119 ClutterTransformInfo *info;
4120 gfloat center_x, center_y;
4122 info = _clutter_actor_get_transform_info (self);
4124 g_object_freeze_notify (obj);
4126 /* get the current scale center coordinates */
4127 clutter_anchor_coord_get_units (self, &info->scale_center,
4132 /* we need to notify this too, because setting explicit coordinates will
4133 * change the gravity as a side effect
4135 if (info->scale_center.is_fractional)
4136 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4140 case CLUTTER_X_AXIS:
4141 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4142 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4145 case CLUTTER_Y_AXIS:
4146 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4147 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4151 g_assert_not_reached ();
4154 self->priv->transform_valid = FALSE;
4156 clutter_actor_queue_redraw (self);
4158 g_object_thaw_notify (obj);
4162 clutter_actor_set_scale_gravity (ClutterActor *self,
4163 ClutterGravity gravity)
4165 ClutterTransformInfo *info;
4168 info = _clutter_actor_get_transform_info (self);
4169 obj = G_OBJECT (self);
4171 if (gravity == CLUTTER_GRAVITY_NONE)
4172 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4174 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4176 self->priv->transform_valid = FALSE;
4178 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4179 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4180 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4182 clutter_actor_queue_redraw (self);
4186 clutter_actor_set_anchor_coord (ClutterActor *self,
4187 ClutterRotateAxis axis,
4190 GObject *obj = G_OBJECT (self);
4191 ClutterTransformInfo *info;
4192 gfloat anchor_x, anchor_y;
4194 info = _clutter_actor_get_transform_info (self);
4196 g_object_freeze_notify (obj);
4198 clutter_anchor_coord_get_units (self, &info->anchor,
4203 if (info->anchor.is_fractional)
4204 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4208 case CLUTTER_X_AXIS:
4209 clutter_anchor_coord_set_units (&info->anchor,
4213 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4216 case CLUTTER_Y_AXIS:
4217 clutter_anchor_coord_set_units (&info->anchor,
4221 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4225 g_assert_not_reached ();
4228 self->priv->transform_valid = FALSE;
4230 clutter_actor_queue_redraw (self);
4232 g_object_thaw_notify (obj);
4236 clutter_actor_set_property (GObject *object,
4238 const GValue *value,
4241 ClutterActor *actor = CLUTTER_ACTOR (object);
4242 ClutterActorPrivate *priv = actor->priv;
4247 clutter_actor_set_x (actor, g_value_get_float (value));
4251 clutter_actor_set_y (actor, g_value_get_float (value));
4255 clutter_actor_set_width (actor, g_value_get_float (value));
4259 clutter_actor_set_height (actor, g_value_get_float (value));
4263 clutter_actor_set_x (actor, g_value_get_float (value));
4267 clutter_actor_set_y (actor, g_value_get_float (value));
4270 case PROP_FIXED_POSITION_SET:
4271 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4274 case PROP_MIN_WIDTH:
4275 clutter_actor_set_min_width (actor, g_value_get_float (value));
4278 case PROP_MIN_HEIGHT:
4279 clutter_actor_set_min_height (actor, g_value_get_float (value));
4282 case PROP_NATURAL_WIDTH:
4283 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4286 case PROP_NATURAL_HEIGHT:
4287 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4290 case PROP_MIN_WIDTH_SET:
4291 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4294 case PROP_MIN_HEIGHT_SET:
4295 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4298 case PROP_NATURAL_WIDTH_SET:
4299 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4302 case PROP_NATURAL_HEIGHT_SET:
4303 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4306 case PROP_REQUEST_MODE:
4307 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4311 clutter_actor_set_depth (actor, g_value_get_float (value));
4315 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4318 case PROP_OFFSCREEN_REDIRECT:
4319 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4323 clutter_actor_set_name (actor, g_value_get_string (value));
4327 if (g_value_get_boolean (value) == TRUE)
4328 clutter_actor_show (actor);
4330 clutter_actor_hide (actor);
4334 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4335 g_value_get_double (value));
4339 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4340 g_value_get_double (value));
4343 case PROP_SCALE_CENTER_X:
4344 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4345 g_value_get_float (value));
4348 case PROP_SCALE_CENTER_Y:
4349 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4350 g_value_get_float (value));
4353 case PROP_SCALE_GRAVITY:
4354 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4359 const ClutterGeometry *geom = g_value_get_boxed (value);
4361 clutter_actor_set_clip (actor,
4363 geom->width, geom->height);
4367 case PROP_CLIP_TO_ALLOCATION:
4368 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4372 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4375 case PROP_ROTATION_ANGLE_X:
4376 clutter_actor_set_rotation_angle (actor,
4378 g_value_get_double (value));
4381 case PROP_ROTATION_ANGLE_Y:
4382 clutter_actor_set_rotation_angle (actor,
4384 g_value_get_double (value));
4387 case PROP_ROTATION_ANGLE_Z:
4388 clutter_actor_set_rotation_angle (actor,
4390 g_value_get_double (value));
4393 case PROP_ROTATION_CENTER_X:
4394 clutter_actor_set_rotation_center_internal (actor,
4396 g_value_get_boxed (value));
4399 case PROP_ROTATION_CENTER_Y:
4400 clutter_actor_set_rotation_center_internal (actor,
4402 g_value_get_boxed (value));
4405 case PROP_ROTATION_CENTER_Z:
4406 clutter_actor_set_rotation_center_internal (actor,
4408 g_value_get_boxed (value));
4411 case PROP_ROTATION_CENTER_Z_GRAVITY:
4413 const ClutterTransformInfo *info;
4415 info = _clutter_actor_get_transform_info_or_defaults (actor);
4416 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4417 g_value_get_enum (value));
4422 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4423 g_value_get_float (value));
4427 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4428 g_value_get_float (value));
4431 case PROP_ANCHOR_GRAVITY:
4432 clutter_actor_set_anchor_point_from_gravity (actor,
4433 g_value_get_enum (value));
4436 case PROP_SHOW_ON_SET_PARENT:
4437 priv->show_on_set_parent = g_value_get_boolean (value);
4440 case PROP_TEXT_DIRECTION:
4441 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4445 clutter_actor_add_action (actor, g_value_get_object (value));
4448 case PROP_CONSTRAINTS:
4449 clutter_actor_add_constraint (actor, g_value_get_object (value));
4453 clutter_actor_add_effect (actor, g_value_get_object (value));
4456 case PROP_LAYOUT_MANAGER:
4457 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4461 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4465 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4468 case PROP_MARGIN_TOP:
4469 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4472 case PROP_MARGIN_BOTTOM:
4473 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4476 case PROP_MARGIN_LEFT:
4477 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4480 case PROP_MARGIN_RIGHT:
4481 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4484 case PROP_BACKGROUND_COLOR:
4485 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4489 clutter_actor_set_content (actor, g_value_get_object (value));
4492 case PROP_CONTENT_GRAVITY:
4493 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4496 case PROP_MINIFICATION_FILTER:
4497 clutter_actor_set_content_scaling_filters (actor,
4498 g_value_get_enum (value),
4499 actor->priv->mag_filter);
4502 case PROP_MAGNIFICATION_FILTER:
4503 clutter_actor_set_content_scaling_filters (actor,
4504 actor->priv->min_filter,
4505 g_value_get_enum (value));
4509 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4515 clutter_actor_get_property (GObject *object,
4520 ClutterActor *actor = CLUTTER_ACTOR (object);
4521 ClutterActorPrivate *priv = actor->priv;
4526 g_value_set_float (value, clutter_actor_get_x (actor));
4530 g_value_set_float (value, clutter_actor_get_y (actor));
4534 g_value_set_float (value, clutter_actor_get_width (actor));
4538 g_value_set_float (value, clutter_actor_get_height (actor));
4543 const ClutterLayoutInfo *info;
4545 info = _clutter_actor_get_layout_info_or_defaults (actor);
4546 g_value_set_float (value, info->fixed_x);
4552 const ClutterLayoutInfo *info;
4554 info = _clutter_actor_get_layout_info_or_defaults (actor);
4555 g_value_set_float (value, info->fixed_y);
4559 case PROP_FIXED_POSITION_SET:
4560 g_value_set_boolean (value, priv->position_set);
4563 case PROP_MIN_WIDTH:
4565 const ClutterLayoutInfo *info;
4567 info = _clutter_actor_get_layout_info_or_defaults (actor);
4568 g_value_set_float (value, info->min_width);
4572 case PROP_MIN_HEIGHT:
4574 const ClutterLayoutInfo *info;
4576 info = _clutter_actor_get_layout_info_or_defaults (actor);
4577 g_value_set_float (value, info->min_height);
4581 case PROP_NATURAL_WIDTH:
4583 const ClutterLayoutInfo *info;
4585 info = _clutter_actor_get_layout_info_or_defaults (actor);
4586 g_value_set_float (value, info->natural_width);
4590 case PROP_NATURAL_HEIGHT:
4592 const ClutterLayoutInfo *info;
4594 info = _clutter_actor_get_layout_info_or_defaults (actor);
4595 g_value_set_float (value, info->natural_height);
4599 case PROP_MIN_WIDTH_SET:
4600 g_value_set_boolean (value, priv->min_width_set);
4603 case PROP_MIN_HEIGHT_SET:
4604 g_value_set_boolean (value, priv->min_height_set);
4607 case PROP_NATURAL_WIDTH_SET:
4608 g_value_set_boolean (value, priv->natural_width_set);
4611 case PROP_NATURAL_HEIGHT_SET:
4612 g_value_set_boolean (value, priv->natural_height_set);
4615 case PROP_REQUEST_MODE:
4616 g_value_set_enum (value, priv->request_mode);
4619 case PROP_ALLOCATION:
4620 g_value_set_boxed (value, &priv->allocation);
4624 g_value_set_float (value, clutter_actor_get_depth (actor));
4628 g_value_set_uint (value, priv->opacity);
4631 case PROP_OFFSCREEN_REDIRECT:
4632 g_value_set_enum (value, priv->offscreen_redirect);
4636 g_value_set_string (value, priv->name);
4640 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4644 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4648 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4652 g_value_set_boolean (value, priv->has_clip);
4657 ClutterGeometry clip;
4659 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4660 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4661 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4662 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4664 g_value_set_boxed (value, &clip);
4668 case PROP_CLIP_TO_ALLOCATION:
4669 g_value_set_boolean (value, priv->clip_to_allocation);
4674 const ClutterTransformInfo *info;
4676 info = _clutter_actor_get_transform_info_or_defaults (actor);
4677 g_value_set_double (value, info->scale_x);
4683 const ClutterTransformInfo *info;
4685 info = _clutter_actor_get_transform_info_or_defaults (actor);
4686 g_value_set_double (value, info->scale_y);
4690 case PROP_SCALE_CENTER_X:
4694 clutter_actor_get_scale_center (actor, ¢er, NULL);
4696 g_value_set_float (value, center);
4700 case PROP_SCALE_CENTER_Y:
4704 clutter_actor_get_scale_center (actor, NULL, ¢er);
4706 g_value_set_float (value, center);
4710 case PROP_SCALE_GRAVITY:
4711 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4715 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4718 case PROP_ROTATION_ANGLE_X:
4720 const ClutterTransformInfo *info;
4722 info = _clutter_actor_get_transform_info_or_defaults (actor);
4723 g_value_set_double (value, info->rx_angle);
4727 case PROP_ROTATION_ANGLE_Y:
4729 const ClutterTransformInfo *info;
4731 info = _clutter_actor_get_transform_info_or_defaults (actor);
4732 g_value_set_double (value, info->ry_angle);
4736 case PROP_ROTATION_ANGLE_Z:
4738 const ClutterTransformInfo *info;
4740 info = _clutter_actor_get_transform_info_or_defaults (actor);
4741 g_value_set_double (value, info->rz_angle);
4745 case PROP_ROTATION_CENTER_X:
4747 ClutterVertex center;
4749 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4754 g_value_set_boxed (value, ¢er);
4758 case PROP_ROTATION_CENTER_Y:
4760 ClutterVertex center;
4762 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4767 g_value_set_boxed (value, ¢er);
4771 case PROP_ROTATION_CENTER_Z:
4773 ClutterVertex center;
4775 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4780 g_value_set_boxed (value, ¢er);
4784 case PROP_ROTATION_CENTER_Z_GRAVITY:
4785 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4790 const ClutterTransformInfo *info;
4793 info = _clutter_actor_get_transform_info_or_defaults (actor);
4794 clutter_anchor_coord_get_units (actor, &info->anchor,
4798 g_value_set_float (value, anchor_x);
4804 const ClutterTransformInfo *info;
4807 info = _clutter_actor_get_transform_info_or_defaults (actor);
4808 clutter_anchor_coord_get_units (actor, &info->anchor,
4812 g_value_set_float (value, anchor_y);
4816 case PROP_ANCHOR_GRAVITY:
4817 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4820 case PROP_SHOW_ON_SET_PARENT:
4821 g_value_set_boolean (value, priv->show_on_set_parent);
4824 case PROP_TEXT_DIRECTION:
4825 g_value_set_enum (value, priv->text_direction);
4828 case PROP_HAS_POINTER:
4829 g_value_set_boolean (value, priv->has_pointer);
4832 case PROP_LAYOUT_MANAGER:
4833 g_value_set_object (value, priv->layout_manager);
4838 const ClutterLayoutInfo *info;
4840 info = _clutter_actor_get_layout_info_or_defaults (actor);
4841 g_value_set_enum (value, info->x_align);
4847 const ClutterLayoutInfo *info;
4849 info = _clutter_actor_get_layout_info_or_defaults (actor);
4850 g_value_set_enum (value, info->y_align);
4854 case PROP_MARGIN_TOP:
4856 const ClutterLayoutInfo *info;
4858 info = _clutter_actor_get_layout_info_or_defaults (actor);
4859 g_value_set_float (value, info->margin.top);
4863 case PROP_MARGIN_BOTTOM:
4865 const ClutterLayoutInfo *info;
4867 info = _clutter_actor_get_layout_info_or_defaults (actor);
4868 g_value_set_float (value, info->margin.bottom);
4872 case PROP_MARGIN_LEFT:
4874 const ClutterLayoutInfo *info;
4876 info = _clutter_actor_get_layout_info_or_defaults (actor);
4877 g_value_set_float (value, info->margin.left);
4881 case PROP_MARGIN_RIGHT:
4883 const ClutterLayoutInfo *info;
4885 info = _clutter_actor_get_layout_info_or_defaults (actor);
4886 g_value_set_float (value, info->margin.right);
4890 case PROP_BACKGROUND_COLOR_SET:
4891 g_value_set_boolean (value, priv->bg_color_set);
4894 case PROP_BACKGROUND_COLOR:
4895 g_value_set_boxed (value, &priv->bg_color);
4898 case PROP_FIRST_CHILD:
4899 g_value_set_object (value, priv->first_child);
4902 case PROP_LAST_CHILD:
4903 g_value_set_object (value, priv->last_child);
4907 g_value_set_object (value, priv->content);
4910 case PROP_CONTENT_GRAVITY:
4911 g_value_set_enum (value, priv->content_gravity);
4914 case PROP_CONTENT_BOX:
4916 ClutterActorBox box = { 0, };
4918 clutter_actor_get_content_box (actor, &box);
4919 g_value_set_boxed (value, &box);
4923 case PROP_MINIFICATION_FILTER:
4924 g_value_set_enum (value, priv->min_filter);
4927 case PROP_MAGNIFICATION_FILTER:
4928 g_value_set_enum (value, priv->mag_filter);
4932 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4938 clutter_actor_dispose (GObject *object)
4940 ClutterActor *self = CLUTTER_ACTOR (object);
4941 ClutterActorPrivate *priv = self->priv;
4943 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4945 g_type_name (G_OBJECT_TYPE (self)),
4948 g_signal_emit (self, actor_signals[DESTROY], 0);
4950 /* avoid recursing when called from clutter_actor_destroy() */
4951 if (priv->parent != NULL)
4953 ClutterActor *parent = priv->parent;
4955 /* go through the Container implementation unless this
4956 * is an internal child and has been marked as such.
4958 * removing the actor from its parent will reset the
4959 * realized and mapped states.
4961 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4962 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4964 clutter_actor_remove_child_internal (parent, self,
4965 REMOVE_CHILD_LEGACY_FLAGS);
4968 /* parent must be gone at this point */
4969 g_assert (priv->parent == NULL);
4971 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4973 /* can't be mapped or realized with no parent */
4974 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4975 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4978 g_clear_object (&priv->pango_context);
4979 g_clear_object (&priv->actions);
4980 g_clear_object (&priv->constraints);
4981 g_clear_object (&priv->effects);
4982 g_clear_object (&priv->flatten_effect);
4984 if (priv->layout_manager != NULL)
4986 clutter_layout_manager_set_container (priv->layout_manager, NULL);
4987 g_clear_object (&priv->layout_manager);
4990 if (priv->content != NULL)
4992 _clutter_content_detached (priv->content, self);
4993 g_clear_object (&priv->content);
4996 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5000 clutter_actor_finalize (GObject *object)
5002 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5004 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5005 priv->name != NULL ? priv->name : "<none>",
5007 g_type_name (G_OBJECT_TYPE (object)));
5009 _clutter_context_release_id (priv->id);
5011 g_free (priv->name);
5013 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5018 * clutter_actor_get_accessible:
5019 * @self: a #ClutterActor
5021 * Returns the accessible object that describes the actor to an
5022 * assistive technology.
5024 * If no class-specific #AtkObject implementation is available for the
5025 * actor instance in question, it will inherit an #AtkObject
5026 * implementation from the first ancestor class for which such an
5027 * implementation is defined.
5029 * The documentation of the <ulink
5030 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5031 * library contains more information about accessible objects and
5034 * Returns: (transfer none): the #AtkObject associated with @actor
5037 clutter_actor_get_accessible (ClutterActor *self)
5039 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5041 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5045 clutter_actor_real_get_accessible (ClutterActor *actor)
5047 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5051 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5053 AtkObject *accessible;
5055 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5056 if (accessible != NULL)
5057 g_object_ref (accessible);
5063 atk_implementor_iface_init (AtkImplementorIface *iface)
5065 iface->ref_accessible = _clutter_actor_ref_accessible;
5069 clutter_actor_update_default_paint_volume (ClutterActor *self,
5070 ClutterPaintVolume *volume)
5072 ClutterActorPrivate *priv = self->priv;
5073 gboolean res = FALSE;
5075 /* we start from the allocation */
5076 clutter_paint_volume_set_width (volume,
5077 priv->allocation.x2 - priv->allocation.x1);
5078 clutter_paint_volume_set_height (volume,
5079 priv->allocation.y2 - priv->allocation.y1);
5081 /* if the actor has a clip set then we have a pretty definite
5082 * size for the paint volume: the actor cannot possibly paint
5083 * outside the clip region.
5085 if (priv->clip_to_allocation)
5087 /* the allocation has already been set, so we just flip the
5094 ClutterActor *child;
5096 if (priv->has_clip &&
5097 priv->clip.width >= 0 &&
5098 priv->clip.height >= 0)
5100 ClutterVertex origin;
5102 origin.x = priv->clip.x;
5103 origin.y = priv->clip.y;
5106 clutter_paint_volume_set_origin (volume, &origin);
5107 clutter_paint_volume_set_width (volume, priv->clip.width);
5108 clutter_paint_volume_set_height (volume, priv->clip.height);
5113 /* if we don't have children we just bail out here... */
5114 if (priv->n_children == 0)
5117 /* ...but if we have children then we ask for their paint volume in
5118 * our coordinates. if any of our children replies that it doesn't
5119 * have a paint volume, we bail out
5121 for (child = priv->first_child;
5123 child = child->priv->next_sibling)
5125 const ClutterPaintVolume *child_volume;
5127 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5128 if (child_volume == NULL)
5134 clutter_paint_volume_union (volume, child_volume);
5144 clutter_actor_real_get_paint_volume (ClutterActor *self,
5145 ClutterPaintVolume *volume)
5147 ClutterActorClass *klass;
5150 klass = CLUTTER_ACTOR_GET_CLASS (self);
5152 /* XXX - this thoroughly sucks, but we don't want to penalize users
5153 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5154 * redraw. This should go away in 2.0.
5156 if (klass->paint == clutter_actor_real_paint &&
5157 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5163 /* this is the default return value: we cannot know if a class
5164 * is going to paint outside its allocation, so we take the
5165 * conservative approach.
5170 if (clutter_actor_update_default_paint_volume (self, volume))
5177 * clutter_actor_get_default_paint_volume:
5178 * @self: a #ClutterActor
5180 * Retrieves the default paint volume for @self.
5182 * This function provides the same #ClutterPaintVolume that would be
5183 * computed by the default implementation inside #ClutterActor of the
5184 * #ClutterActorClass.get_paint_volume() virtual function.
5186 * This function should only be used by #ClutterActor subclasses that
5187 * cannot chain up to the parent implementation when computing their
5190 * Return value: (transfer none): a pointer to the default
5191 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5192 * the actor could not compute a valid paint volume. The returned value
5193 * is not guaranteed to be stable across multiple frames, so if you
5194 * want to retain it, you will need to copy it using
5195 * clutter_paint_volume_copy().
5199 const ClutterPaintVolume *
5200 clutter_actor_get_default_paint_volume (ClutterActor *self)
5202 ClutterPaintVolume volume;
5203 ClutterPaintVolume *res;
5205 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5208 _clutter_paint_volume_init_static (&volume, self);
5209 if (clutter_actor_update_default_paint_volume (self, &volume))
5211 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5215 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5216 _clutter_paint_volume_copy_static (&volume, res);
5220 clutter_paint_volume_free (&volume);
5226 clutter_actor_real_has_overlaps (ClutterActor *self)
5228 /* By default we'll assume that all actors need an offscreen redirect to get
5229 * the correct opacity. Actors such as ClutterTexture that would never need
5230 * an offscreen redirect can override this to return FALSE. */
5235 clutter_actor_real_destroy (ClutterActor *actor)
5237 ClutterActorIter iter;
5239 clutter_actor_iter_init (&iter, actor);
5240 while (clutter_actor_iter_next (&iter, NULL))
5241 clutter_actor_iter_destroy (&iter);
5245 clutter_actor_constructor (GType gtype,
5247 GObjectConstructParam *props)
5249 GObjectClass *gobject_class;
5253 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5254 retval = gobject_class->constructor (gtype, n_props, props);
5255 self = CLUTTER_ACTOR (retval);
5257 if (self->priv->layout_manager == NULL)
5259 ClutterLayoutManager *default_layout;
5261 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5263 default_layout = clutter_fixed_layout_new ();
5264 clutter_actor_set_layout_manager (self, default_layout);
5271 clutter_actor_class_init (ClutterActorClass *klass)
5273 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5275 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5276 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5277 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5278 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5280 object_class->constructor = clutter_actor_constructor;
5281 object_class->set_property = clutter_actor_set_property;
5282 object_class->get_property = clutter_actor_get_property;
5283 object_class->dispose = clutter_actor_dispose;
5284 object_class->finalize = clutter_actor_finalize;
5286 klass->show = clutter_actor_real_show;
5287 klass->show_all = clutter_actor_show;
5288 klass->hide = clutter_actor_real_hide;
5289 klass->hide_all = clutter_actor_hide;
5290 klass->map = clutter_actor_real_map;
5291 klass->unmap = clutter_actor_real_unmap;
5292 klass->unrealize = clutter_actor_real_unrealize;
5293 klass->pick = clutter_actor_real_pick;
5294 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5295 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5296 klass->allocate = clutter_actor_real_allocate;
5297 klass->queue_redraw = clutter_actor_real_queue_redraw;
5298 klass->queue_relayout = clutter_actor_real_queue_relayout;
5299 klass->apply_transform = clutter_actor_real_apply_transform;
5300 klass->get_accessible = clutter_actor_real_get_accessible;
5301 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5302 klass->has_overlaps = clutter_actor_real_has_overlaps;
5303 klass->paint = clutter_actor_real_paint;
5304 klass->destroy = clutter_actor_real_destroy;
5306 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5311 * X coordinate of the actor in pixels. If written, forces a fixed
5312 * position for the actor. If read, returns the fixed position if any,
5313 * otherwise the allocation if available, otherwise 0.
5315 * The #ClutterActor:x property is animatable.
5318 g_param_spec_float ("x",
5320 P_("X coordinate of the actor"),
5321 -G_MAXFLOAT, G_MAXFLOAT,
5324 G_PARAM_STATIC_STRINGS |
5325 CLUTTER_PARAM_ANIMATABLE);
5330 * Y coordinate of the actor in pixels. If written, forces a fixed
5331 * position for the actor. If read, returns the fixed position if
5332 * any, otherwise the allocation if available, otherwise 0.
5334 * The #ClutterActor:y property is animatable.
5337 g_param_spec_float ("y",
5339 P_("Y coordinate of the actor"),
5340 -G_MAXFLOAT, G_MAXFLOAT,
5343 G_PARAM_STATIC_STRINGS |
5344 CLUTTER_PARAM_ANIMATABLE);
5347 * ClutterActor:width:
5349 * Width of the actor (in pixels). If written, forces the minimum and
5350 * natural size request of the actor to the given width. If read, returns
5351 * the allocated width if available, otherwise the width request.
5353 * The #ClutterActor:width property is animatable.
5355 obj_props[PROP_WIDTH] =
5356 g_param_spec_float ("width",
5358 P_("Width of the actor"),
5362 G_PARAM_STATIC_STRINGS |
5363 CLUTTER_PARAM_ANIMATABLE);
5366 * ClutterActor:height:
5368 * Height of the actor (in pixels). If written, forces the minimum and
5369 * natural size request of the actor to the given height. If read, returns
5370 * the allocated height if available, otherwise the height request.
5372 * The #ClutterActor:height property is animatable.
5374 obj_props[PROP_HEIGHT] =
5375 g_param_spec_float ("height",
5377 P_("Height of the actor"),
5381 G_PARAM_STATIC_STRINGS |
5382 CLUTTER_PARAM_ANIMATABLE);
5385 * ClutterActor:fixed-x:
5387 * The fixed X position of the actor in pixels.
5389 * Writing this property sets #ClutterActor:fixed-position-set
5390 * property as well, as a side effect
5394 obj_props[PROP_FIXED_X] =
5395 g_param_spec_float ("fixed-x",
5397 P_("Forced X position of the actor"),
5398 -G_MAXFLOAT, G_MAXFLOAT,
5400 CLUTTER_PARAM_READWRITE);
5403 * ClutterActor:fixed-y:
5405 * The fixed Y position of the actor in pixels.
5407 * Writing this property sets the #ClutterActor:fixed-position-set
5408 * property as well, as a side effect
5412 obj_props[PROP_FIXED_Y] =
5413 g_param_spec_float ("fixed-y",
5415 P_("Forced Y position of the actor"),
5416 -G_MAXFLOAT, G_MAXFLOAT,
5418 CLUTTER_PARAM_READWRITE);
5421 * ClutterActor:fixed-position-set:
5423 * This flag controls whether the #ClutterActor:fixed-x and
5424 * #ClutterActor:fixed-y properties are used
5428 obj_props[PROP_FIXED_POSITION_SET] =
5429 g_param_spec_boolean ("fixed-position-set",
5430 P_("Fixed position set"),
5431 P_("Whether to use fixed positioning for the actor"),
5433 CLUTTER_PARAM_READWRITE);
5436 * ClutterActor:min-width:
5438 * A forced minimum width request for the actor, in pixels
5440 * Writing this property sets the #ClutterActor:min-width-set property
5441 * as well, as a side effect.
5443 *This property overrides the usual width request of the actor.
5447 obj_props[PROP_MIN_WIDTH] =
5448 g_param_spec_float ("min-width",
5450 P_("Forced minimum width request for the actor"),
5453 CLUTTER_PARAM_READWRITE);
5456 * ClutterActor:min-height:
5458 * A forced minimum height request for the actor, in pixels
5460 * Writing this property sets the #ClutterActor:min-height-set property
5461 * as well, as a side effect. This property overrides the usual height
5462 * request of the actor.
5466 obj_props[PROP_MIN_HEIGHT] =
5467 g_param_spec_float ("min-height",
5469 P_("Forced minimum height request for the actor"),
5472 CLUTTER_PARAM_READWRITE);
5475 * ClutterActor:natural-width:
5477 * A forced natural width request for the actor, in pixels
5479 * Writing this property sets the #ClutterActor:natural-width-set
5480 * property as well, as a side effect. This property overrides the
5481 * usual width request of the actor
5485 obj_props[PROP_NATURAL_WIDTH] =
5486 g_param_spec_float ("natural-width",
5487 P_("Natural Width"),
5488 P_("Forced natural width request for the actor"),
5491 CLUTTER_PARAM_READWRITE);
5494 * ClutterActor:natural-height:
5496 * A forced natural height request for the actor, in pixels
5498 * Writing this property sets the #ClutterActor:natural-height-set
5499 * property as well, as a side effect. This property overrides the
5500 * usual height request of the actor
5504 obj_props[PROP_NATURAL_HEIGHT] =
5505 g_param_spec_float ("natural-height",
5506 P_("Natural Height"),
5507 P_("Forced natural height request for the actor"),
5510 CLUTTER_PARAM_READWRITE);
5513 * ClutterActor:min-width-set:
5515 * This flag controls whether the #ClutterActor:min-width property
5520 obj_props[PROP_MIN_WIDTH_SET] =
5521 g_param_spec_boolean ("min-width-set",
5522 P_("Minimum width set"),
5523 P_("Whether to use the min-width property"),
5525 CLUTTER_PARAM_READWRITE);
5528 * ClutterActor:min-height-set:
5530 * This flag controls whether the #ClutterActor:min-height property
5535 obj_props[PROP_MIN_HEIGHT_SET] =
5536 g_param_spec_boolean ("min-height-set",
5537 P_("Minimum height set"),
5538 P_("Whether to use the min-height property"),
5540 CLUTTER_PARAM_READWRITE);
5543 * ClutterActor:natural-width-set:
5545 * This flag controls whether the #ClutterActor:natural-width property
5550 obj_props[PROP_NATURAL_WIDTH_SET] =
5551 g_param_spec_boolean ("natural-width-set",
5552 P_("Natural width set"),
5553 P_("Whether to use the natural-width property"),
5555 CLUTTER_PARAM_READWRITE);
5558 * ClutterActor:natural-height-set:
5560 * This flag controls whether the #ClutterActor:natural-height property
5565 obj_props[PROP_NATURAL_HEIGHT_SET] =
5566 g_param_spec_boolean ("natural-height-set",
5567 P_("Natural height set"),
5568 P_("Whether to use the natural-height property"),
5570 CLUTTER_PARAM_READWRITE);
5573 * ClutterActor:allocation:
5575 * The allocation for the actor, in pixels
5577 * This is property is read-only, but you might monitor it to know when an
5578 * actor moves or resizes
5582 obj_props[PROP_ALLOCATION] =
5583 g_param_spec_boxed ("allocation",
5585 P_("The actor's allocation"),
5586 CLUTTER_TYPE_ACTOR_BOX,
5587 CLUTTER_PARAM_READABLE);
5590 * ClutterActor:request-mode:
5592 * Request mode for the #ClutterActor. The request mode determines the
5593 * type of geometry management used by the actor, either height for width
5594 * (the default) or width for height.
5596 * For actors implementing height for width, the parent container should get
5597 * the preferred width first, and then the preferred height for that width.
5599 * For actors implementing width for height, the parent container should get
5600 * the preferred height first, and then the preferred width for that height.
5605 * ClutterRequestMode mode;
5606 * gfloat natural_width, min_width;
5607 * gfloat natural_height, min_height;
5609 * mode = clutter_actor_get_request_mode (child);
5610 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5612 * clutter_actor_get_preferred_width (child, -1,
5614 * &natural_width);
5615 * clutter_actor_get_preferred_height (child, natural_width,
5617 * &natural_height);
5621 * clutter_actor_get_preferred_height (child, -1,
5623 * &natural_height);
5624 * clutter_actor_get_preferred_width (child, natural_height,
5626 * &natural_width);
5630 * will retrieve the minimum and natural width and height depending on the
5631 * preferred request mode of the #ClutterActor "child".
5633 * The clutter_actor_get_preferred_size() function will implement this
5638 obj_props[PROP_REQUEST_MODE] =
5639 g_param_spec_enum ("request-mode",
5641 P_("The actor's request mode"),
5642 CLUTTER_TYPE_REQUEST_MODE,
5643 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5644 CLUTTER_PARAM_READWRITE);
5647 * ClutterActor:depth:
5649 * The position of the actor on the Z axis.
5651 * The #ClutterActor:depth property is relative to the parent's
5654 * The #ClutterActor:depth property is animatable.
5658 obj_props[PROP_DEPTH] =
5659 g_param_spec_float ("depth",
5661 P_("Position on the Z axis"),
5662 -G_MAXFLOAT, G_MAXFLOAT,
5665 G_PARAM_STATIC_STRINGS |
5666 CLUTTER_PARAM_ANIMATABLE);
5669 * ClutterActor:opacity:
5671 * Opacity of an actor, between 0 (fully transparent) and
5672 * 255 (fully opaque)
5674 * The #ClutterActor:opacity property is animatable.
5676 obj_props[PROP_OPACITY] =
5677 g_param_spec_uint ("opacity",
5679 P_("Opacity of an actor"),
5683 G_PARAM_STATIC_STRINGS |
5684 CLUTTER_PARAM_ANIMATABLE);
5687 * ClutterActor:offscreen-redirect:
5689 * Determines the conditions in which the actor will be redirected
5690 * to an offscreen framebuffer while being painted. For example this
5691 * can be used to cache an actor in a framebuffer or for improved
5692 * handling of transparent actors. See
5693 * clutter_actor_set_offscreen_redirect() for details.
5697 obj_props[PROP_OFFSCREEN_REDIRECT] =
5698 g_param_spec_flags ("offscreen-redirect",
5699 P_("Offscreen redirect"),
5700 P_("Flags controlling when to flatten the actor into a single image"),
5701 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5703 CLUTTER_PARAM_READWRITE);
5706 * ClutterActor:visible:
5708 * Whether the actor is set to be visible or not
5710 * See also #ClutterActor:mapped
5712 obj_props[PROP_VISIBLE] =
5713 g_param_spec_boolean ("visible",
5715 P_("Whether the actor is visible or not"),
5717 CLUTTER_PARAM_READWRITE);
5720 * ClutterActor:mapped:
5722 * Whether the actor is mapped (will be painted when the stage
5723 * to which it belongs is mapped)
5727 obj_props[PROP_MAPPED] =
5728 g_param_spec_boolean ("mapped",
5730 P_("Whether the actor will be painted"),
5732 CLUTTER_PARAM_READABLE);
5735 * ClutterActor:realized:
5737 * Whether the actor has been realized
5741 obj_props[PROP_REALIZED] =
5742 g_param_spec_boolean ("realized",
5744 P_("Whether the actor has been realized"),
5746 CLUTTER_PARAM_READABLE);
5749 * ClutterActor:reactive:
5751 * Whether the actor is reactive to events or not
5753 * Only reactive actors will emit event-related signals
5757 obj_props[PROP_REACTIVE] =
5758 g_param_spec_boolean ("reactive",
5760 P_("Whether the actor is reactive to events"),
5762 CLUTTER_PARAM_READWRITE);
5765 * ClutterActor:has-clip:
5767 * Whether the actor has the #ClutterActor:clip property set or not
5769 obj_props[PROP_HAS_CLIP] =
5770 g_param_spec_boolean ("has-clip",
5772 P_("Whether the actor has a clip set"),
5774 CLUTTER_PARAM_READABLE);
5777 * ClutterActor:clip:
5779 * The clip region for the actor, in actor-relative coordinates
5781 * Every part of the actor outside the clip region will not be
5784 obj_props[PROP_CLIP] =
5785 g_param_spec_boxed ("clip",
5787 P_("The clip region for the actor"),
5788 CLUTTER_TYPE_GEOMETRY,
5789 CLUTTER_PARAM_READWRITE);
5792 * ClutterActor:name:
5794 * The name of the actor
5798 obj_props[PROP_NAME] =
5799 g_param_spec_string ("name",
5801 P_("Name of the actor"),
5803 CLUTTER_PARAM_READWRITE);
5806 * ClutterActor:scale-x:
5808 * The horizontal scale of the actor.
5810 * The #ClutterActor:scale-x property is animatable.
5814 obj_props[PROP_SCALE_X] =
5815 g_param_spec_double ("scale-x",
5817 P_("Scale factor on the X axis"),
5821 G_PARAM_STATIC_STRINGS |
5822 CLUTTER_PARAM_ANIMATABLE);
5825 * ClutterActor:scale-y:
5827 * The vertical scale of the actor.
5829 * The #ClutterActor:scale-y property is animatable.
5833 obj_props[PROP_SCALE_Y] =
5834 g_param_spec_double ("scale-y",
5836 P_("Scale factor on the Y axis"),
5840 G_PARAM_STATIC_STRINGS |
5841 CLUTTER_PARAM_ANIMATABLE);
5844 * ClutterActor:scale-center-x:
5846 * The horizontal center point for scaling
5850 obj_props[PROP_SCALE_CENTER_X] =
5851 g_param_spec_float ("scale-center-x",
5852 P_("Scale Center X"),
5853 P_("Horizontal scale center"),
5854 -G_MAXFLOAT, G_MAXFLOAT,
5856 CLUTTER_PARAM_READWRITE);
5859 * ClutterActor:scale-center-y:
5861 * The vertical center point for scaling
5865 obj_props[PROP_SCALE_CENTER_Y] =
5866 g_param_spec_float ("scale-center-y",
5867 P_("Scale Center Y"),
5868 P_("Vertical scale center"),
5869 -G_MAXFLOAT, G_MAXFLOAT,
5871 CLUTTER_PARAM_READWRITE);
5874 * ClutterActor:scale-gravity:
5876 * The center point for scaling expressed as a #ClutterGravity
5880 obj_props[PROP_SCALE_GRAVITY] =
5881 g_param_spec_enum ("scale-gravity",
5882 P_("Scale Gravity"),
5883 P_("The center of scaling"),
5884 CLUTTER_TYPE_GRAVITY,
5885 CLUTTER_GRAVITY_NONE,
5886 CLUTTER_PARAM_READWRITE);
5889 * ClutterActor:rotation-angle-x:
5891 * The rotation angle on the X axis.
5893 * The #ClutterActor:rotation-angle-x property is animatable.
5897 obj_props[PROP_ROTATION_ANGLE_X] =
5898 g_param_spec_double ("rotation-angle-x",
5899 P_("Rotation Angle X"),
5900 P_("The rotation angle on the X axis"),
5901 -G_MAXDOUBLE, G_MAXDOUBLE,
5904 G_PARAM_STATIC_STRINGS |
5905 CLUTTER_PARAM_ANIMATABLE);
5908 * ClutterActor:rotation-angle-y:
5910 * The rotation angle on the Y axis
5912 * The #ClutterActor:rotation-angle-y property is animatable.
5916 obj_props[PROP_ROTATION_ANGLE_Y] =
5917 g_param_spec_double ("rotation-angle-y",
5918 P_("Rotation Angle Y"),
5919 P_("The rotation angle on the Y axis"),
5920 -G_MAXDOUBLE, G_MAXDOUBLE,
5923 G_PARAM_STATIC_STRINGS |
5924 CLUTTER_PARAM_ANIMATABLE);
5927 * ClutterActor:rotation-angle-z:
5929 * The rotation angle on the Z axis
5931 * The #ClutterActor:rotation-angle-z property is animatable.
5935 obj_props[PROP_ROTATION_ANGLE_Z] =
5936 g_param_spec_double ("rotation-angle-z",
5937 P_("Rotation Angle Z"),
5938 P_("The rotation angle on the Z axis"),
5939 -G_MAXDOUBLE, G_MAXDOUBLE,
5942 G_PARAM_STATIC_STRINGS |
5943 CLUTTER_PARAM_ANIMATABLE);
5946 * ClutterActor:rotation-center-x:
5948 * The rotation center on the X axis.
5952 obj_props[PROP_ROTATION_CENTER_X] =
5953 g_param_spec_boxed ("rotation-center-x",
5954 P_("Rotation Center X"),
5955 P_("The rotation center on the X axis"),
5956 CLUTTER_TYPE_VERTEX,
5957 CLUTTER_PARAM_READWRITE);
5960 * ClutterActor:rotation-center-y:
5962 * The rotation center on the Y axis.
5966 obj_props[PROP_ROTATION_CENTER_Y] =
5967 g_param_spec_boxed ("rotation-center-y",
5968 P_("Rotation Center Y"),
5969 P_("The rotation center on the Y axis"),
5970 CLUTTER_TYPE_VERTEX,
5971 CLUTTER_PARAM_READWRITE);
5974 * ClutterActor:rotation-center-z:
5976 * The rotation center on the Z axis.
5980 obj_props[PROP_ROTATION_CENTER_Z] =
5981 g_param_spec_boxed ("rotation-center-z",
5982 P_("Rotation Center Z"),
5983 P_("The rotation center on the Z axis"),
5984 CLUTTER_TYPE_VERTEX,
5985 CLUTTER_PARAM_READWRITE);
5988 * ClutterActor:rotation-center-z-gravity:
5990 * The rotation center on the Z axis expressed as a #ClutterGravity.
5994 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5995 g_param_spec_enum ("rotation-center-z-gravity",
5996 P_("Rotation Center Z Gravity"),
5997 P_("Center point for rotation around the Z axis"),
5998 CLUTTER_TYPE_GRAVITY,
5999 CLUTTER_GRAVITY_NONE,
6000 CLUTTER_PARAM_READWRITE);
6003 * ClutterActor:anchor-x:
6005 * The X coordinate of an actor's anchor point, relative to
6006 * the actor coordinate space, in pixels
6010 obj_props[PROP_ANCHOR_X] =
6011 g_param_spec_float ("anchor-x",
6013 P_("X coordinate of the anchor point"),
6014 -G_MAXFLOAT, G_MAXFLOAT,
6016 CLUTTER_PARAM_READWRITE);
6019 * ClutterActor:anchor-y:
6021 * The Y coordinate of an actor's anchor point, relative to
6022 * the actor coordinate space, in pixels
6026 obj_props[PROP_ANCHOR_Y] =
6027 g_param_spec_float ("anchor-y",
6029 P_("Y coordinate of the anchor point"),
6030 -G_MAXFLOAT, G_MAXFLOAT,
6032 CLUTTER_PARAM_READWRITE);
6035 * ClutterActor:anchor-gravity:
6037 * The anchor point expressed as a #ClutterGravity
6041 obj_props[PROP_ANCHOR_GRAVITY] =
6042 g_param_spec_enum ("anchor-gravity",
6043 P_("Anchor Gravity"),
6044 P_("The anchor point as a ClutterGravity"),
6045 CLUTTER_TYPE_GRAVITY,
6046 CLUTTER_GRAVITY_NONE,
6047 CLUTTER_PARAM_READWRITE);
6050 * ClutterActor:show-on-set-parent:
6052 * If %TRUE, the actor is automatically shown when parented.
6054 * Calling clutter_actor_hide() on an actor which has not been
6055 * parented will set this property to %FALSE as a side effect.
6059 obj_props[PROP_SHOW_ON_SET_PARENT] =
6060 g_param_spec_boolean ("show-on-set-parent",
6061 P_("Show on set parent"),
6062 P_("Whether the actor is shown when parented"),
6064 CLUTTER_PARAM_READWRITE);
6067 * ClutterActor:clip-to-allocation:
6069 * Whether the clip region should track the allocated area
6072 * This property is ignored if a clip area has been explicitly
6073 * set using clutter_actor_set_clip().
6077 obj_props[PROP_CLIP_TO_ALLOCATION] =
6078 g_param_spec_boolean ("clip-to-allocation",
6079 P_("Clip to Allocation"),
6080 P_("Sets the clip region to track the actor's allocation"),
6082 CLUTTER_PARAM_READWRITE);
6085 * ClutterActor:text-direction:
6087 * The direction of the text inside a #ClutterActor.
6091 obj_props[PROP_TEXT_DIRECTION] =
6092 g_param_spec_enum ("text-direction",
6093 P_("Text Direction"),
6094 P_("Direction of the text"),
6095 CLUTTER_TYPE_TEXT_DIRECTION,
6096 CLUTTER_TEXT_DIRECTION_LTR,
6097 CLUTTER_PARAM_READWRITE);
6100 * ClutterActor:has-pointer:
6102 * Whether the actor contains the pointer of a #ClutterInputDevice
6107 obj_props[PROP_HAS_POINTER] =
6108 g_param_spec_boolean ("has-pointer",
6110 P_("Whether the actor contains the pointer of an input device"),
6112 CLUTTER_PARAM_READABLE);
6115 * ClutterActor:actions:
6117 * Adds a #ClutterAction to the actor
6121 obj_props[PROP_ACTIONS] =
6122 g_param_spec_object ("actions",
6124 P_("Adds an action to the actor"),
6125 CLUTTER_TYPE_ACTION,
6126 CLUTTER_PARAM_WRITABLE);
6129 * ClutterActor:constraints:
6131 * Adds a #ClutterConstraint to the actor
6135 obj_props[PROP_CONSTRAINTS] =
6136 g_param_spec_object ("constraints",
6138 P_("Adds a constraint to the actor"),
6139 CLUTTER_TYPE_CONSTRAINT,
6140 CLUTTER_PARAM_WRITABLE);
6143 * ClutterActor:effect:
6145 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6149 obj_props[PROP_EFFECT] =
6150 g_param_spec_object ("effect",
6152 P_("Add an effect to be applied on the actor"),
6153 CLUTTER_TYPE_EFFECT,
6154 CLUTTER_PARAM_WRITABLE);
6157 * ClutterActor:layout-manager:
6159 * A delegate object for controlling the layout of the children of
6164 obj_props[PROP_LAYOUT_MANAGER] =
6165 g_param_spec_object ("layout-manager",
6166 P_("Layout Manager"),
6167 P_("The object controlling the layout of an actor's children"),
6168 CLUTTER_TYPE_LAYOUT_MANAGER,
6169 CLUTTER_PARAM_READWRITE);
6173 * ClutterActor:x-align:
6175 * The alignment of an actor on the X axis, if the actor has been given
6176 * extra space for its allocation.
6180 obj_props[PROP_X_ALIGN] =
6181 g_param_spec_enum ("x-align",
6183 P_("The alignment of the actor on the X axis within its allocation"),
6184 CLUTTER_TYPE_ACTOR_ALIGN,
6185 CLUTTER_ACTOR_ALIGN_FILL,
6186 CLUTTER_PARAM_READWRITE);
6189 * ClutterActor:y-align:
6191 * The alignment of an actor on the Y axis, if the actor has been given
6192 * extra space for its allocation.
6196 obj_props[PROP_Y_ALIGN] =
6197 g_param_spec_enum ("y-align",
6199 P_("The alignment of the actor on the Y axis within its allocation"),
6200 CLUTTER_TYPE_ACTOR_ALIGN,
6201 CLUTTER_ACTOR_ALIGN_FILL,
6202 CLUTTER_PARAM_READWRITE);
6205 * ClutterActor:margin-top:
6207 * The margin (in pixels) from the top of the actor.
6209 * This property adds a margin to the actor's preferred size; the margin
6210 * will be automatically taken into account when allocating the actor.
6214 obj_props[PROP_MARGIN_TOP] =
6215 g_param_spec_float ("margin-top",
6217 P_("Extra space at the top"),
6220 CLUTTER_PARAM_READWRITE);
6223 * ClutterActor:margin-bottom:
6225 * The margin (in pixels) from the bottom of the actor.
6227 * This property adds a margin to the actor's preferred size; the margin
6228 * will be automatically taken into account when allocating the actor.
6232 obj_props[PROP_MARGIN_BOTTOM] =
6233 g_param_spec_float ("margin-bottom",
6234 P_("Margin Bottom"),
6235 P_("Extra space at the bottom"),
6238 CLUTTER_PARAM_READWRITE);
6241 * ClutterActor:margin-left:
6243 * The margin (in pixels) from the left of the actor.
6245 * This property adds a margin to the actor's preferred size; the margin
6246 * will be automatically taken into account when allocating the actor.
6250 obj_props[PROP_MARGIN_LEFT] =
6251 g_param_spec_float ("margin-left",
6253 P_("Extra space at the left"),
6256 CLUTTER_PARAM_READWRITE);
6259 * ClutterActor:margin-right:
6261 * The margin (in pixels) from the right of the actor.
6263 * This property adds a margin to the actor's preferred size; the margin
6264 * will be automatically taken into account when allocating the actor.
6268 obj_props[PROP_MARGIN_RIGHT] =
6269 g_param_spec_float ("margin-right",
6271 P_("Extra space at the right"),
6274 CLUTTER_PARAM_READWRITE);
6277 * ClutterActor:background-color-set:
6279 * Whether the #ClutterActor:background-color property has been set.
6283 obj_props[PROP_BACKGROUND_COLOR_SET] =
6284 g_param_spec_boolean ("background-color-set",
6285 P_("Background Color Set"),
6286 P_("Whether the background color is set"),
6288 CLUTTER_PARAM_READABLE);
6291 * ClutterActor:background-color:
6293 * Paints a solid fill of the actor's allocation using the specified
6296 * The #ClutterActor:background-color property is animatable.
6300 obj_props[PROP_BACKGROUND_COLOR] =
6301 clutter_param_spec_color ("background-color",
6302 P_("Background color"),
6303 P_("The actor's background color"),
6304 CLUTTER_COLOR_Transparent,
6306 G_PARAM_STATIC_STRINGS |
6307 CLUTTER_PARAM_ANIMATABLE);
6310 * ClutterActor:first-child:
6312 * The actor's first child.
6316 obj_props[PROP_FIRST_CHILD] =
6317 g_param_spec_object ("first-child",
6319 P_("The actor's first child"),
6321 CLUTTER_PARAM_READABLE);
6324 * ClutterActor:last-child:
6326 * The actor's last child.
6330 obj_props[PROP_LAST_CHILD] =
6331 g_param_spec_object ("last-child",
6333 P_("The actor's last child"),
6335 CLUTTER_PARAM_READABLE);
6338 * ClutterActor:content:
6340 * The #ClutterContent implementation that controls the content
6345 obj_props[PROP_CONTENT] =
6346 g_param_spec_object ("content",
6348 P_("Delegate object for painting the actor's content"),
6349 CLUTTER_TYPE_CONTENT,
6350 CLUTTER_PARAM_READWRITE);
6353 * ClutterActor:content-gravity:
6355 * The alignment that should be honoured by the #ClutterContent
6356 * set with the #ClutterActor:content property.
6358 * Changing the value of this property will change the bounding box of
6359 * the content; you can use the #ClutterActor:content-box property to
6360 * get the position and size of the content within the actor's
6363 * This property is meaningful only for #ClutterContent implementations
6364 * that have a preferred size, and if the preferred size is smaller than
6365 * the actor's allocation.
6369 obj_props[PROP_CONTENT_GRAVITY] =
6370 g_param_spec_enum ("content-gravity",
6371 P_("Content Gravity"),
6372 P_("Alignment of the actor's content"),
6373 CLUTTER_TYPE_CONTENT_GRAVITY,
6374 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6375 CLUTTER_PARAM_READWRITE);
6378 * ClutterActor:content-box:
6380 * The bounding box for the #ClutterContent used by the actor.
6382 * The value of this property is controlled by the #ClutterActor:allocation
6383 * and #ClutterActor:content-gravity properties of #ClutterActor.
6385 * The bounding box for the content is guaranteed to never exceed the
6386 * allocation's of the actor.
6390 obj_props[PROP_CONTENT_BOX] =
6391 g_param_spec_boxed ("content-box",
6393 P_("The bounding box of the actor's content"),
6394 CLUTTER_TYPE_ACTOR_BOX,
6395 CLUTTER_PARAM_READABLE);
6397 obj_props[PROP_MINIFICATION_FILTER] =
6398 g_param_spec_enum ("minification-filter",
6399 P_("Minification Filter"),
6400 P_("The filter used when reducing the size of the content"),
6401 CLUTTER_TYPE_SCALING_FILTER,
6402 CLUTTER_SCALING_FILTER_LINEAR,
6403 CLUTTER_PARAM_READWRITE);
6405 obj_props[PROP_MAGNIFICATION_FILTER] =
6406 g_param_spec_enum ("magnification-filter",
6407 P_("Magnification Filter"),
6408 P_("The filter used when increasing the size of the content"),
6409 CLUTTER_TYPE_SCALING_FILTER,
6410 CLUTTER_SCALING_FILTER_LINEAR,
6411 CLUTTER_PARAM_READWRITE);
6413 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6416 * ClutterActor::destroy:
6417 * @actor: the #ClutterActor which emitted the signal
6419 * The ::destroy signal notifies that all references held on the
6420 * actor which emitted it should be released.
6422 * The ::destroy signal should be used by all holders of a reference
6425 * This signal might result in the finalization of the #ClutterActor
6426 * if all references are released.
6428 * Composite actors and actors implementing the #ClutterContainer
6429 * interface should override the default implementation of the
6430 * class handler of this signal and call clutter_actor_destroy() on
6431 * their children. When overriding the default class handler, it is
6432 * required to chain up to the parent's implementation.
6436 actor_signals[DESTROY] =
6437 g_signal_new (I_("destroy"),
6438 G_TYPE_FROM_CLASS (object_class),
6439 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6440 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6442 _clutter_marshal_VOID__VOID,
6445 * ClutterActor::show:
6446 * @actor: the object which received the signal
6448 * The ::show signal is emitted when an actor is visible and
6449 * rendered on the stage.
6453 actor_signals[SHOW] =
6454 g_signal_new (I_("show"),
6455 G_TYPE_FROM_CLASS (object_class),
6457 G_STRUCT_OFFSET (ClutterActorClass, show),
6459 _clutter_marshal_VOID__VOID,
6462 * ClutterActor::hide:
6463 * @actor: the object which received the signal
6465 * The ::hide signal is emitted when an actor is no longer rendered
6470 actor_signals[HIDE] =
6471 g_signal_new (I_("hide"),
6472 G_TYPE_FROM_CLASS (object_class),
6474 G_STRUCT_OFFSET (ClutterActorClass, hide),
6476 _clutter_marshal_VOID__VOID,
6479 * ClutterActor::parent-set:
6480 * @actor: the object which received the signal
6481 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6483 * This signal is emitted when the parent of the actor changes.
6487 actor_signals[PARENT_SET] =
6488 g_signal_new (I_("parent-set"),
6489 G_TYPE_FROM_CLASS (object_class),
6491 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6493 _clutter_marshal_VOID__OBJECT,
6495 CLUTTER_TYPE_ACTOR);
6498 * ClutterActor::queue-redraw:
6499 * @actor: the actor we're bubbling the redraw request through
6500 * @origin: the actor which initiated the redraw request
6502 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6503 * is called on @origin.
6505 * The default implementation for #ClutterActor chains up to the
6506 * parent actor and queues a redraw on the parent, thus "bubbling"
6507 * the redraw queue up through the actor graph. The default
6508 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6509 * in a main loop idle handler.
6511 * Note that the @origin actor may be the stage, or a container; it
6512 * does not have to be a leaf node in the actor graph.
6514 * Toolkits embedding a #ClutterStage which require a redraw and
6515 * relayout cycle can stop the emission of this signal using the
6516 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6521 * on_redraw_complete (gpointer data)
6523 * ClutterStage *stage = data;
6525 * /* execute the Clutter drawing pipeline */
6526 * clutter_stage_ensure_redraw (stage);
6530 * on_stage_queue_redraw (ClutterStage *stage)
6532 * /* this prevents the default handler to run */
6533 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6535 * /* queue a redraw with the host toolkit and call
6536 * * a function when the redraw has been completed
6538 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6542 * <note><para>This signal is emitted before the Clutter paint
6543 * pipeline is executed. If you want to know when the pipeline has
6544 * been completed you should connect to the ::paint signal on the
6545 * Stage with g_signal_connect_after().</para></note>
6549 actor_signals[QUEUE_REDRAW] =
6550 g_signal_new (I_("queue-redraw"),
6551 G_TYPE_FROM_CLASS (object_class),
6554 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6556 _clutter_marshal_VOID__OBJECT,
6558 CLUTTER_TYPE_ACTOR);
6561 * ClutterActor::queue-relayout
6562 * @actor: the actor being queued for relayout
6564 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6565 * is called on an actor.
6567 * The default implementation for #ClutterActor chains up to the
6568 * parent actor and queues a relayout on the parent, thus "bubbling"
6569 * the relayout queue up through the actor graph.
6571 * The main purpose of this signal is to allow relayout to be propagated
6572 * properly in the procense of #ClutterClone actors. Applications will
6573 * not normally need to connect to this signal.
6577 actor_signals[QUEUE_RELAYOUT] =
6578 g_signal_new (I_("queue-relayout"),
6579 G_TYPE_FROM_CLASS (object_class),
6582 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6584 _clutter_marshal_VOID__VOID,
6588 * ClutterActor::event:
6589 * @actor: the actor which received the event
6590 * @event: a #ClutterEvent
6592 * The ::event signal is emitted each time an event is received
6593 * by the @actor. This signal will be emitted on every actor,
6594 * following the hierarchy chain, until it reaches the top-level
6595 * container (the #ClutterStage).
6597 * Return value: %TRUE if the event has been handled by the actor,
6598 * or %FALSE to continue the emission.
6602 actor_signals[EVENT] =
6603 g_signal_new (I_("event"),
6604 G_TYPE_FROM_CLASS (object_class),
6606 G_STRUCT_OFFSET (ClutterActorClass, event),
6607 _clutter_boolean_handled_accumulator, NULL,
6608 _clutter_marshal_BOOLEAN__BOXED,
6610 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6612 * ClutterActor::button-press-event:
6613 * @actor: the actor which received the event
6614 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6616 * The ::button-press-event signal is emitted each time a mouse button
6617 * is pressed on @actor.
6619 * Return value: %TRUE if the event has been handled by the actor,
6620 * or %FALSE to continue the emission.
6624 actor_signals[BUTTON_PRESS_EVENT] =
6625 g_signal_new (I_("button-press-event"),
6626 G_TYPE_FROM_CLASS (object_class),
6628 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6629 _clutter_boolean_handled_accumulator, NULL,
6630 _clutter_marshal_BOOLEAN__BOXED,
6632 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6634 * ClutterActor::button-release-event:
6635 * @actor: the actor which received the event
6636 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6638 * The ::button-release-event signal is emitted each time a mouse button
6639 * is released on @actor.
6641 * Return value: %TRUE if the event has been handled by the actor,
6642 * or %FALSE to continue the emission.
6646 actor_signals[BUTTON_RELEASE_EVENT] =
6647 g_signal_new (I_("button-release-event"),
6648 G_TYPE_FROM_CLASS (object_class),
6650 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6651 _clutter_boolean_handled_accumulator, NULL,
6652 _clutter_marshal_BOOLEAN__BOXED,
6654 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6656 * ClutterActor::scroll-event:
6657 * @actor: the actor which received the event
6658 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6660 * The ::scroll-event signal is emitted each time the mouse is
6661 * scrolled on @actor
6663 * Return value: %TRUE if the event has been handled by the actor,
6664 * or %FALSE to continue the emission.
6668 actor_signals[SCROLL_EVENT] =
6669 g_signal_new (I_("scroll-event"),
6670 G_TYPE_FROM_CLASS (object_class),
6672 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6673 _clutter_boolean_handled_accumulator, NULL,
6674 _clutter_marshal_BOOLEAN__BOXED,
6676 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6678 * ClutterActor::key-press-event:
6679 * @actor: the actor which received the event
6680 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6682 * The ::key-press-event signal is emitted each time a keyboard button
6683 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6685 * Return value: %TRUE if the event has been handled by the actor,
6686 * or %FALSE to continue the emission.
6690 actor_signals[KEY_PRESS_EVENT] =
6691 g_signal_new (I_("key-press-event"),
6692 G_TYPE_FROM_CLASS (object_class),
6694 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6695 _clutter_boolean_handled_accumulator, NULL,
6696 _clutter_marshal_BOOLEAN__BOXED,
6698 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6700 * ClutterActor::key-release-event:
6701 * @actor: the actor which received the event
6702 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6704 * The ::key-release-event signal is emitted each time a keyboard button
6705 * is released while @actor has key focus (see
6706 * clutter_stage_set_key_focus()).
6708 * Return value: %TRUE if the event has been handled by the actor,
6709 * or %FALSE to continue the emission.
6713 actor_signals[KEY_RELEASE_EVENT] =
6714 g_signal_new (I_("key-release-event"),
6715 G_TYPE_FROM_CLASS (object_class),
6717 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6718 _clutter_boolean_handled_accumulator, NULL,
6719 _clutter_marshal_BOOLEAN__BOXED,
6721 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6723 * ClutterActor::motion-event:
6724 * @actor: the actor which received the event
6725 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6727 * The ::motion-event signal is emitted each time the mouse pointer is
6728 * moved over @actor.
6730 * Return value: %TRUE if the event has been handled by the actor,
6731 * or %FALSE to continue the emission.
6735 actor_signals[MOTION_EVENT] =
6736 g_signal_new (I_("motion-event"),
6737 G_TYPE_FROM_CLASS (object_class),
6739 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6740 _clutter_boolean_handled_accumulator, NULL,
6741 _clutter_marshal_BOOLEAN__BOXED,
6743 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6746 * ClutterActor::key-focus-in:
6747 * @actor: the actor which now has key focus
6749 * The ::key-focus-in signal is emitted when @actor receives key focus.
6753 actor_signals[KEY_FOCUS_IN] =
6754 g_signal_new (I_("key-focus-in"),
6755 G_TYPE_FROM_CLASS (object_class),
6757 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6759 _clutter_marshal_VOID__VOID,
6763 * ClutterActor::key-focus-out:
6764 * @actor: the actor which now has key focus
6766 * The ::key-focus-out signal is emitted when @actor loses key focus.
6770 actor_signals[KEY_FOCUS_OUT] =
6771 g_signal_new (I_("key-focus-out"),
6772 G_TYPE_FROM_CLASS (object_class),
6774 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6776 _clutter_marshal_VOID__VOID,
6780 * ClutterActor::enter-event:
6781 * @actor: the actor which the pointer has entered.
6782 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6784 * The ::enter-event signal is emitted when the pointer enters the @actor
6786 * Return value: %TRUE if the event has been handled by the actor,
6787 * or %FALSE to continue the emission.
6791 actor_signals[ENTER_EVENT] =
6792 g_signal_new (I_("enter-event"),
6793 G_TYPE_FROM_CLASS (object_class),
6795 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6796 _clutter_boolean_handled_accumulator, NULL,
6797 _clutter_marshal_BOOLEAN__BOXED,
6799 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6802 * ClutterActor::leave-event:
6803 * @actor: the actor which the pointer has left
6804 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6806 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6808 * Return value: %TRUE if the event has been handled by the actor,
6809 * or %FALSE to continue the emission.
6813 actor_signals[LEAVE_EVENT] =
6814 g_signal_new (I_("leave-event"),
6815 G_TYPE_FROM_CLASS (object_class),
6817 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6818 _clutter_boolean_handled_accumulator, NULL,
6819 _clutter_marshal_BOOLEAN__BOXED,
6821 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6824 * ClutterActor::captured-event:
6825 * @actor: the actor which received the signal
6826 * @event: a #ClutterEvent
6828 * The ::captured-event signal is emitted when an event is captured
6829 * by Clutter. This signal will be emitted starting from the top-level
6830 * container (the #ClutterStage) to the actor which received the event
6831 * going down the hierarchy. This signal can be used to intercept every
6832 * event before the specialized events (like
6833 * ClutterActor::button-press-event or ::key-released-event) are
6836 * Return value: %TRUE if the event has been handled by the actor,
6837 * or %FALSE to continue the emission.
6841 actor_signals[CAPTURED_EVENT] =
6842 g_signal_new (I_("captured-event"),
6843 G_TYPE_FROM_CLASS (object_class),
6845 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6846 _clutter_boolean_handled_accumulator, NULL,
6847 _clutter_marshal_BOOLEAN__BOXED,
6849 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6852 * ClutterActor::paint:
6853 * @actor: the #ClutterActor that received the signal
6855 * The ::paint signal is emitted each time an actor is being painted.
6857 * Subclasses of #ClutterActor should override the class signal handler
6858 * and paint themselves in that function.
6860 * It is possible to connect a handler to the ::paint signal in order
6861 * to set up some custom aspect of a paint.
6865 actor_signals[PAINT] =
6866 g_signal_new (I_("paint"),
6867 G_TYPE_FROM_CLASS (object_class),
6870 G_STRUCT_OFFSET (ClutterActorClass, paint),
6872 _clutter_marshal_VOID__VOID,
6875 * ClutterActor::realize:
6876 * @actor: the #ClutterActor that received the signal
6878 * The ::realize signal is emitted each time an actor is being
6883 actor_signals[REALIZE] =
6884 g_signal_new (I_("realize"),
6885 G_TYPE_FROM_CLASS (object_class),
6887 G_STRUCT_OFFSET (ClutterActorClass, realize),
6889 _clutter_marshal_VOID__VOID,
6892 * ClutterActor::unrealize:
6893 * @actor: the #ClutterActor that received the signal
6895 * The ::unrealize signal is emitted each time an actor is being
6900 actor_signals[UNREALIZE] =
6901 g_signal_new (I_("unrealize"),
6902 G_TYPE_FROM_CLASS (object_class),
6904 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6906 _clutter_marshal_VOID__VOID,
6910 * ClutterActor::pick:
6911 * @actor: the #ClutterActor that received the signal
6912 * @color: the #ClutterColor to be used when picking
6914 * The ::pick signal is emitted each time an actor is being painted
6915 * in "pick mode". The pick mode is used to identify the actor during
6916 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6917 * The actor should paint its shape using the passed @pick_color.
6919 * Subclasses of #ClutterActor should override the class signal handler
6920 * and paint themselves in that function.
6922 * It is possible to connect a handler to the ::pick signal in order
6923 * to set up some custom aspect of a paint in pick mode.
6927 actor_signals[PICK] =
6928 g_signal_new (I_("pick"),
6929 G_TYPE_FROM_CLASS (object_class),
6931 G_STRUCT_OFFSET (ClutterActorClass, pick),
6933 _clutter_marshal_VOID__BOXED,
6935 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6938 * ClutterActor::allocation-changed:
6939 * @actor: the #ClutterActor that emitted the signal
6940 * @box: a #ClutterActorBox with the new allocation
6941 * @flags: #ClutterAllocationFlags for the allocation
6943 * The ::allocation-changed signal is emitted when the
6944 * #ClutterActor:allocation property changes. Usually, application
6945 * code should just use the notifications for the :allocation property
6946 * but if you want to track the allocation flags as well, for instance
6947 * to know whether the absolute origin of @actor changed, then you might
6948 * want use this signal instead.
6952 actor_signals[ALLOCATION_CHANGED] =
6953 g_signal_new (I_("allocation-changed"),
6954 G_TYPE_FROM_CLASS (object_class),
6958 _clutter_marshal_VOID__BOXED_FLAGS,
6960 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6961 CLUTTER_TYPE_ALLOCATION_FLAGS);
6964 * ClutterActor::transitions-completed:
6965 * @actor: a #ClutterActor
6967 * The ::transitions-completed signal is emitted once all transitions
6968 * involving @actor are complete.
6972 actor_signals[TRANSITIONS_COMPLETED] =
6973 g_signal_new (I_("transitions-completed"),
6974 G_TYPE_FROM_CLASS (object_class),
6978 _clutter_marshal_VOID__VOID,
6983 clutter_actor_init (ClutterActor *self)
6985 ClutterActorPrivate *priv;
6987 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6989 priv->id = _clutter_context_acquire_id (self);
6992 priv->opacity = 0xff;
6993 priv->show_on_set_parent = TRUE;
6995 priv->needs_width_request = TRUE;
6996 priv->needs_height_request = TRUE;
6997 priv->needs_allocation = TRUE;
6999 priv->cached_width_age = 1;
7000 priv->cached_height_age = 1;
7002 priv->opacity_override = -1;
7003 priv->enable_model_view_transform = TRUE;
7005 /* Initialize an empty paint volume to start with */
7006 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7007 priv->last_paint_volume_valid = TRUE;
7009 priv->transform_valid = FALSE;
7011 /* the default is to stretch the content, to match the
7012 * current behaviour of basically all actors. also, it's
7013 * the easiest thing to compute.
7015 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7016 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7017 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7021 * clutter_actor_new:
7023 * Creates a new #ClutterActor.
7025 * A newly created actor has a floating reference, which will be sunk
7026 * when it is added to another actor.
7028 * Return value: (transfer full): the newly created #ClutterActor
7033 clutter_actor_new (void)
7035 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7039 * clutter_actor_destroy:
7040 * @self: a #ClutterActor
7042 * Destroys an actor. When an actor is destroyed, it will break any
7043 * references it holds to other objects. If the actor is inside a
7044 * container, the actor will be removed.
7046 * When you destroy a container, its children will be destroyed as well.
7048 * Note: you cannot destroy the #ClutterStage returned by
7049 * clutter_stage_get_default().
7052 clutter_actor_destroy (ClutterActor *self)
7054 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7056 g_object_ref (self);
7058 /* avoid recursion while destroying */
7059 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7061 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7063 g_object_run_dispose (G_OBJECT (self));
7065 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7068 g_object_unref (self);
7072 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7073 ClutterPaintVolume *clip)
7075 ClutterActorPrivate *priv = self->priv;
7076 ClutterPaintVolume *pv;
7079 /* Remove queue entry early in the process, otherwise a new
7080 queue_redraw() during signal handling could put back this
7081 object in the stage redraw list (but the entry is freed as
7082 soon as we return from this function, causing a segfault
7085 priv->queue_redraw_entry = NULL;
7087 /* If we've been explicitly passed a clip volume then there's
7088 * nothing more to calculate, but otherwise the only thing we know
7089 * is that the change is constrained to the given actor.
7091 * The idea is that if we know the paint volume for where the actor
7092 * was last drawn (in eye coordinates) and we also have the paint
7093 * volume for where it will be drawn next (in actor coordinates)
7094 * then if we queue a redraw for both these volumes that will cover
7095 * everything that needs to be redrawn to clear the old view and
7096 * show the latest view of the actor.
7098 * Don't clip this redraw if we don't know what position we had for
7099 * the previous redraw since we don't know where to set the clip so
7100 * it will clear the actor as it is currently.
7104 _clutter_actor_set_queue_redraw_clip (self, clip);
7107 else if (G_LIKELY (priv->last_paint_volume_valid))
7109 pv = _clutter_actor_get_paint_volume_mutable (self);
7112 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7114 /* make sure we redraw the actors old position... */
7115 _clutter_actor_set_queue_redraw_clip (stage,
7116 &priv->last_paint_volume);
7117 _clutter_actor_signal_queue_redraw (stage, stage);
7118 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7120 /* XXX: Ideally the redraw signal would take a clip volume
7121 * argument, but that would be an ABI break. Until we can
7122 * break the ABI we pass the argument out-of-band
7125 /* setup the clip for the actors new position... */
7126 _clutter_actor_set_queue_redraw_clip (self, pv);
7135 _clutter_actor_signal_queue_redraw (self, self);
7137 /* Just in case anyone is manually firing redraw signals without
7138 * using the public queue_redraw() API we are careful to ensure that
7139 * our out-of-band clip member is cleared before returning...
7141 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7143 if (G_LIKELY (clipped))
7144 _clutter_actor_set_queue_redraw_clip (self, NULL);
7148 _clutter_actor_get_allocation_clip (ClutterActor *self,
7149 ClutterActorBox *clip)
7151 ClutterActorBox allocation;
7153 /* XXX: we don't care if we get an out of date allocation here
7154 * because clutter_actor_queue_redraw_with_clip knows to ignore
7155 * the clip if the actor's allocation is invalid.
7157 * This is noted because clutter_actor_get_allocation_box does some
7158 * unnecessary work to support buggy code with a comment suggesting
7159 * that it could be changed later which would be good for this use
7162 clutter_actor_get_allocation_box (self, &allocation);
7164 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7165 * actor's own coordinate space but the allocation is in parent
7169 clip->x2 = allocation.x2 - allocation.x1;
7170 clip->y2 = allocation.y2 - allocation.y1;
7174 _clutter_actor_queue_redraw_full (ClutterActor *self,
7175 ClutterRedrawFlags flags,
7176 ClutterPaintVolume *volume,
7177 ClutterEffect *effect)
7179 ClutterActorPrivate *priv = self->priv;
7180 ClutterPaintVolume allocation_pv;
7181 ClutterPaintVolume *pv;
7182 gboolean should_free_pv;
7183 ClutterActor *stage;
7185 /* Here's an outline of the actor queue redraw mechanism:
7187 * The process starts in one of the following two functions which
7188 * are wrappers for this function:
7189 * clutter_actor_queue_redraw
7190 * _clutter_actor_queue_redraw_with_clip
7192 * additionally, an effect can queue a redraw by wrapping this
7193 * function in clutter_effect_queue_rerun
7195 * This functions queues an entry in a list associated with the
7196 * stage which is a list of actors that queued a redraw while
7197 * updating the timelines, performing layouting and processing other
7198 * mainloop sources before the next paint starts.
7200 * We aim to minimize the processing done at this point because
7201 * there is a good chance other events will happen while updating
7202 * the scenegraph that would invalidate any expensive work we might
7203 * otherwise try to do here. For example we don't try and resolve
7204 * the screen space bounding box of an actor at this stage so as to
7205 * minimize how much of the screen redraw because it's possible
7206 * something else will happen which will force a full redraw anyway.
7208 * When all updates are complete and we come to paint the stage then
7209 * we iterate this list and actually emit the "queue-redraw" signals
7210 * for each of the listed actors which will bubble up to the stage
7211 * for each actor and at that point we will transform the actors
7212 * paint volume into screen coordinates to determine the clip region
7213 * for what needs to be redrawn in the next paint.
7215 * Besides minimizing redundant work another reason for this
7216 * deferred design is that it's more likely we will be able to
7217 * determine the paint volume of an actor once we've finished
7218 * updating the scenegraph because its allocation should be up to
7219 * date. NB: If we can't determine an actors paint volume then we
7220 * can't automatically queue a clipped redraw which can make a big
7221 * difference to performance.
7223 * So the control flow goes like this:
7224 * One of clutter_actor_queue_redraw,
7225 * _clutter_actor_queue_redraw_with_clip
7226 * or clutter_effect_queue_rerun
7228 * then control moves to:
7229 * _clutter_stage_queue_actor_redraw
7231 * later during _clutter_stage_do_update, once relayouting is done
7232 * and the scenegraph has been updated we will call:
7233 * _clutter_stage_finish_queue_redraws
7235 * _clutter_stage_finish_queue_redraws will call
7236 * _clutter_actor_finish_queue_redraw for each listed actor.
7237 * Note: actors *are* allowed to queue further redraws during this
7238 * process (considering clone actors or texture_new_from_actor which
7239 * respond to their source queueing a redraw by queuing a redraw
7240 * themselves). We repeat the process until the list is empty.
7242 * This will result in the "queue-redraw" signal being fired for
7243 * each actor which will pass control to the default signal handler:
7244 * clutter_actor_real_queue_redraw
7246 * This will bubble up to the stages handler:
7247 * clutter_stage_real_queue_redraw
7249 * clutter_stage_real_queue_redraw will transform the actors paint
7250 * volume into screen space and add it as a clip region for the next
7254 /* ignore queueing a redraw for actors being destroyed */
7255 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7258 stage = _clutter_actor_get_stage_internal (self);
7260 /* Ignore queueing a redraw for actors not descended from a stage */
7264 /* ignore queueing a redraw on stages that are being destroyed */
7265 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7268 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7270 ClutterActorBox allocation_clip;
7271 ClutterVertex origin;
7273 /* If the actor doesn't have a valid allocation then we will
7274 * queue a full stage redraw. */
7275 if (priv->needs_allocation)
7277 /* NB: NULL denotes an undefined clip which will result in a
7279 _clutter_actor_set_queue_redraw_clip (self, NULL);
7280 _clutter_actor_signal_queue_redraw (self, self);
7284 _clutter_paint_volume_init_static (&allocation_pv, self);
7285 pv = &allocation_pv;
7287 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7289 origin.x = allocation_clip.x1;
7290 origin.y = allocation_clip.y1;
7292 clutter_paint_volume_set_origin (pv, &origin);
7293 clutter_paint_volume_set_width (pv,
7294 allocation_clip.x2 - allocation_clip.x1);
7295 clutter_paint_volume_set_height (pv,
7296 allocation_clip.y2 -
7297 allocation_clip.y1);
7298 should_free_pv = TRUE;
7303 should_free_pv = FALSE;
7306 self->priv->queue_redraw_entry =
7307 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7308 priv->queue_redraw_entry,
7313 clutter_paint_volume_free (pv);
7315 /* If this is the first redraw queued then we can directly use the
7317 if (!priv->is_dirty)
7318 priv->effect_to_redraw = effect;
7319 /* Otherwise we need to merge it with the existing effect parameter */
7320 else if (effect != NULL)
7322 /* If there's already an effect then we need to use whichever is
7323 later in the chain of actors. Otherwise a full redraw has
7324 already been queued on the actor so we need to ignore the
7326 if (priv->effect_to_redraw != NULL)
7328 if (priv->effects == NULL)
7329 g_warning ("Redraw queued with an effect that is "
7330 "not applied to the actor");
7335 for (l = _clutter_meta_group_peek_metas (priv->effects);
7339 if (l->data == priv->effect_to_redraw ||
7341 priv->effect_to_redraw = l->data;
7348 /* If no effect is specified then we need to redraw the whole
7350 priv->effect_to_redraw = NULL;
7353 priv->is_dirty = TRUE;
7357 * clutter_actor_queue_redraw:
7358 * @self: A #ClutterActor
7360 * Queues up a redraw of an actor and any children. The redraw occurs
7361 * once the main loop becomes idle (after the current batch of events
7362 * has been processed, roughly).
7364 * Applications rarely need to call this, as redraws are handled
7365 * automatically by modification functions.
7367 * This function will not do anything if @self is not visible, or
7368 * if the actor is inside an invisible part of the scenegraph.
7370 * Also be aware that painting is a NOP for actors with an opacity of
7373 * When you are implementing a custom actor you must queue a redraw
7374 * whenever some private state changes that will affect painting or
7375 * picking of your actor.
7378 clutter_actor_queue_redraw (ClutterActor *self)
7380 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7382 _clutter_actor_queue_redraw_full (self,
7384 NULL, /* clip volume */
7389 * _clutter_actor_queue_redraw_with_clip:
7390 * @self: A #ClutterActor
7391 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7392 * this queue redraw.
7393 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7394 * redrawn or %NULL if you are just using a @flag to state your
7397 * Queues up a clipped redraw of an actor and any children. The redraw
7398 * occurs once the main loop becomes idle (after the current batch of
7399 * events has been processed, roughly).
7401 * If no flags are given the clip volume is defined by @volume
7402 * specified in actor coordinates and tells Clutter that only content
7403 * within this volume has been changed so Clutter can optionally
7404 * optimize the redraw.
7406 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7407 * should be %NULL and this tells Clutter to use the actor's current
7408 * allocation as a clip box. This flag can only be used for 2D actors,
7409 * because any actor with depth may be projected outside its
7412 * Applications rarely need to call this, as redraws are handled
7413 * automatically by modification functions.
7415 * This function will not do anything if @self is not visible, or if
7416 * the actor is inside an invisible part of the scenegraph.
7418 * Also be aware that painting is a NOP for actors with an opacity of
7421 * When you are implementing a custom actor you must queue a redraw
7422 * whenever some private state changes that will affect painting or
7423 * picking of your actor.
7426 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7427 ClutterRedrawFlags flags,
7428 ClutterPaintVolume *volume)
7430 _clutter_actor_queue_redraw_full (self,
7432 volume, /* clip volume */
7437 _clutter_actor_queue_only_relayout (ClutterActor *self)
7439 ClutterActorPrivate *priv = self->priv;
7441 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7444 if (priv->needs_width_request &&
7445 priv->needs_height_request &&
7446 priv->needs_allocation)
7447 return; /* save some cpu cycles */
7449 #if CLUTTER_ENABLE_DEBUG
7450 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7452 g_warning ("The actor '%s' is currently inside an allocation "
7453 "cycle; calling clutter_actor_queue_relayout() is "
7455 _clutter_actor_get_debug_name (self));
7457 #endif /* CLUTTER_ENABLE_DEBUG */
7459 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7463 * clutter_actor_queue_redraw_with_clip:
7464 * @self: a #ClutterActor
7465 * @clip: (allow-none): a rectangular clip region, or %NULL
7467 * Queues a redraw on @self limited to a specific, actor-relative
7470 * If @clip is %NULL this function is equivalent to
7471 * clutter_actor_queue_redraw().
7476 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7477 const cairo_rectangle_int_t *clip)
7479 ClutterPaintVolume volume;
7480 ClutterVertex origin;
7482 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7486 clutter_actor_queue_redraw (self);
7490 _clutter_paint_volume_init_static (&volume, self);
7496 clutter_paint_volume_set_origin (&volume, &origin);
7497 clutter_paint_volume_set_width (&volume, clip->width);
7498 clutter_paint_volume_set_height (&volume, clip->height);
7500 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7502 clutter_paint_volume_free (&volume);
7506 * clutter_actor_queue_relayout:
7507 * @self: A #ClutterActor
7509 * Indicates that the actor's size request or other layout-affecting
7510 * properties may have changed. This function is used inside #ClutterActor
7511 * subclass implementations, not by applications directly.
7513 * Queueing a new layout automatically queues a redraw as well.
7518 clutter_actor_queue_relayout (ClutterActor *self)
7520 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7522 _clutter_actor_queue_only_relayout (self);
7523 clutter_actor_queue_redraw (self);
7527 * clutter_actor_get_preferred_size:
7528 * @self: a #ClutterActor
7529 * @min_width_p: (out) (allow-none): return location for the minimum
7531 * @min_height_p: (out) (allow-none): return location for the minimum
7533 * @natural_width_p: (out) (allow-none): return location for the natural
7535 * @natural_height_p: (out) (allow-none): return location for the natural
7538 * Computes the preferred minimum and natural size of an actor, taking into
7539 * account the actor's geometry management (either height-for-width
7540 * or width-for-height).
7542 * The width and height used to compute the preferred height and preferred
7543 * width are the actor's natural ones.
7545 * If you need to control the height for the preferred width, or the width for
7546 * the preferred height, you should use clutter_actor_get_preferred_width()
7547 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7548 * geometry management using the #ClutterActor:request-mode property.
7553 clutter_actor_get_preferred_size (ClutterActor *self,
7554 gfloat *min_width_p,
7555 gfloat *min_height_p,
7556 gfloat *natural_width_p,
7557 gfloat *natural_height_p)
7559 ClutterActorPrivate *priv;
7560 gfloat min_width, min_height;
7561 gfloat natural_width, natural_height;
7563 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7567 min_width = min_height = 0;
7568 natural_width = natural_height = 0;
7570 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7572 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7573 clutter_actor_get_preferred_width (self, -1,
7576 clutter_actor_get_preferred_height (self, natural_width,
7582 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7583 clutter_actor_get_preferred_height (self, -1,
7586 clutter_actor_get_preferred_width (self, natural_height,
7592 *min_width_p = min_width;
7595 *min_height_p = min_height;
7597 if (natural_width_p)
7598 *natural_width_p = natural_width;
7600 if (natural_height_p)
7601 *natural_height_p = natural_height;
7606 * @align: a #ClutterActorAlign
7607 * @direction: a #ClutterTextDirection
7609 * Retrieves the correct alignment depending on the text direction
7611 * Return value: the effective alignment
7613 static ClutterActorAlign
7614 effective_align (ClutterActorAlign align,
7615 ClutterTextDirection direction)
7617 ClutterActorAlign res;
7621 case CLUTTER_ACTOR_ALIGN_START:
7622 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7623 ? CLUTTER_ACTOR_ALIGN_END
7624 : CLUTTER_ACTOR_ALIGN_START;
7627 case CLUTTER_ACTOR_ALIGN_END:
7628 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7629 ? CLUTTER_ACTOR_ALIGN_START
7630 : CLUTTER_ACTOR_ALIGN_END;
7642 adjust_for_margin (float margin_start,
7644 float *minimum_size,
7645 float *natural_size,
7646 float *allocated_start,
7647 float *allocated_end)
7649 *minimum_size -= (margin_start + margin_end);
7650 *natural_size -= (margin_start + margin_end);
7651 *allocated_start += margin_start;
7652 *allocated_end -= margin_end;
7656 adjust_for_alignment (ClutterActorAlign alignment,
7658 float *allocated_start,
7659 float *allocated_end)
7661 float allocated_size = *allocated_end - *allocated_start;
7665 case CLUTTER_ACTOR_ALIGN_FILL:
7669 case CLUTTER_ACTOR_ALIGN_START:
7671 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7674 case CLUTTER_ACTOR_ALIGN_END:
7675 if (allocated_size > natural_size)
7677 *allocated_start += (allocated_size - natural_size);
7678 *allocated_end = *allocated_start + natural_size;
7682 case CLUTTER_ACTOR_ALIGN_CENTER:
7683 if (allocated_size > natural_size)
7685 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7686 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7693 * clutter_actor_adjust_width:
7694 * @self: a #ClutterActor
7695 * @minimum_width: (inout): the actor's preferred minimum width, which
7696 * will be adjusted depending on the margin
7697 * @natural_width: (inout): the actor's preferred natural width, which
7698 * will be adjusted depending on the margin
7699 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7700 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7702 * Adjusts the preferred and allocated position and size of an actor,
7703 * depending on the margin and alignment properties.
7706 clutter_actor_adjust_width (ClutterActor *self,
7707 gfloat *minimum_width,
7708 gfloat *natural_width,
7709 gfloat *adjusted_x1,
7710 gfloat *adjusted_x2)
7712 ClutterTextDirection text_dir;
7713 const ClutterLayoutInfo *info;
7715 info = _clutter_actor_get_layout_info_or_defaults (self);
7716 text_dir = clutter_actor_get_text_direction (self);
7718 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7720 /* this will tweak natural_width to remove the margin, so that
7721 * adjust_for_alignment() will use the correct size
7723 adjust_for_margin (info->margin.left, info->margin.right,
7724 minimum_width, natural_width,
7725 adjusted_x1, adjusted_x2);
7727 adjust_for_alignment (effective_align (info->x_align, text_dir),
7729 adjusted_x1, adjusted_x2);
7733 * clutter_actor_adjust_height:
7734 * @self: a #ClutterActor
7735 * @minimum_height: (inout): the actor's preferred minimum height, which
7736 * will be adjusted depending on the margin
7737 * @natural_height: (inout): the actor's preferred natural height, which
7738 * will be adjusted depending on the margin
7739 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7740 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7742 * Adjusts the preferred and allocated position and size of an actor,
7743 * depending on the margin and alignment properties.
7746 clutter_actor_adjust_height (ClutterActor *self,
7747 gfloat *minimum_height,
7748 gfloat *natural_height,
7749 gfloat *adjusted_y1,
7750 gfloat *adjusted_y2)
7752 const ClutterLayoutInfo *info;
7754 info = _clutter_actor_get_layout_info_or_defaults (self);
7756 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7758 /* this will tweak natural_height to remove the margin, so that
7759 * adjust_for_alignment() will use the correct size
7761 adjust_for_margin (info->margin.top, info->margin.bottom,
7762 minimum_height, natural_height,
7766 /* we don't use effective_align() here, because text direction
7767 * only affects the horizontal axis
7769 adjust_for_alignment (info->y_align,
7776 /* looks for a cached size request for this for_size. If not
7777 * found, returns the oldest entry so it can be overwritten */
7779 _clutter_actor_get_cached_size_request (gfloat for_size,
7780 SizeRequest *cached_size_requests,
7781 SizeRequest **result)
7785 *result = &cached_size_requests[0];
7787 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7791 sr = &cached_size_requests[i];
7794 sr->for_size == for_size)
7796 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7800 else if (sr->age < (*result)->age)
7806 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7812 * clutter_actor_get_preferred_width:
7813 * @self: A #ClutterActor
7814 * @for_height: available height when computing the preferred width,
7815 * or a negative value to indicate that no height is defined
7816 * @min_width_p: (out) (allow-none): return location for minimum width,
7818 * @natural_width_p: (out) (allow-none): return location for the natural
7821 * Computes the requested minimum and natural widths for an actor,
7822 * optionally depending on the specified height, or if they are
7823 * already computed, returns the cached values.
7825 * An actor may not get its request - depending on the layout
7826 * manager that's in effect.
7828 * A request should not incorporate the actor's scale or anchor point;
7829 * those transformations do not affect layout, only rendering.
7834 clutter_actor_get_preferred_width (ClutterActor *self,
7836 gfloat *min_width_p,
7837 gfloat *natural_width_p)
7839 float request_min_width, request_natural_width;
7840 SizeRequest *cached_size_request;
7841 const ClutterLayoutInfo *info;
7842 ClutterActorPrivate *priv;
7843 gboolean found_in_cache;
7845 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7849 info = _clutter_actor_get_layout_info_or_defaults (self);
7851 /* we shortcircuit the case of a fixed size set using set_width() */
7852 if (priv->min_width_set && priv->natural_width_set)
7854 if (min_width_p != NULL)
7855 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7857 if (natural_width_p != NULL)
7858 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7863 /* the remaining cases are:
7865 * - either min_width or natural_width have been set
7866 * - neither min_width or natural_width have been set
7868 * in both cases, we go through the cache (and through the actor in case
7869 * of cache misses) and determine the authoritative value depending on
7873 if (!priv->needs_width_request)
7876 _clutter_actor_get_cached_size_request (for_height,
7877 priv->width_requests,
7878 &cached_size_request);
7882 /* if the actor needs a width request we use the first slot */
7883 found_in_cache = FALSE;
7884 cached_size_request = &priv->width_requests[0];
7887 if (!found_in_cache)
7889 gfloat minimum_width, natural_width;
7890 ClutterActorClass *klass;
7892 minimum_width = natural_width = 0;
7894 /* adjust for the margin */
7895 if (for_height >= 0)
7897 for_height -= (info->margin.top + info->margin.bottom);
7902 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7904 klass = CLUTTER_ACTOR_GET_CLASS (self);
7905 klass->get_preferred_width (self, for_height,
7909 /* adjust for the margin */
7910 minimum_width += (info->margin.left + info->margin.right);
7911 natural_width += (info->margin.left + info->margin.right);
7913 /* Due to accumulated float errors, it's better not to warn
7914 * on this, but just fix it.
7916 if (natural_width < minimum_width)
7917 natural_width = minimum_width;
7919 cached_size_request->min_size = minimum_width;
7920 cached_size_request->natural_size = natural_width;
7921 cached_size_request->for_size = for_height;
7922 cached_size_request->age = priv->cached_width_age;
7924 priv->cached_width_age += 1;
7925 priv->needs_width_request = FALSE;
7928 if (!priv->min_width_set)
7929 request_min_width = cached_size_request->min_size;
7931 request_min_width = info->min_width;
7933 if (!priv->natural_width_set)
7934 request_natural_width = cached_size_request->natural_size;
7936 request_natural_width = info->natural_width;
7939 *min_width_p = request_min_width;
7941 if (natural_width_p)
7942 *natural_width_p = request_natural_width;
7946 * clutter_actor_get_preferred_height:
7947 * @self: A #ClutterActor
7948 * @for_width: available width to assume in computing desired height,
7949 * or a negative value to indicate that no width is defined
7950 * @min_height_p: (out) (allow-none): return location for minimum height,
7952 * @natural_height_p: (out) (allow-none): return location for natural
7955 * Computes the requested minimum and natural heights for an actor,
7956 * or if they are already computed, returns the cached values.
7958 * An actor may not get its request - depending on the layout
7959 * manager that's in effect.
7961 * A request should not incorporate the actor's scale or anchor point;
7962 * those transformations do not affect layout, only rendering.
7967 clutter_actor_get_preferred_height (ClutterActor *self,
7969 gfloat *min_height_p,
7970 gfloat *natural_height_p)
7972 float request_min_height, request_natural_height;
7973 SizeRequest *cached_size_request;
7974 const ClutterLayoutInfo *info;
7975 ClutterActorPrivate *priv;
7976 gboolean found_in_cache;
7978 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7982 info = _clutter_actor_get_layout_info_or_defaults (self);
7984 /* we shortcircuit the case of a fixed size set using set_height() */
7985 if (priv->min_height_set && priv->natural_height_set)
7987 if (min_height_p != NULL)
7988 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7990 if (natural_height_p != NULL)
7991 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7996 /* the remaining cases are:
7998 * - either min_height or natural_height have been set
7999 * - neither min_height or natural_height have been set
8001 * in both cases, we go through the cache (and through the actor in case
8002 * of cache misses) and determine the authoritative value depending on
8006 if (!priv->needs_height_request)
8009 _clutter_actor_get_cached_size_request (for_width,
8010 priv->height_requests,
8011 &cached_size_request);
8015 found_in_cache = FALSE;
8016 cached_size_request = &priv->height_requests[0];
8019 if (!found_in_cache)
8021 gfloat minimum_height, natural_height;
8022 ClutterActorClass *klass;
8024 minimum_height = natural_height = 0;
8026 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8028 /* adjust for margin */
8031 for_width -= (info->margin.left + info->margin.right);
8036 klass = CLUTTER_ACTOR_GET_CLASS (self);
8037 klass->get_preferred_height (self, for_width,
8041 /* adjust for margin */
8042 minimum_height += (info->margin.top + info->margin.bottom);
8043 natural_height += (info->margin.top + info->margin.bottom);
8045 /* Due to accumulated float errors, it's better not to warn
8046 * on this, but just fix it.
8048 if (natural_height < minimum_height)
8049 natural_height = minimum_height;
8051 cached_size_request->min_size = minimum_height;
8052 cached_size_request->natural_size = natural_height;
8053 cached_size_request->for_size = for_width;
8054 cached_size_request->age = priv->cached_height_age;
8056 priv->cached_height_age += 1;
8057 priv->needs_height_request = FALSE;
8060 if (!priv->min_height_set)
8061 request_min_height = cached_size_request->min_size;
8063 request_min_height = info->min_height;
8065 if (!priv->natural_height_set)
8066 request_natural_height = cached_size_request->natural_size;
8068 request_natural_height = info->natural_height;
8071 *min_height_p = request_min_height;
8073 if (natural_height_p)
8074 *natural_height_p = request_natural_height;
8078 * clutter_actor_get_allocation_box:
8079 * @self: A #ClutterActor
8080 * @box: (out): the function fills this in with the actor's allocation
8082 * Gets the layout box an actor has been assigned. The allocation can
8083 * only be assumed valid inside a paint() method; anywhere else, it
8084 * may be out-of-date.
8086 * An allocation does not incorporate the actor's scale or anchor point;
8087 * those transformations do not affect layout, only rendering.
8089 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8090 * of functions inside the implementation of the get_preferred_width()
8091 * or get_preferred_height() virtual functions.</note>
8096 clutter_actor_get_allocation_box (ClutterActor *self,
8097 ClutterActorBox *box)
8099 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8101 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8102 * which limits calling get_allocation to inside paint() basically; or
8103 * we can 2) force a layout, which could be expensive if someone calls
8104 * get_allocation somewhere silly; or we can 3) just return the latest
8105 * value, allowing it to be out-of-date, and assume people know what
8108 * The least-surprises approach that keeps existing code working is
8109 * likely to be 2). People can end up doing some inefficient things,
8110 * though, and in general code that requires 2) is probably broken.
8113 /* this implements 2) */
8114 if (G_UNLIKELY (self->priv->needs_allocation))
8116 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8118 /* do not queue a relayout on an unparented actor */
8120 _clutter_stage_maybe_relayout (stage);
8123 /* commenting out the code above and just keeping this assigment
8126 *box = self->priv->allocation;
8130 * clutter_actor_get_allocation_geometry:
8131 * @self: A #ClutterActor
8132 * @geom: (out): allocation geometry in pixels
8134 * Gets the layout box an actor has been assigned. The allocation can
8135 * only be assumed valid inside a paint() method; anywhere else, it
8136 * may be out-of-date.
8138 * An allocation does not incorporate the actor's scale or anchor point;
8139 * those transformations do not affect layout, only rendering.
8141 * The returned rectangle is in pixels.
8146 clutter_actor_get_allocation_geometry (ClutterActor *self,
8147 ClutterGeometry *geom)
8149 ClutterActorBox box;
8151 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8152 g_return_if_fail (geom != NULL);
8154 clutter_actor_get_allocation_box (self, &box);
8156 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8157 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8158 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8159 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8163 clutter_actor_update_constraints (ClutterActor *self,
8164 ClutterActorBox *allocation)
8166 ClutterActorPrivate *priv = self->priv;
8167 const GList *constraints, *l;
8169 if (priv->constraints == NULL)
8172 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8173 for (l = constraints; l != NULL; l = l->next)
8175 ClutterConstraint *constraint = l->data;
8176 ClutterActorMeta *meta = l->data;
8178 if (clutter_actor_meta_get_enabled (meta))
8180 _clutter_constraint_update_allocation (constraint,
8184 CLUTTER_NOTE (LAYOUT,
8185 "Allocation of '%s' after constraint '%s': "
8186 "{ %.2f, %.2f, %.2f, %.2f }",
8187 _clutter_actor_get_debug_name (self),
8188 _clutter_actor_meta_get_debug_name (meta),
8198 * clutter_actor_adjust_allocation:
8199 * @self: a #ClutterActor
8200 * @allocation: (inout): the allocation to adjust
8202 * Adjusts the passed allocation box taking into account the actor's
8203 * layout information, like alignment, expansion, and margin.
8206 clutter_actor_adjust_allocation (ClutterActor *self,
8207 ClutterActorBox *allocation)
8209 ClutterActorBox adj_allocation;
8210 float alloc_width, alloc_height;
8211 float min_width, min_height;
8212 float nat_width, nat_height;
8213 ClutterRequestMode req_mode;
8215 adj_allocation = *allocation;
8217 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8219 /* we want to hit the cache, so we use the public API */
8220 req_mode = clutter_actor_get_request_mode (self);
8222 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8224 clutter_actor_get_preferred_width (self, -1,
8227 clutter_actor_get_preferred_height (self, alloc_width,
8231 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8233 clutter_actor_get_preferred_height (self, -1,
8236 clutter_actor_get_preferred_height (self, alloc_height,
8241 #ifdef CLUTTER_ENABLE_DEBUG
8242 /* warn about underallocations */
8243 if (_clutter_diagnostic_enabled () &&
8244 (floorf (min_width - alloc_width) > 0 ||
8245 floorf (min_height - alloc_height) > 0))
8247 ClutterActor *parent = clutter_actor_get_parent (self);
8249 /* the only actors that are allowed to be underallocated are the Stage,
8250 * as it doesn't have an implicit size, and Actors that specifically
8251 * told us that they want to opt-out from layout control mechanisms
8252 * through the NO_LAYOUT escape hatch.
8254 if (parent != NULL &&
8255 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8257 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8258 "of %.2f x %.2f from its parent actor '%s', but its "
8259 "requested minimum size is of %.2f x %.2f",
8260 _clutter_actor_get_debug_name (self),
8261 alloc_width, alloc_height,
8262 _clutter_actor_get_debug_name (parent),
8263 min_width, min_height);
8268 clutter_actor_adjust_width (self,
8272 &adj_allocation.x2);
8274 clutter_actor_adjust_height (self,
8278 &adj_allocation.y2);
8280 /* we maintain the invariant that an allocation cannot be adjusted
8281 * to be outside the parent-given box
8283 if (adj_allocation.x1 < allocation->x1 ||
8284 adj_allocation.y1 < allocation->y1 ||
8285 adj_allocation.x2 > allocation->x2 ||
8286 adj_allocation.y2 > allocation->y2)
8288 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8289 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8290 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8291 _clutter_actor_get_debug_name (self),
8292 adj_allocation.x1, adj_allocation.y1,
8293 adj_allocation.x2 - adj_allocation.x1,
8294 adj_allocation.y2 - adj_allocation.y1,
8295 allocation->x1, allocation->y1,
8296 allocation->x2 - allocation->x1,
8297 allocation->y2 - allocation->y1);
8301 *allocation = adj_allocation;
8305 * clutter_actor_allocate:
8306 * @self: A #ClutterActor
8307 * @box: new allocation of the actor, in parent-relative coordinates
8308 * @flags: flags that control the allocation
8310 * Called by the parent of an actor to assign the actor its size.
8311 * Should never be called by applications (except when implementing
8312 * a container or layout manager).
8314 * Actors can know from their allocation box whether they have moved
8315 * with respect to their parent actor. The @flags parameter describes
8316 * additional information about the allocation, for instance whether
8317 * the parent has moved with respect to the stage, for example because
8318 * a grandparent's origin has moved.
8323 clutter_actor_allocate (ClutterActor *self,
8324 const ClutterActorBox *box,
8325 ClutterAllocationFlags flags)
8327 ClutterActorPrivate *priv;
8328 ClutterActorClass *klass;
8329 ClutterActorBox old_allocation, real_allocation;
8330 gboolean origin_changed, child_moved, size_changed;
8331 gboolean stage_allocation_changed;
8333 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8334 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8336 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8337 "which isn't a descendent of the stage!\n",
8338 self, _clutter_actor_get_debug_name (self));
8344 old_allocation = priv->allocation;
8345 real_allocation = *box;
8347 /* constraints are allowed to modify the allocation only here; we do
8348 * this prior to all the other checks so that we can bail out if the
8349 * allocation did not change
8351 clutter_actor_update_constraints (self, &real_allocation);
8353 /* adjust the allocation depending on the align/margin properties */
8354 clutter_actor_adjust_allocation (self, &real_allocation);
8356 if (real_allocation.x2 < real_allocation.x1 ||
8357 real_allocation.y2 < real_allocation.y1)
8359 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8360 _clutter_actor_get_debug_name (self),
8361 real_allocation.x2 - real_allocation.x1,
8362 real_allocation.y2 - real_allocation.y1);
8365 /* we allow 0-sized actors, but not negative-sized ones */
8366 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8367 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8369 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8371 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8372 real_allocation.y1 != old_allocation.y1);
8374 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8375 real_allocation.y2 != old_allocation.y2);
8377 if (origin_changed || child_moved || size_changed)
8378 stage_allocation_changed = TRUE;
8380 stage_allocation_changed = FALSE;
8382 /* If we get an allocation "out of the blue"
8383 * (we did not queue relayout), then we want to
8384 * ignore it. But if we have needs_allocation set,
8385 * we want to guarantee that allocate() virtual
8386 * method is always called, i.e. that queue_relayout()
8387 * always results in an allocate() invocation on
8390 * The optimization here is to avoid re-allocating
8391 * actors that did not queue relayout and were
8394 if (!priv->needs_allocation && !stage_allocation_changed)
8396 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8400 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8401 * clutter_actor_allocate(), it indicates whether the parent has its
8402 * absolute origin moved; when passed in to ClutterActor::allocate()
8403 * virtual method though, it indicates whether the child has its
8404 * absolute origin moved. So we set it when child_moved is TRUE
8407 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8409 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8411 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8412 _clutter_actor_get_debug_name (self));
8414 klass = CLUTTER_ACTOR_GET_CLASS (self);
8415 klass->allocate (self, &real_allocation, flags);
8417 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8419 if (stage_allocation_changed)
8420 clutter_actor_queue_redraw (self);
8424 * clutter_actor_set_allocation:
8425 * @self: a #ClutterActor
8426 * @box: a #ClutterActorBox
8427 * @flags: allocation flags
8429 * Stores the allocation of @self as defined by @box.
8431 * This function can only be called from within the implementation of
8432 * the #ClutterActorClass.allocate() virtual function.
8434 * The allocation should have been adjusted to take into account constraints,
8435 * alignment, and margin properties. If you are implementing a #ClutterActor
8436 * subclass that provides its own layout management policy for its children
8437 * instead of using a #ClutterLayoutManager delegate, you should not call
8438 * this function on the children of @self; instead, you should call
8439 * clutter_actor_allocate(), which will adjust the allocation box for
8442 * This function should only be used by subclasses of #ClutterActor
8443 * that wish to store their allocation but cannot chain up to the
8444 * parent's implementation; the default implementation of the
8445 * #ClutterActorClass.allocate() virtual function will call this
8448 * It is important to note that, while chaining up was the recommended
8449 * behaviour for #ClutterActor subclasses prior to the introduction of
8450 * this function, it is recommended to call clutter_actor_set_allocation()
8453 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8454 * to handle the allocation of its children, this function will call
8455 * the clutter_layout_manager_allocate() function only if the
8456 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8457 * expected that the subclass will call clutter_layout_manager_allocate()
8458 * by itself. For instance, the following code:
8462 * my_actor_allocate (ClutterActor *actor,
8463 * const ClutterActorBox *allocation,
8464 * ClutterAllocationFlags flags)
8466 * ClutterActorBox new_alloc;
8467 * ClutterAllocationFlags new_flags;
8469 * adjust_allocation (allocation, &new_alloc);
8471 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8473 * /* this will use the layout manager set on the actor */
8474 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8478 * is equivalent to this:
8482 * my_actor_allocate (ClutterActor *actor,
8483 * const ClutterActorBox *allocation,
8484 * ClutterAllocationFlags flags)
8486 * ClutterLayoutManager *layout;
8487 * ClutterActorBox new_alloc;
8489 * adjust_allocation (allocation, &new_alloc);
8491 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8493 * layout = clutter_actor_get_layout_manager (actor);
8494 * clutter_layout_manager_allocate (layout,
8495 * CLUTTER_CONTAINER (actor),
8504 clutter_actor_set_allocation (ClutterActor *self,
8505 const ClutterActorBox *box,
8506 ClutterAllocationFlags flags)
8508 ClutterActorPrivate *priv;
8511 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8512 g_return_if_fail (box != NULL);
8514 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8516 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8517 "can only be called from within the implementation of "
8518 "the ClutterActor::allocate() virtual function.");
8524 g_object_freeze_notify (G_OBJECT (self));
8526 changed = clutter_actor_set_allocation_internal (self, box, flags);
8528 /* we allocate our children before we notify changes in our geometry,
8529 * so that people connecting to properties will be able to get valid
8530 * data out of the sub-tree of the scene graph that has this actor at
8533 clutter_actor_maybe_layout_children (self, box, flags);
8537 ClutterActorBox signal_box = priv->allocation;
8538 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8540 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8545 g_object_thaw_notify (G_OBJECT (self));
8549 * clutter_actor_set_geometry:
8550 * @self: A #ClutterActor
8551 * @geometry: A #ClutterGeometry
8553 * Sets the actor's fixed position and forces its minimum and natural
8554 * size, in pixels. This means the untransformed actor will have the
8555 * given geometry. This is the same as calling clutter_actor_set_position()
8556 * and clutter_actor_set_size().
8558 * Deprecated: 1.10: Use clutter_actor_set_position() and
8559 * clutter_actor_set_size() instead.
8562 clutter_actor_set_geometry (ClutterActor *self,
8563 const ClutterGeometry *geometry)
8565 g_object_freeze_notify (G_OBJECT (self));
8567 clutter_actor_set_position (self, geometry->x, geometry->y);
8568 clutter_actor_set_size (self, geometry->width, geometry->height);
8570 g_object_thaw_notify (G_OBJECT (self));
8574 * clutter_actor_get_geometry:
8575 * @self: A #ClutterActor
8576 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8578 * Gets the size and position of an actor relative to its parent
8579 * actor. This is the same as calling clutter_actor_get_position() and
8580 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8581 * requested size and position if the actor's allocation is invalid.
8583 * Deprecated: 1.10: Use clutter_actor_get_position() and
8584 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8588 clutter_actor_get_geometry (ClutterActor *self,
8589 ClutterGeometry *geometry)
8591 gfloat x, y, width, height;
8593 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8594 g_return_if_fail (geometry != NULL);
8596 clutter_actor_get_position (self, &x, &y);
8597 clutter_actor_get_size (self, &width, &height);
8599 geometry->x = (int) x;
8600 geometry->y = (int) y;
8601 geometry->width = (int) width;
8602 geometry->height = (int) height;
8606 * clutter_actor_set_position:
8607 * @self: A #ClutterActor
8608 * @x: New left position of actor in pixels.
8609 * @y: New top position of actor in pixels.
8611 * Sets the actor's fixed position in pixels relative to any parent
8614 * If a layout manager is in use, this position will override the
8615 * layout manager and force a fixed position.
8618 clutter_actor_set_position (ClutterActor *self,
8622 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8624 g_object_freeze_notify (G_OBJECT (self));
8626 clutter_actor_set_x (self, x);
8627 clutter_actor_set_y (self, y);
8629 g_object_thaw_notify (G_OBJECT (self));
8633 * clutter_actor_get_fixed_position_set:
8634 * @self: A #ClutterActor
8636 * Checks whether an actor has a fixed position set (and will thus be
8637 * unaffected by any layout manager).
8639 * Return value: %TRUE if the fixed position is set on the actor
8644 clutter_actor_get_fixed_position_set (ClutterActor *self)
8646 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8648 return self->priv->position_set;
8652 * clutter_actor_set_fixed_position_set:
8653 * @self: A #ClutterActor
8654 * @is_set: whether to use fixed position
8656 * Sets whether an actor has a fixed position set (and will thus be
8657 * unaffected by any layout manager).
8662 clutter_actor_set_fixed_position_set (ClutterActor *self,
8665 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8667 if (self->priv->position_set == (is_set != FALSE))
8670 self->priv->position_set = is_set != FALSE;
8671 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8673 clutter_actor_queue_relayout (self);
8677 * clutter_actor_move_by:
8678 * @self: A #ClutterActor
8679 * @dx: Distance to move Actor on X axis.
8680 * @dy: Distance to move Actor on Y axis.
8682 * Moves an actor by the specified distance relative to its current
8683 * position in pixels.
8685 * This function modifies the fixed position of an actor and thus removes
8686 * it from any layout management. Another way to move an actor is with an
8687 * anchor point, see clutter_actor_set_anchor_point().
8692 clutter_actor_move_by (ClutterActor *self,
8696 const ClutterLayoutInfo *info;
8699 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8701 info = _clutter_actor_get_layout_info_or_defaults (self);
8705 clutter_actor_set_position (self, x + dx, y + dy);
8709 clutter_actor_set_min_width (ClutterActor *self,
8712 ClutterActorPrivate *priv = self->priv;
8713 ClutterActorBox old = { 0, };
8714 ClutterLayoutInfo *info;
8716 /* if we are setting the size on a top-level actor and the
8717 * backend only supports static top-levels (e.g. framebuffers)
8718 * then we ignore the passed value and we override it with
8719 * the stage implementation's preferred size.
8721 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8722 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8725 info = _clutter_actor_get_layout_info (self);
8727 if (priv->min_width_set && min_width == info->min_width)
8730 g_object_freeze_notify (G_OBJECT (self));
8732 clutter_actor_store_old_geometry (self, &old);
8734 info->min_width = min_width;
8735 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8736 clutter_actor_set_min_width_set (self, TRUE);
8738 clutter_actor_notify_if_geometry_changed (self, &old);
8740 g_object_thaw_notify (G_OBJECT (self));
8742 clutter_actor_queue_relayout (self);
8746 clutter_actor_set_min_height (ClutterActor *self,
8750 ClutterActorPrivate *priv = self->priv;
8751 ClutterActorBox old = { 0, };
8752 ClutterLayoutInfo *info;
8754 /* if we are setting the size on a top-level actor and the
8755 * backend only supports static top-levels (e.g. framebuffers)
8756 * then we ignore the passed value and we override it with
8757 * the stage implementation's preferred size.
8759 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8760 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8763 info = _clutter_actor_get_layout_info (self);
8765 if (priv->min_height_set && min_height == info->min_height)
8768 g_object_freeze_notify (G_OBJECT (self));
8770 clutter_actor_store_old_geometry (self, &old);
8772 info->min_height = min_height;
8773 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8774 clutter_actor_set_min_height_set (self, TRUE);
8776 clutter_actor_notify_if_geometry_changed (self, &old);
8778 g_object_thaw_notify (G_OBJECT (self));
8780 clutter_actor_queue_relayout (self);
8784 clutter_actor_set_natural_width (ClutterActor *self,
8785 gfloat natural_width)
8787 ClutterActorPrivate *priv = self->priv;
8788 ClutterActorBox old = { 0, };
8789 ClutterLayoutInfo *info;
8791 /* if we are setting the size on a top-level actor and the
8792 * backend only supports static top-levels (e.g. framebuffers)
8793 * then we ignore the passed value and we override it with
8794 * the stage implementation's preferred size.
8796 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8797 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8800 info = _clutter_actor_get_layout_info (self);
8802 if (priv->natural_width_set && natural_width == info->natural_width)
8805 g_object_freeze_notify (G_OBJECT (self));
8807 clutter_actor_store_old_geometry (self, &old);
8809 info->natural_width = natural_width;
8810 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8811 clutter_actor_set_natural_width_set (self, TRUE);
8813 clutter_actor_notify_if_geometry_changed (self, &old);
8815 g_object_thaw_notify (G_OBJECT (self));
8817 clutter_actor_queue_relayout (self);
8821 clutter_actor_set_natural_height (ClutterActor *self,
8822 gfloat natural_height)
8824 ClutterActorPrivate *priv = self->priv;
8825 ClutterActorBox old = { 0, };
8826 ClutterLayoutInfo *info;
8828 /* if we are setting the size on a top-level actor and the
8829 * backend only supports static top-levels (e.g. framebuffers)
8830 * then we ignore the passed value and we override it with
8831 * the stage implementation's preferred size.
8833 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8834 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8837 info = _clutter_actor_get_layout_info (self);
8839 if (priv->natural_height_set && natural_height == info->natural_height)
8842 g_object_freeze_notify (G_OBJECT (self));
8844 clutter_actor_store_old_geometry (self, &old);
8846 info->natural_height = natural_height;
8847 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8848 clutter_actor_set_natural_height_set (self, TRUE);
8850 clutter_actor_notify_if_geometry_changed (self, &old);
8852 g_object_thaw_notify (G_OBJECT (self));
8854 clutter_actor_queue_relayout (self);
8858 clutter_actor_set_min_width_set (ClutterActor *self,
8859 gboolean use_min_width)
8861 ClutterActorPrivate *priv = self->priv;
8862 ClutterActorBox old = { 0, };
8864 if (priv->min_width_set == (use_min_width != FALSE))
8867 clutter_actor_store_old_geometry (self, &old);
8869 priv->min_width_set = use_min_width != FALSE;
8870 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8872 clutter_actor_notify_if_geometry_changed (self, &old);
8874 clutter_actor_queue_relayout (self);
8878 clutter_actor_set_min_height_set (ClutterActor *self,
8879 gboolean use_min_height)
8881 ClutterActorPrivate *priv = self->priv;
8882 ClutterActorBox old = { 0, };
8884 if (priv->min_height_set == (use_min_height != FALSE))
8887 clutter_actor_store_old_geometry (self, &old);
8889 priv->min_height_set = use_min_height != FALSE;
8890 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8892 clutter_actor_notify_if_geometry_changed (self, &old);
8894 clutter_actor_queue_relayout (self);
8898 clutter_actor_set_natural_width_set (ClutterActor *self,
8899 gboolean use_natural_width)
8901 ClutterActorPrivate *priv = self->priv;
8902 ClutterActorBox old = { 0, };
8904 if (priv->natural_width_set == (use_natural_width != FALSE))
8907 clutter_actor_store_old_geometry (self, &old);
8909 priv->natural_width_set = use_natural_width != FALSE;
8910 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8912 clutter_actor_notify_if_geometry_changed (self, &old);
8914 clutter_actor_queue_relayout (self);
8918 clutter_actor_set_natural_height_set (ClutterActor *self,
8919 gboolean use_natural_height)
8921 ClutterActorPrivate *priv = self->priv;
8922 ClutterActorBox old = { 0, };
8924 if (priv->natural_height_set == (use_natural_height != FALSE))
8927 clutter_actor_store_old_geometry (self, &old);
8929 priv->natural_height_set = use_natural_height != FALSE;
8930 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8932 clutter_actor_notify_if_geometry_changed (self, &old);
8934 clutter_actor_queue_relayout (self);
8938 * clutter_actor_set_request_mode:
8939 * @self: a #ClutterActor
8940 * @mode: the request mode
8942 * Sets the geometry request mode of @self.
8944 * The @mode determines the order for invoking
8945 * clutter_actor_get_preferred_width() and
8946 * clutter_actor_get_preferred_height()
8951 clutter_actor_set_request_mode (ClutterActor *self,
8952 ClutterRequestMode mode)
8954 ClutterActorPrivate *priv;
8956 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8960 if (priv->request_mode == mode)
8963 priv->request_mode = mode;
8965 priv->needs_width_request = TRUE;
8966 priv->needs_height_request = TRUE;
8968 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8970 clutter_actor_queue_relayout (self);
8974 * clutter_actor_get_request_mode:
8975 * @self: a #ClutterActor
8977 * Retrieves the geometry request mode of @self
8979 * Return value: the request mode for the actor
8984 clutter_actor_get_request_mode (ClutterActor *self)
8986 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8987 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8989 return self->priv->request_mode;
8992 /* variant of set_width() without checks and without notification
8993 * freeze+thaw, for internal usage only
8996 clutter_actor_set_width_internal (ClutterActor *self,
9001 /* the Stage will use the :min-width to control the minimum
9002 * width to be resized to, so we should not be setting it
9003 * along with the :natural-width
9005 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9006 clutter_actor_set_min_width (self, width);
9008 clutter_actor_set_natural_width (self, width);
9012 /* we only unset the :natural-width for the Stage */
9013 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9014 clutter_actor_set_min_width_set (self, FALSE);
9016 clutter_actor_set_natural_width_set (self, FALSE);
9020 /* variant of set_height() without checks and without notification
9021 * freeze+thaw, for internal usage only
9024 clutter_actor_set_height_internal (ClutterActor *self,
9029 /* see the comment above in set_width_internal() */
9030 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9031 clutter_actor_set_min_height (self, height);
9033 clutter_actor_set_natural_height (self, height);
9037 /* see the comment above in set_width_internal() */
9038 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9039 clutter_actor_set_min_height_set (self, FALSE);
9041 clutter_actor_set_natural_height_set (self, FALSE);
9046 * clutter_actor_set_size:
9047 * @self: A #ClutterActor
9048 * @width: New width of actor in pixels, or -1
9049 * @height: New height of actor in pixels, or -1
9051 * Sets the actor's size request in pixels. This overrides any
9052 * "normal" size request the actor would have. For example
9053 * a text actor might normally request the size of the text;
9054 * this function would force a specific size instead.
9056 * If @width and/or @height are -1 the actor will use its
9057 * "normal" size request instead of overriding it, i.e.
9058 * you can "unset" the size with -1.
9060 * This function sets or unsets both the minimum and natural size.
9063 clutter_actor_set_size (ClutterActor *self,
9067 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9069 g_object_freeze_notify (G_OBJECT (self));
9071 clutter_actor_set_width (self, width);
9072 clutter_actor_set_height (self, height);
9074 g_object_thaw_notify (G_OBJECT (self));
9078 * clutter_actor_get_size:
9079 * @self: A #ClutterActor
9080 * @width: (out) (allow-none): return location for the width, or %NULL.
9081 * @height: (out) (allow-none): return location for the height, or %NULL.
9083 * This function tries to "do what you mean" and return
9084 * the size an actor will have. If the actor has a valid
9085 * allocation, the allocation will be returned; otherwise,
9086 * the actors natural size request will be returned.
9088 * If you care whether you get the request vs. the allocation, you
9089 * should probably call a different function like
9090 * clutter_actor_get_allocation_box() or
9091 * clutter_actor_get_preferred_width().
9096 clutter_actor_get_size (ClutterActor *self,
9100 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9103 *width = clutter_actor_get_width (self);
9106 *height = clutter_actor_get_height (self);
9110 * clutter_actor_get_position:
9111 * @self: a #ClutterActor
9112 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9113 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9115 * This function tries to "do what you mean" and tell you where the
9116 * actor is, prior to any transformations. Retrieves the fixed
9117 * position of an actor in pixels, if one has been set; otherwise, if
9118 * the allocation is valid, returns the actor's allocated position;
9119 * otherwise, returns 0,0.
9121 * The returned position is in pixels.
9126 clutter_actor_get_position (ClutterActor *self,
9130 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9133 *x = clutter_actor_get_x (self);
9136 *y = clutter_actor_get_y (self);
9140 * clutter_actor_get_transformed_position:
9141 * @self: A #ClutterActor
9142 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9143 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9145 * Gets the absolute position of an actor, in pixels relative to the stage.
9150 clutter_actor_get_transformed_position (ClutterActor *self,
9157 v1.x = v1.y = v1.z = 0;
9158 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9168 * clutter_actor_get_transformed_size:
9169 * @self: A #ClutterActor
9170 * @width: (out) (allow-none): return location for the width, or %NULL
9171 * @height: (out) (allow-none): return location for the height, or %NULL
9173 * Gets the absolute size of an actor in pixels, taking into account the
9176 * If the actor has a valid allocation, the allocated size will be used.
9177 * If the actor has not a valid allocation then the preferred size will
9178 * be transformed and returned.
9180 * If you want the transformed allocation, see
9181 * clutter_actor_get_abs_allocation_vertices() instead.
9183 * <note>When the actor (or one of its ancestors) is rotated around the
9184 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9185 * as a generic quadrangle; in that case this function returns the size
9186 * of the smallest rectangle that encapsulates the entire quad. Please
9187 * note that in this case no assumptions can be made about the relative
9188 * position of this envelope to the absolute position of the actor, as
9189 * returned by clutter_actor_get_transformed_position(); if you need this
9190 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9191 * to get the coords of the actual quadrangle.</note>
9196 clutter_actor_get_transformed_size (ClutterActor *self,
9200 ClutterActorPrivate *priv;
9202 gfloat x_min, x_max, y_min, y_max;
9205 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9209 /* if the actor hasn't been allocated yet, get the preferred
9210 * size and transform that
9212 if (priv->needs_allocation)
9214 gfloat natural_width, natural_height;
9215 ClutterActorBox box;
9217 /* Make a fake allocation to transform.
9219 * NB: _clutter_actor_transform_and_project_box expects a box in
9220 * the actor's coordinate space... */
9225 natural_width = natural_height = 0;
9226 clutter_actor_get_preferred_size (self, NULL, NULL,
9230 box.x2 = natural_width;
9231 box.y2 = natural_height;
9233 _clutter_actor_transform_and_project_box (self, &box, v);
9236 clutter_actor_get_abs_allocation_vertices (self, v);
9238 x_min = x_max = v[0].x;
9239 y_min = y_max = v[0].y;
9241 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9257 *width = x_max - x_min;
9260 *height = y_max - y_min;
9264 * clutter_actor_get_width:
9265 * @self: A #ClutterActor
9267 * Retrieves the width of a #ClutterActor.
9269 * If the actor has a valid allocation, this function will return the
9270 * width of the allocated area given to the actor.
9272 * If the actor does not have a valid allocation, this function will
9273 * return the actor's natural width, that is the preferred width of
9276 * If you care whether you get the preferred width or the width that
9277 * has been assigned to the actor, you should probably call a different
9278 * function like clutter_actor_get_allocation_box() to retrieve the
9279 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9282 * If an actor has a fixed width, for instance a width that has been
9283 * assigned using clutter_actor_set_width(), the width returned will
9284 * be the same value.
9286 * Return value: the width of the actor, in pixels
9289 clutter_actor_get_width (ClutterActor *self)
9291 ClutterActorPrivate *priv;
9293 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9297 if (priv->needs_allocation)
9299 gfloat natural_width = 0;
9301 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9302 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9305 gfloat natural_height = 0;
9307 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9308 clutter_actor_get_preferred_width (self, natural_height,
9313 return natural_width;
9316 return priv->allocation.x2 - priv->allocation.x1;
9320 * clutter_actor_get_height:
9321 * @self: A #ClutterActor
9323 * Retrieves the height of a #ClutterActor.
9325 * If the actor has a valid allocation, this function will return the
9326 * height of the allocated area given to the actor.
9328 * If the actor does not have a valid allocation, this function will
9329 * return the actor's natural height, that is the preferred height of
9332 * If you care whether you get the preferred height or the height that
9333 * has been assigned to the actor, you should probably call a different
9334 * function like clutter_actor_get_allocation_box() to retrieve the
9335 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9338 * If an actor has a fixed height, for instance a height that has been
9339 * assigned using clutter_actor_set_height(), the height returned will
9340 * be the same value.
9342 * Return value: the height of the actor, in pixels
9345 clutter_actor_get_height (ClutterActor *self)
9347 ClutterActorPrivate *priv;
9349 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9353 if (priv->needs_allocation)
9355 gfloat natural_height = 0;
9357 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9359 gfloat natural_width = 0;
9361 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9362 clutter_actor_get_preferred_height (self, natural_width,
9363 NULL, &natural_height);
9366 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9368 return natural_height;
9371 return priv->allocation.y2 - priv->allocation.y1;
9375 * clutter_actor_set_width:
9376 * @self: A #ClutterActor
9377 * @width: Requested new width for the actor, in pixels, or -1
9379 * Forces a width on an actor, causing the actor's preferred width
9380 * and height (if any) to be ignored.
9382 * If @width is -1 the actor will use its preferred width request
9383 * instead of overriding it, i.e. you can "unset" the width with -1.
9385 * This function sets both the minimum and natural size of the actor.
9390 clutter_actor_set_width (ClutterActor *self,
9393 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9395 if (clutter_actor_get_easing_duration (self) != 0)
9397 ClutterTransition *transition;
9399 transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9400 if (transition == NULL)
9402 float old_width = clutter_actor_get_width (self);
9404 transition = _clutter_actor_create_transition (self,
9405 obj_props[PROP_WIDTH],
9408 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9411 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9413 clutter_actor_queue_relayout (self);
9417 g_object_freeze_notify (G_OBJECT (self));
9419 clutter_actor_set_width_internal (self, width);
9421 g_object_thaw_notify (G_OBJECT (self));
9426 * clutter_actor_set_height:
9427 * @self: A #ClutterActor
9428 * @height: Requested new height for the actor, in pixels, or -1
9430 * Forces a height on an actor, causing the actor's preferred width
9431 * and height (if any) to be ignored.
9433 * If @height is -1 the actor will use its preferred height instead of
9434 * overriding it, i.e. you can "unset" the height with -1.
9436 * This function sets both the minimum and natural size of the actor.
9441 clutter_actor_set_height (ClutterActor *self,
9444 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9446 if (clutter_actor_get_easing_duration (self) != 0)
9448 ClutterTransition *transition;
9450 transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9451 if (transition == NULL)
9453 float old_height = clutter_actor_get_height (self);
9455 transition = _clutter_actor_create_transition (self,
9456 obj_props[PROP_HEIGHT],
9459 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9462 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9464 clutter_actor_queue_relayout (self);
9468 g_object_freeze_notify (G_OBJECT (self));
9470 clutter_actor_set_height_internal (self, height);
9472 g_object_thaw_notify (G_OBJECT (self));
9477 clutter_actor_set_x_internal (ClutterActor *self,
9480 ClutterActorPrivate *priv = self->priv;
9481 ClutterLayoutInfo *linfo;
9482 ClutterActorBox old = { 0, };
9484 linfo = _clutter_actor_get_layout_info (self);
9486 if (priv->position_set && linfo->fixed_x == x)
9489 clutter_actor_store_old_geometry (self, &old);
9492 clutter_actor_set_fixed_position_set (self, TRUE);
9494 clutter_actor_notify_if_geometry_changed (self, &old);
9496 clutter_actor_queue_relayout (self);
9500 clutter_actor_set_y_internal (ClutterActor *self,
9503 ClutterActorPrivate *priv = self->priv;
9504 ClutterLayoutInfo *linfo;
9505 ClutterActorBox old = { 0, };
9507 linfo = _clutter_actor_get_layout_info (self);
9509 if (priv->position_set && linfo->fixed_y == y)
9512 clutter_actor_store_old_geometry (self, &old);
9515 clutter_actor_set_fixed_position_set (self, TRUE);
9517 clutter_actor_notify_if_geometry_changed (self, &old);
9519 clutter_actor_queue_relayout (self);
9523 * clutter_actor_set_x:
9524 * @self: a #ClutterActor
9525 * @x: the actor's position on the X axis
9527 * Sets the actor's X coordinate, relative to its parent, in pixels.
9529 * Overrides any layout manager and forces a fixed position for
9532 * The #ClutterActor:x property is animatable.
9537 clutter_actor_set_x (ClutterActor *self,
9540 const ClutterLayoutInfo *linfo;
9542 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9544 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9546 if (clutter_actor_get_easing_duration (self) != 0)
9548 ClutterTransition *transition;
9550 transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9551 if (transition == NULL)
9553 transition = _clutter_actor_create_transition (self,
9558 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9561 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9563 clutter_actor_queue_relayout (self);
9566 clutter_actor_set_x_internal (self, x);
9570 * clutter_actor_set_y:
9571 * @self: a #ClutterActor
9572 * @y: the actor's position on the Y axis
9574 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9576 * Overrides any layout manager and forces a fixed position for
9579 * The #ClutterActor:y property is animatable.
9584 clutter_actor_set_y (ClutterActor *self,
9587 const ClutterLayoutInfo *linfo;
9589 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9591 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9593 if (clutter_actor_get_easing_duration (self) != 0)
9595 ClutterTransition *transition;
9597 transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9598 if (transition == NULL)
9600 transition = _clutter_actor_create_transition (self,
9605 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9608 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9610 clutter_actor_queue_relayout (self);
9613 clutter_actor_set_y_internal (self, y);
9615 clutter_actor_queue_relayout (self);
9619 * clutter_actor_get_x:
9620 * @self: A #ClutterActor
9622 * Retrieves the X coordinate of a #ClutterActor.
9624 * This function tries to "do what you mean", by returning the
9625 * correct value depending on the actor's state.
9627 * If the actor has a valid allocation, this function will return
9628 * the X coordinate of the origin of the allocation box.
9630 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9631 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9632 * function will return that coordinate.
9634 * If both the allocation and a fixed position are missing, this function
9637 * Return value: the X coordinate, in pixels, ignoring any
9638 * transformation (i.e. scaling, rotation)
9641 clutter_actor_get_x (ClutterActor *self)
9643 ClutterActorPrivate *priv;
9645 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9649 if (priv->needs_allocation)
9651 if (priv->position_set)
9653 const ClutterLayoutInfo *info;
9655 info = _clutter_actor_get_layout_info_or_defaults (self);
9657 return info->fixed_x;
9663 return priv->allocation.x1;
9667 * clutter_actor_get_y:
9668 * @self: A #ClutterActor
9670 * Retrieves the Y coordinate of a #ClutterActor.
9672 * This function tries to "do what you mean", by returning the
9673 * correct value depending on the actor's state.
9675 * If the actor has a valid allocation, this function will return
9676 * the Y coordinate of the origin of the allocation box.
9678 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9679 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9680 * function will return that coordinate.
9682 * If both the allocation and a fixed position are missing, this function
9685 * Return value: the Y coordinate, in pixels, ignoring any
9686 * transformation (i.e. scaling, rotation)
9689 clutter_actor_get_y (ClutterActor *self)
9691 ClutterActorPrivate *priv;
9693 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9697 if (priv->needs_allocation)
9699 if (priv->position_set)
9701 const ClutterLayoutInfo *info;
9703 info = _clutter_actor_get_layout_info_or_defaults (self);
9705 return info->fixed_y;
9711 return priv->allocation.y1;
9715 * clutter_actor_set_scale:
9716 * @self: A #ClutterActor
9717 * @scale_x: double factor to scale actor by horizontally.
9718 * @scale_y: double factor to scale actor by vertically.
9720 * Scales an actor with the given factors. The scaling is relative to
9721 * the scale center and the anchor point. The scale center is
9722 * unchanged by this function and defaults to 0,0.
9724 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9730 clutter_actor_set_scale (ClutterActor *self,
9734 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9736 g_object_freeze_notify (G_OBJECT (self));
9738 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9739 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9741 g_object_thaw_notify (G_OBJECT (self));
9745 * clutter_actor_set_scale_full:
9746 * @self: A #ClutterActor
9747 * @scale_x: double factor to scale actor by horizontally.
9748 * @scale_y: double factor to scale actor by vertically.
9749 * @center_x: X coordinate of the center of the scale.
9750 * @center_y: Y coordinate of the center of the scale
9752 * Scales an actor with the given factors around the given center
9753 * point. The center point is specified in pixels relative to the
9754 * anchor point (usually the top left corner of the actor).
9756 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9762 clutter_actor_set_scale_full (ClutterActor *self,
9768 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9770 g_object_freeze_notify (G_OBJECT (self));
9772 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9773 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9774 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9775 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9777 g_object_thaw_notify (G_OBJECT (self));
9781 * clutter_actor_set_scale_with_gravity:
9782 * @self: A #ClutterActor
9783 * @scale_x: double factor to scale actor by horizontally.
9784 * @scale_y: double factor to scale actor by vertically.
9785 * @gravity: the location of the scale center expressed as a compass
9788 * Scales an actor with the given factors around the given
9789 * center point. The center point is specified as one of the compass
9790 * directions in #ClutterGravity. For example, setting it to north
9791 * will cause the top of the actor to remain unchanged and the rest of
9792 * the actor to expand left, right and downwards.
9794 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9800 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9803 ClutterGravity gravity)
9805 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9807 g_object_freeze_notify (G_OBJECT (self));
9809 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9810 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9811 clutter_actor_set_scale_gravity (self, gravity);
9813 g_object_thaw_notify (G_OBJECT (self));
9817 * clutter_actor_get_scale:
9818 * @self: A #ClutterActor
9819 * @scale_x: (out) (allow-none): Location to store horizonal
9820 * scale factor, or %NULL.
9821 * @scale_y: (out) (allow-none): Location to store vertical
9822 * scale factor, or %NULL.
9824 * Retrieves an actors scale factors.
9829 clutter_actor_get_scale (ClutterActor *self,
9833 const ClutterTransformInfo *info;
9835 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9837 info = _clutter_actor_get_transform_info_or_defaults (self);
9840 *scale_x = info->scale_x;
9843 *scale_y = info->scale_y;
9847 * clutter_actor_get_scale_center:
9848 * @self: A #ClutterActor
9849 * @center_x: (out) (allow-none): Location to store the X position
9850 * of the scale center, or %NULL.
9851 * @center_y: (out) (allow-none): Location to store the Y position
9852 * of the scale center, or %NULL.
9854 * Retrieves the scale center coordinate in pixels relative to the top
9855 * left corner of the actor. If the scale center was specified using a
9856 * #ClutterGravity this will calculate the pixel offset using the
9857 * current size of the actor.
9862 clutter_actor_get_scale_center (ClutterActor *self,
9866 const ClutterTransformInfo *info;
9868 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9870 info = _clutter_actor_get_transform_info_or_defaults (self);
9872 clutter_anchor_coord_get_units (self, &info->scale_center,
9879 * clutter_actor_get_scale_gravity:
9880 * @self: A #ClutterActor
9882 * Retrieves the scale center as a compass direction. If the scale
9883 * center was specified in pixels or units this will return
9884 * %CLUTTER_GRAVITY_NONE.
9886 * Return value: the scale gravity
9891 clutter_actor_get_scale_gravity (ClutterActor *self)
9893 const ClutterTransformInfo *info;
9895 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9897 info = _clutter_actor_get_transform_info_or_defaults (self);
9899 return clutter_anchor_coord_get_gravity (&info->scale_center);
9903 clutter_actor_set_opacity_internal (ClutterActor *self,
9906 ClutterActorPrivate *priv = self->priv;
9908 if (priv->opacity != opacity)
9910 priv->opacity = opacity;
9912 /* Queue a redraw from the flatten effect so that it can use
9913 its cached image if available instead of having to redraw the
9914 actual actor. If it doesn't end up using the FBO then the
9915 effect is still able to continue the paint anyway. If there
9916 is no flatten effect yet then this is equivalent to queueing
9918 _clutter_actor_queue_redraw_full (self,
9921 priv->flatten_effect);
9923 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9928 * clutter_actor_set_opacity:
9929 * @self: A #ClutterActor
9930 * @opacity: New opacity value for the actor.
9932 * Sets the actor's opacity, with zero being completely transparent and
9933 * 255 (0xff) being fully opaque.
9935 * The #ClutterActor:opacity property is animatable.
9938 clutter_actor_set_opacity (ClutterActor *self,
9941 ClutterActorPrivate *priv;
9943 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9947 if (clutter_actor_get_easing_duration (self) != 0)
9949 ClutterTransition *transition;
9951 transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9952 if (transition == NULL)
9954 transition = _clutter_actor_create_transition (self,
9955 obj_props[PROP_OPACITY],
9958 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9961 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9963 clutter_actor_queue_redraw (self);
9966 clutter_actor_set_opacity_internal (self, opacity);
9970 * clutter_actor_get_paint_opacity_internal:
9971 * @self: a #ClutterActor
9973 * Retrieves the absolute opacity of the actor, as it appears on the stage
9975 * This function does not do type checks
9977 * Return value: the absolute opacity of the actor
9980 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9982 ClutterActorPrivate *priv = self->priv;
9983 ClutterActor *parent;
9985 /* override the top-level opacity to always be 255; even in
9986 * case of ClutterStage:use-alpha being TRUE we want the rest
9987 * of the scene to be painted
9989 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9992 if (priv->opacity_override >= 0)
9993 return priv->opacity_override;
9995 parent = priv->parent;
9997 /* Factor in the actual actors opacity with parents */
10000 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10002 if (opacity != 0xff)
10003 return (opacity * priv->opacity) / 0xff;
10006 return priv->opacity;
10011 * clutter_actor_get_paint_opacity:
10012 * @self: A #ClutterActor
10014 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10016 * This function traverses the hierarchy chain and composites the opacity of
10017 * the actor with that of its parents.
10019 * This function is intended for subclasses to use in the paint virtual
10020 * function, to paint themselves with the correct opacity.
10022 * Return value: The actor opacity value.
10027 clutter_actor_get_paint_opacity (ClutterActor *self)
10029 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10031 return clutter_actor_get_paint_opacity_internal (self);
10035 * clutter_actor_get_opacity:
10036 * @self: a #ClutterActor
10038 * Retrieves the opacity value of an actor, as set by
10039 * clutter_actor_set_opacity().
10041 * For retrieving the absolute opacity of the actor inside a paint
10042 * virtual function, see clutter_actor_get_paint_opacity().
10044 * Return value: the opacity of the actor
10047 clutter_actor_get_opacity (ClutterActor *self)
10049 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10051 return self->priv->opacity;
10055 * clutter_actor_set_offscreen_redirect:
10056 * @self: A #ClutterActor
10057 * @redirect: New offscreen redirect flags for the actor.
10059 * Defines the circumstances where the actor should be redirected into
10060 * an offscreen image. The offscreen image is used to flatten the
10061 * actor into a single image while painting for two main reasons.
10062 * Firstly, when the actor is painted a second time without any of its
10063 * contents changing it can simply repaint the cached image without
10064 * descending further down the actor hierarchy. Secondly, it will make
10065 * the opacity look correct even if there are overlapping primitives
10068 * Caching the actor could in some cases be a performance win and in
10069 * some cases be a performance lose so it is important to determine
10070 * which value is right for an actor before modifying this value. For
10071 * example, there is never any reason to flatten an actor that is just
10072 * a single texture (such as a #ClutterTexture) because it is
10073 * effectively already cached in an image so the offscreen would be
10074 * redundant. Also if the actor contains primitives that are far apart
10075 * with a large transparent area in the middle (such as a large
10076 * CluterGroup with a small actor in the top left and a small actor in
10077 * the bottom right) then the cached image will contain the entire
10078 * image of the large area and the paint will waste time blending all
10079 * of the transparent pixels in the middle.
10081 * The default method of implementing opacity on a container simply
10082 * forwards on the opacity to all of the children. If the children are
10083 * overlapping then it will appear as if they are two separate glassy
10084 * objects and there will be a break in the color where they
10085 * overlap. By redirecting to an offscreen buffer it will be as if the
10086 * two opaque objects are combined into one and then made transparent
10087 * which is usually what is expected.
10089 * The image below demonstrates the difference between redirecting and
10090 * not. The image shows two Clutter groups, each containing a red and
10091 * a green rectangle which overlap. The opacity on the group is set to
10092 * 128 (which is 50%). When the offscreen redirect is not used, the
10093 * red rectangle can be seen through the blue rectangle as if the two
10094 * rectangles were separately transparent. When the redirect is used
10095 * the group as a whole is transparent instead so the red rectangle is
10096 * not visible where they overlap.
10098 * <figure id="offscreen-redirect">
10099 * <title>Sample of using an offscreen redirect for transparency</title>
10100 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10103 * The default value for this property is 0, so we effectively will
10104 * never redirect an actor offscreen by default. This means that there
10105 * are times that transparent actors may look glassy as described
10106 * above. The reason this is the default is because there is a
10107 * performance trade off between quality and performance here. In many
10108 * cases the default form of glassy opacity looks good enough, but if
10109 * it's not you will need to set the
10110 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10111 * redirection for opacity.
10113 * Custom actors that don't contain any overlapping primitives are
10114 * recommended to override the has_overlaps() virtual to return %FALSE
10115 * for maximum efficiency.
10120 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10121 ClutterOffscreenRedirect redirect)
10123 ClutterActorPrivate *priv;
10125 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10129 if (priv->offscreen_redirect != redirect)
10131 priv->offscreen_redirect = redirect;
10133 /* Queue a redraw from the effect so that it can use its cached
10134 image if available instead of having to redraw the actual
10135 actor. If it doesn't end up using the FBO then the effect is
10136 still able to continue the paint anyway. If there is no
10137 effect then this is equivalent to queuing a full redraw */
10138 _clutter_actor_queue_redraw_full (self,
10141 priv->flatten_effect);
10143 g_object_notify_by_pspec (G_OBJECT (self),
10144 obj_props[PROP_OFFSCREEN_REDIRECT]);
10149 * clutter_actor_get_offscreen_redirect:
10150 * @self: a #ClutterActor
10152 * Retrieves whether to redirect the actor to an offscreen buffer, as
10153 * set by clutter_actor_set_offscreen_redirect().
10155 * Return value: the value of the offscreen-redirect property of the actor
10159 ClutterOffscreenRedirect
10160 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10162 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10164 return self->priv->offscreen_redirect;
10168 * clutter_actor_set_name:
10169 * @self: A #ClutterActor
10170 * @name: Textual tag to apply to actor
10172 * Sets the given name to @self. The name can be used to identify
10176 clutter_actor_set_name (ClutterActor *self,
10179 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10181 g_free (self->priv->name);
10182 self->priv->name = g_strdup (name);
10184 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10188 * clutter_actor_get_name:
10189 * @self: A #ClutterActor
10191 * Retrieves the name of @self.
10193 * Return value: the name of the actor, or %NULL. The returned string is
10194 * owned by the actor and should not be modified or freed.
10197 clutter_actor_get_name (ClutterActor *self)
10199 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10201 return self->priv->name;
10205 * clutter_actor_get_gid:
10206 * @self: A #ClutterActor
10208 * Retrieves the unique id for @self.
10210 * Return value: Globally unique value for this object instance.
10214 * Deprecated: 1.8: The id is not used any longer.
10217 clutter_actor_get_gid (ClutterActor *self)
10219 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10221 return self->priv->id;
10225 clutter_actor_set_depth_internal (ClutterActor *self,
10228 ClutterTransformInfo *info;
10230 info = _clutter_actor_get_transform_info (self);
10232 if (info->depth != depth)
10234 /* Sets Z value - XXX 2.0: should we invert? */
10235 info->depth = depth;
10237 self->priv->transform_valid = FALSE;
10239 /* FIXME - remove this crap; sadly, there are still containers
10240 * in Clutter that depend on this utter brain damage
10242 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10244 clutter_actor_queue_redraw (self);
10246 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10251 * clutter_actor_set_depth:
10252 * @self: a #ClutterActor
10255 * Sets the Z coordinate of @self to @depth.
10257 * The unit used by @depth is dependant on the perspective setup. See
10258 * also clutter_stage_set_perspective().
10261 clutter_actor_set_depth (ClutterActor *self,
10264 const ClutterTransformInfo *tinfo;
10266 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10268 tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10270 if (clutter_actor_get_easing_duration (self) != 0)
10272 ClutterTransition *transition;
10274 transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10275 if (transition == NULL)
10277 transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10280 clutter_timeline_start (CLUTTER_TIMELINE (transition));
10283 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10285 clutter_actor_queue_redraw (self);
10288 clutter_actor_set_depth_internal (self, depth);
10292 * clutter_actor_get_depth:
10293 * @self: a #ClutterActor
10295 * Retrieves the depth of @self.
10297 * Return value: the depth of the actor
10300 clutter_actor_get_depth (ClutterActor *self)
10302 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10304 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10308 * clutter_actor_set_rotation:
10309 * @self: a #ClutterActor
10310 * @axis: the axis of rotation
10311 * @angle: the angle of rotation
10312 * @x: X coordinate of the rotation center
10313 * @y: Y coordinate of the rotation center
10314 * @z: Z coordinate of the rotation center
10316 * Sets the rotation angle of @self around the given axis.
10318 * The rotation center coordinates used depend on the value of @axis:
10320 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10321 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10322 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10325 * The rotation coordinates are relative to the anchor point of the
10326 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10327 * point is set, the upper left corner is assumed as the origin.
10332 clutter_actor_set_rotation (ClutterActor *self,
10333 ClutterRotateAxis axis,
10341 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10347 g_object_freeze_notify (G_OBJECT (self));
10349 clutter_actor_set_rotation_angle (self, axis, angle);
10350 clutter_actor_set_rotation_center_internal (self, axis, &v);
10352 g_object_thaw_notify (G_OBJECT (self));
10356 * clutter_actor_set_z_rotation_from_gravity:
10357 * @self: a #ClutterActor
10358 * @angle: the angle of rotation
10359 * @gravity: the center point of the rotation
10361 * Sets the rotation angle of @self around the Z axis using the center
10362 * point specified as a compass point. For example to rotate such that
10363 * the center of the actor remains static you can use
10364 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10365 * will move accordingly.
10370 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10372 ClutterGravity gravity)
10374 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10376 if (gravity == CLUTTER_GRAVITY_NONE)
10377 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10380 GObject *obj = G_OBJECT (self);
10381 ClutterTransformInfo *info;
10383 info = _clutter_actor_get_transform_info (self);
10385 g_object_freeze_notify (obj);
10387 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10389 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10390 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10391 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10393 g_object_thaw_notify (obj);
10398 * clutter_actor_get_rotation:
10399 * @self: a #ClutterActor
10400 * @axis: the axis of rotation
10401 * @x: (out): return value for the X coordinate of the center of rotation
10402 * @y: (out): return value for the Y coordinate of the center of rotation
10403 * @z: (out): return value for the Z coordinate of the center of rotation
10405 * Retrieves the angle and center of rotation on the given axis,
10406 * set using clutter_actor_set_rotation().
10408 * Return value: the angle of rotation
10413 clutter_actor_get_rotation (ClutterActor *self,
10414 ClutterRotateAxis axis,
10419 const ClutterTransformInfo *info;
10420 const AnchorCoord *anchor_coord;
10421 gdouble retval = 0;
10423 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10425 info = _clutter_actor_get_transform_info_or_defaults (self);
10429 case CLUTTER_X_AXIS:
10430 anchor_coord = &info->rx_center;
10431 retval = info->rx_angle;
10434 case CLUTTER_Y_AXIS:
10435 anchor_coord = &info->ry_center;
10436 retval = info->ry_angle;
10439 case CLUTTER_Z_AXIS:
10440 anchor_coord = &info->rz_center;
10441 retval = info->rz_angle;
10445 anchor_coord = NULL;
10450 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10456 * clutter_actor_get_z_rotation_gravity:
10457 * @self: A #ClutterActor
10459 * Retrieves the center for the rotation around the Z axis as a
10460 * compass direction. If the center was specified in pixels or units
10461 * this will return %CLUTTER_GRAVITY_NONE.
10463 * Return value: the Z rotation center
10468 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10470 const ClutterTransformInfo *info;
10472 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10474 info = _clutter_actor_get_transform_info_or_defaults (self);
10476 return clutter_anchor_coord_get_gravity (&info->rz_center);
10480 * clutter_actor_set_clip:
10481 * @self: A #ClutterActor
10482 * @xoff: X offset of the clip rectangle
10483 * @yoff: Y offset of the clip rectangle
10484 * @width: Width of the clip rectangle
10485 * @height: Height of the clip rectangle
10487 * Sets clip area for @self. The clip area is always computed from the
10488 * upper left corner of the actor, even if the anchor point is set
10494 clutter_actor_set_clip (ClutterActor *self,
10500 ClutterActorPrivate *priv;
10502 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10506 if (priv->has_clip &&
10507 priv->clip.x == xoff &&
10508 priv->clip.y == yoff &&
10509 priv->clip.width == width &&
10510 priv->clip.height == height)
10513 priv->clip.x = xoff;
10514 priv->clip.y = yoff;
10515 priv->clip.width = width;
10516 priv->clip.height = height;
10518 priv->has_clip = TRUE;
10520 clutter_actor_queue_redraw (self);
10522 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10523 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10527 * clutter_actor_remove_clip:
10528 * @self: A #ClutterActor
10530 * Removes clip area from @self.
10533 clutter_actor_remove_clip (ClutterActor *self)
10535 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10537 if (!self->priv->has_clip)
10540 self->priv->has_clip = FALSE;
10542 clutter_actor_queue_redraw (self);
10544 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10548 * clutter_actor_has_clip:
10549 * @self: a #ClutterActor
10551 * Determines whether the actor has a clip area set or not.
10553 * Return value: %TRUE if the actor has a clip area set.
10558 clutter_actor_has_clip (ClutterActor *self)
10560 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10562 return self->priv->has_clip;
10566 * clutter_actor_get_clip:
10567 * @self: a #ClutterActor
10568 * @xoff: (out) (allow-none): return location for the X offset of
10569 * the clip rectangle, or %NULL
10570 * @yoff: (out) (allow-none): return location for the Y offset of
10571 * the clip rectangle, or %NULL
10572 * @width: (out) (allow-none): return location for the width of
10573 * the clip rectangle, or %NULL
10574 * @height: (out) (allow-none): return location for the height of
10575 * the clip rectangle, or %NULL
10577 * Gets the clip area for @self, if any is set
10582 clutter_actor_get_clip (ClutterActor *self,
10588 ClutterActorPrivate *priv;
10590 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10594 if (!priv->has_clip)
10598 *xoff = priv->clip.x;
10601 *yoff = priv->clip.y;
10604 *width = priv->clip.width;
10606 if (height != NULL)
10607 *height = priv->clip.height;
10611 * clutter_actor_get_children:
10612 * @self: a #ClutterActor
10614 * Retrieves the list of children of @self.
10616 * Return value: (transfer container) (element-type ClutterActor): A newly
10617 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10623 clutter_actor_get_children (ClutterActor *self)
10625 ClutterActor *iter;
10628 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10630 /* we walk the list backward so that we can use prepend(),
10633 for (iter = self->priv->last_child, res = NULL;
10635 iter = iter->priv->prev_sibling)
10637 res = g_list_prepend (res, iter);
10644 * insert_child_at_depth:
10645 * @self: a #ClutterActor
10646 * @child: a #ClutterActor
10648 * Inserts @child inside the list of children held by @self, using
10649 * the depth as the insertion criteria.
10651 * This sadly makes the insertion not O(1), but we can keep the
10652 * list sorted so that the painters algorithm we use for painting
10653 * the children will work correctly.
10656 insert_child_at_depth (ClutterActor *self,
10657 ClutterActor *child,
10658 gpointer dummy G_GNUC_UNUSED)
10660 ClutterActor *iter;
10663 child->priv->parent = self;
10666 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10668 /* special-case the first child */
10669 if (self->priv->n_children == 0)
10671 self->priv->first_child = child;
10672 self->priv->last_child = child;
10674 child->priv->next_sibling = NULL;
10675 child->priv->prev_sibling = NULL;
10680 /* Find the right place to insert the child so that it will still be
10681 sorted and the child will be after all of the actors at the same
10683 for (iter = self->priv->first_child;
10685 iter = iter->priv->next_sibling)
10690 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10692 if (iter_depth > child_depth)
10698 ClutterActor *tmp = iter->priv->prev_sibling;
10701 tmp->priv->next_sibling = child;
10703 /* Insert the node before the found one */
10704 child->priv->prev_sibling = iter->priv->prev_sibling;
10705 child->priv->next_sibling = iter;
10706 iter->priv->prev_sibling = child;
10710 ClutterActor *tmp = self->priv->last_child;
10713 tmp->priv->next_sibling = child;
10715 /* insert the node at the end of the list */
10716 child->priv->prev_sibling = self->priv->last_child;
10717 child->priv->next_sibling = NULL;
10720 if (child->priv->prev_sibling == NULL)
10721 self->priv->first_child = child;
10723 if (child->priv->next_sibling == NULL)
10724 self->priv->last_child = child;
10728 insert_child_at_index (ClutterActor *self,
10729 ClutterActor *child,
10732 gint index_ = GPOINTER_TO_INT (data_);
10734 child->priv->parent = self;
10738 ClutterActor *tmp = self->priv->first_child;
10741 tmp->priv->prev_sibling = child;
10743 child->priv->prev_sibling = NULL;
10744 child->priv->next_sibling = tmp;
10746 else if (index_ < 0 || index_ >= self->priv->n_children)
10748 ClutterActor *tmp = self->priv->last_child;
10751 tmp->priv->next_sibling = child;
10753 child->priv->prev_sibling = tmp;
10754 child->priv->next_sibling = NULL;
10758 ClutterActor *iter;
10761 for (iter = self->priv->first_child, i = 0;
10763 iter = iter->priv->next_sibling, i += 1)
10767 ClutterActor *tmp = iter->priv->prev_sibling;
10769 child->priv->prev_sibling = tmp;
10770 child->priv->next_sibling = iter;
10772 iter->priv->prev_sibling = child;
10775 tmp->priv->next_sibling = child;
10782 if (child->priv->prev_sibling == NULL)
10783 self->priv->first_child = child;
10785 if (child->priv->next_sibling == NULL)
10786 self->priv->last_child = child;
10790 insert_child_above (ClutterActor *self,
10791 ClutterActor *child,
10794 ClutterActor *sibling = data;
10796 child->priv->parent = self;
10798 if (sibling == NULL)
10799 sibling = self->priv->last_child;
10801 child->priv->prev_sibling = sibling;
10803 if (sibling != NULL)
10805 ClutterActor *tmp = sibling->priv->next_sibling;
10807 child->priv->next_sibling = tmp;
10810 tmp->priv->prev_sibling = child;
10812 sibling->priv->next_sibling = child;
10815 child->priv->next_sibling = NULL;
10817 if (child->priv->prev_sibling == NULL)
10818 self->priv->first_child = child;
10820 if (child->priv->next_sibling == NULL)
10821 self->priv->last_child = child;
10825 insert_child_below (ClutterActor *self,
10826 ClutterActor *child,
10829 ClutterActor *sibling = data;
10831 child->priv->parent = self;
10833 if (sibling == NULL)
10834 sibling = self->priv->first_child;
10836 child->priv->next_sibling = sibling;
10838 if (sibling != NULL)
10840 ClutterActor *tmp = sibling->priv->prev_sibling;
10842 child->priv->prev_sibling = tmp;
10845 tmp->priv->next_sibling = child;
10847 sibling->priv->prev_sibling = child;
10850 child->priv->prev_sibling = NULL;
10852 if (child->priv->prev_sibling == NULL)
10853 self->priv->first_child = child;
10855 if (child->priv->next_sibling == NULL)
10856 self->priv->last_child = child;
10859 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10860 ClutterActor *child,
10864 ADD_CHILD_CREATE_META = 1 << 0,
10865 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10866 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10867 ADD_CHILD_CHECK_STATE = 1 << 3,
10868 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10870 /* default flags for public API */
10871 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10872 ADD_CHILD_EMIT_PARENT_SET |
10873 ADD_CHILD_EMIT_ACTOR_ADDED |
10874 ADD_CHILD_CHECK_STATE |
10875 ADD_CHILD_NOTIFY_FIRST_LAST,
10877 /* flags for legacy/deprecated API */
10878 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10879 ADD_CHILD_CHECK_STATE |
10880 ADD_CHILD_NOTIFY_FIRST_LAST
10881 } ClutterActorAddChildFlags;
10884 * clutter_actor_add_child_internal:
10885 * @self: a #ClutterActor
10886 * @child: a #ClutterActor
10887 * @flags: control flags for actions
10888 * @add_func: delegate function
10889 * @data: (closure): data to pass to @add_func
10891 * Adds @child to the list of children of @self.
10893 * The actual insertion inside the list is delegated to @add_func: this
10894 * function will just set up the state, perform basic checks, and emit
10897 * The @flags argument is used to perform additional operations.
10900 clutter_actor_add_child_internal (ClutterActor *self,
10901 ClutterActor *child,
10902 ClutterActorAddChildFlags flags,
10903 ClutterActorAddChildFunc add_func,
10906 ClutterTextDirection text_dir;
10907 gboolean create_meta;
10908 gboolean emit_parent_set, emit_actor_added;
10909 gboolean check_state;
10910 gboolean notify_first_last;
10911 ClutterActor *old_first_child, *old_last_child;
10913 if (child->priv->parent != NULL)
10915 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10916 "use clutter_actor_remove_child() first.",
10917 _clutter_actor_get_debug_name (child),
10918 _clutter_actor_get_debug_name (child->priv->parent));
10922 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10924 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10925 "a child of another actor.",
10926 _clutter_actor_get_debug_name (child));
10931 /* XXX - this check disallows calling methods that change the stacking
10932 * order within the destruction sequence, by triggering a critical
10933 * warning first, and leaving the actor in an undefined state, which
10934 * then ends up being caught by an assertion.
10936 * the reproducible sequence is:
10938 * - actor gets destroyed;
10939 * - another actor, linked to the first, will try to change the
10940 * stacking order of the first actor;
10941 * - changing the stacking order is a composite operation composed
10942 * by the following steps:
10943 * 1. ref() the child;
10944 * 2. remove_child_internal(), which removes the reference;
10945 * 3. add_child_internal(), which adds a reference;
10946 * - the state of the actor is not changed between (2) and (3), as
10947 * it could be an expensive recomputation;
10948 * - if (3) bails out, then the actor is in an undefined state, but
10950 * - the destruction sequence terminates, but the actor is unparented
10951 * while its state indicates being parented instead.
10952 * - assertion failure.
10954 * the obvious fix would be to decompose each set_child_*_sibling()
10955 * method into proper remove_child()/add_child(), with state validation;
10956 * this may cause excessive work, though, and trigger a cascade of other
10957 * bugs in code that assumes that a change in the stacking order is an
10958 * atomic operation.
10960 * another potential fix is to just remove this check here, and let
10961 * code doing stacking order changes inside the destruction sequence
10962 * of an actor continue doing the work.
10964 * the third fix is to silently bail out early from every
10965 * set_child_*_sibling() and set_child_at_index() method, and avoid
10968 * I have a preference for the second solution, since it involves the
10969 * least amount of work, and the least amount of code duplication.
10971 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10973 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10975 g_warning ("The actor '%s' is currently being destroyed, and "
10976 "cannot be added as a child of another actor.",
10977 _clutter_actor_get_debug_name (child));
10982 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10983 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10984 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10985 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10986 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10988 old_first_child = self->priv->first_child;
10989 old_last_child = self->priv->last_child;
10991 g_object_freeze_notify (G_OBJECT (self));
10994 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10996 g_object_ref_sink (child);
10997 child->priv->parent = NULL;
10998 child->priv->next_sibling = NULL;
10999 child->priv->prev_sibling = NULL;
11001 /* delegate the actual insertion */
11002 add_func (self, child, data);
11004 g_assert (child->priv->parent == self);
11006 self->priv->n_children += 1;
11008 self->priv->age += 1;
11010 /* if push_internal() has been called then we automatically set
11011 * the flag on the actor
11013 if (self->priv->internal_child)
11014 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11016 /* clutter_actor_reparent() will emit ::parent-set for us */
11017 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11018 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11022 /* If parent is mapped or realized, we need to also be mapped or
11023 * realized once we're inside the parent.
11025 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11027 /* propagate the parent's text direction to the child */
11028 text_dir = clutter_actor_get_text_direction (self);
11029 clutter_actor_set_text_direction (child, text_dir);
11032 if (child->priv->show_on_set_parent)
11033 clutter_actor_show (child);
11035 if (CLUTTER_ACTOR_IS_MAPPED (child))
11036 clutter_actor_queue_redraw (child);
11038 /* maintain the invariant that if an actor needs layout,
11039 * its parents do as well
11041 if (child->priv->needs_width_request ||
11042 child->priv->needs_height_request ||
11043 child->priv->needs_allocation)
11045 /* we work around the short-circuiting we do
11046 * in clutter_actor_queue_relayout() since we
11047 * want to force a relayout
11049 child->priv->needs_width_request = TRUE;
11050 child->priv->needs_height_request = TRUE;
11051 child->priv->needs_allocation = TRUE;
11053 clutter_actor_queue_relayout (child->priv->parent);
11056 if (emit_actor_added)
11057 g_signal_emit_by_name (self, "actor-added", child);
11059 if (notify_first_last)
11061 if (old_first_child != self->priv->first_child)
11062 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11064 if (old_last_child != self->priv->last_child)
11065 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11068 g_object_thaw_notify (G_OBJECT (self));
11072 * clutter_actor_add_child:
11073 * @self: a #ClutterActor
11074 * @child: a #ClutterActor
11076 * Adds @child to the children of @self.
11078 * This function will acquire a reference on @child that will only
11079 * be released when calling clutter_actor_remove_child().
11081 * This function will take into consideration the #ClutterActor:depth
11082 * of @child, and will keep the list of children sorted.
11084 * This function will emit the #ClutterContainer::actor-added signal
11090 clutter_actor_add_child (ClutterActor *self,
11091 ClutterActor *child)
11093 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11094 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11095 g_return_if_fail (self != child);
11096 g_return_if_fail (child->priv->parent == NULL);
11098 clutter_actor_add_child_internal (self, child,
11099 ADD_CHILD_DEFAULT_FLAGS,
11100 insert_child_at_depth,
11105 * clutter_actor_insert_child_at_index:
11106 * @self: a #ClutterActor
11107 * @child: a #ClutterActor
11108 * @index_: the index
11110 * Inserts @child into the list of children of @self, using the
11111 * given @index_. If @index_ is greater than the number of children
11112 * in @self, or is less than 0, then the new child is added at the end.
11114 * This function will acquire a reference on @child that will only
11115 * be released when calling clutter_actor_remove_child().
11117 * This function will not take into consideration the #ClutterActor:depth
11120 * This function will emit the #ClutterContainer::actor-added signal
11126 clutter_actor_insert_child_at_index (ClutterActor *self,
11127 ClutterActor *child,
11130 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11131 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11132 g_return_if_fail (self != child);
11133 g_return_if_fail (child->priv->parent == NULL);
11135 clutter_actor_add_child_internal (self, child,
11136 ADD_CHILD_DEFAULT_FLAGS,
11137 insert_child_at_index,
11138 GINT_TO_POINTER (index_));
11142 * clutter_actor_insert_child_above:
11143 * @self: a #ClutterActor
11144 * @child: a #ClutterActor
11145 * @sibling: (allow-none): a child of @self, or %NULL
11147 * Inserts @child into the list of children of @self, above another
11148 * child of @self or, if @sibling is %NULL, above all the children
11151 * This function will acquire a reference on @child that will only
11152 * be released when calling clutter_actor_remove_child().
11154 * This function will not take into consideration the #ClutterActor:depth
11157 * This function will emit the #ClutterContainer::actor-added signal
11163 clutter_actor_insert_child_above (ClutterActor *self,
11164 ClutterActor *child,
11165 ClutterActor *sibling)
11167 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11168 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11169 g_return_if_fail (self != child);
11170 g_return_if_fail (child != sibling);
11171 g_return_if_fail (child->priv->parent == NULL);
11172 g_return_if_fail (sibling == NULL ||
11173 (CLUTTER_IS_ACTOR (sibling) &&
11174 sibling->priv->parent == self));
11176 clutter_actor_add_child_internal (self, child,
11177 ADD_CHILD_DEFAULT_FLAGS,
11178 insert_child_above,
11183 * clutter_actor_insert_child_below:
11184 * @self: a #ClutterActor
11185 * @child: a #ClutterActor
11186 * @sibling: (allow-none): a child of @self, or %NULL
11188 * Inserts @child into the list of children of @self, below another
11189 * child of @self or, if @sibling is %NULL, below all the children
11192 * This function will acquire a reference on @child that will only
11193 * be released when calling clutter_actor_remove_child().
11195 * This function will not take into consideration the #ClutterActor:depth
11198 * This function will emit the #ClutterContainer::actor-added signal
11204 clutter_actor_insert_child_below (ClutterActor *self,
11205 ClutterActor *child,
11206 ClutterActor *sibling)
11208 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11209 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11210 g_return_if_fail (self != child);
11211 g_return_if_fail (child != sibling);
11212 g_return_if_fail (child->priv->parent == NULL);
11213 g_return_if_fail (sibling == NULL ||
11214 (CLUTTER_IS_ACTOR (sibling) &&
11215 sibling->priv->parent == self));
11217 clutter_actor_add_child_internal (self, child,
11218 ADD_CHILD_DEFAULT_FLAGS,
11219 insert_child_below,
11224 * clutter_actor_set_parent:
11225 * @self: A #ClutterActor
11226 * @parent: A new #ClutterActor parent
11228 * Sets the parent of @self to @parent.
11230 * This function will result in @parent acquiring a reference on @self,
11231 * eventually by sinking its floating reference first. The reference
11232 * will be released by clutter_actor_unparent().
11234 * This function should only be called by legacy #ClutterActor<!-- -->s
11235 * implementing the #ClutterContainer interface.
11237 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11240 clutter_actor_set_parent (ClutterActor *self,
11241 ClutterActor *parent)
11243 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11244 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11245 g_return_if_fail (self != parent);
11246 g_return_if_fail (self->priv->parent == NULL);
11248 /* as this function will be called inside ClutterContainer::add
11249 * implementations or when building up a composite actor, we have
11250 * to preserve the old behaviour, and not create child meta or
11251 * emit the ::actor-added signal, to avoid recursion or double
11254 clutter_actor_add_child_internal (parent, self,
11255 ADD_CHILD_LEGACY_FLAGS,
11256 insert_child_at_depth,
11261 * clutter_actor_get_parent:
11262 * @self: A #ClutterActor
11264 * Retrieves the parent of @self.
11266 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11267 * if no parent is set
11270 clutter_actor_get_parent (ClutterActor *self)
11272 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11274 return self->priv->parent;
11278 * clutter_actor_get_paint_visibility:
11279 * @self: A #ClutterActor
11281 * Retrieves the 'paint' visibility of an actor recursively checking for non
11284 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11286 * Return Value: %TRUE if the actor is visibile and will be painted.
11291 clutter_actor_get_paint_visibility (ClutterActor *actor)
11293 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11295 return CLUTTER_ACTOR_IS_MAPPED (actor);
11299 * clutter_actor_remove_child:
11300 * @self: a #ClutterActor
11301 * @child: a #ClutterActor
11303 * Removes @child from the children of @self.
11305 * This function will release the reference added by
11306 * clutter_actor_add_child(), so if you want to keep using @child
11307 * you will have to acquire a referenced on it before calling this
11310 * This function will emit the #ClutterContainer::actor-removed
11316 clutter_actor_remove_child (ClutterActor *self,
11317 ClutterActor *child)
11319 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11320 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11321 g_return_if_fail (self != child);
11322 g_return_if_fail (child->priv->parent != NULL);
11323 g_return_if_fail (child->priv->parent == self);
11325 clutter_actor_remove_child_internal (self, child,
11326 REMOVE_CHILD_DEFAULT_FLAGS);
11330 * clutter_actor_remove_all_children:
11331 * @self: a #ClutterActor
11333 * Removes all children of @self.
11335 * This function releases the reference added by inserting a child actor
11336 * in the list of children of @self.
11338 * If the reference count of a child drops to zero, the child will be
11339 * destroyed. If you want to ensure the destruction of all the children
11340 * of @self, use clutter_actor_destroy_all_children().
11345 clutter_actor_remove_all_children (ClutterActor *self)
11347 ClutterActorIter iter;
11349 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11351 if (self->priv->n_children == 0)
11354 g_object_freeze_notify (G_OBJECT (self));
11356 clutter_actor_iter_init (&iter, self);
11357 while (clutter_actor_iter_next (&iter, NULL))
11358 clutter_actor_iter_remove (&iter);
11360 g_object_thaw_notify (G_OBJECT (self));
11363 g_assert (self->priv->first_child == NULL);
11364 g_assert (self->priv->last_child == NULL);
11365 g_assert (self->priv->n_children == 0);
11369 * clutter_actor_destroy_all_children:
11370 * @self: a #ClutterActor
11372 * Destroys all children of @self.
11374 * This function releases the reference added by inserting a child
11375 * actor in the list of children of @self, and ensures that the
11376 * #ClutterActor::destroy signal is emitted on each child of the
11379 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11380 * when its reference count drops to 0; the default handler of the
11381 * #ClutterActor::destroy signal will destroy all the children of an
11382 * actor. This function ensures that all children are destroyed, instead
11383 * of just removed from @self, unlike clutter_actor_remove_all_children()
11384 * which will merely release the reference and remove each child.
11386 * Unless you acquired an additional reference on each child of @self
11387 * prior to calling clutter_actor_remove_all_children() and want to reuse
11388 * the actors, you should use clutter_actor_destroy_all_children() in
11389 * order to make sure that children are destroyed and signal handlers
11390 * are disconnected even in cases where circular references prevent this
11391 * from automatically happening through reference counting alone.
11396 clutter_actor_destroy_all_children (ClutterActor *self)
11398 ClutterActorIter iter;
11400 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11402 if (self->priv->n_children == 0)
11405 g_object_freeze_notify (G_OBJECT (self));
11407 clutter_actor_iter_init (&iter, self);
11408 while (clutter_actor_iter_next (&iter, NULL))
11409 clutter_actor_iter_destroy (&iter);
11411 g_object_thaw_notify (G_OBJECT (self));
11414 g_assert (self->priv->first_child == NULL);
11415 g_assert (self->priv->last_child == NULL);
11416 g_assert (self->priv->n_children == 0);
11419 typedef struct _InsertBetweenData {
11420 ClutterActor *prev_sibling;
11421 ClutterActor *next_sibling;
11422 } InsertBetweenData;
11425 insert_child_between (ClutterActor *self,
11426 ClutterActor *child,
11429 InsertBetweenData *data = data_;
11430 ClutterActor *prev_sibling = data->prev_sibling;
11431 ClutterActor *next_sibling = data->next_sibling;
11433 child->priv->parent = self;
11434 child->priv->prev_sibling = prev_sibling;
11435 child->priv->next_sibling = next_sibling;
11437 if (prev_sibling != NULL)
11438 prev_sibling->priv->next_sibling = child;
11440 if (next_sibling != NULL)
11441 next_sibling->priv->prev_sibling = child;
11443 if (child->priv->prev_sibling == NULL)
11444 self->priv->first_child = child;
11446 if (child->priv->next_sibling == NULL)
11447 self->priv->last_child = child;
11451 * clutter_actor_replace_child:
11452 * @self: a #ClutterActor
11453 * @old_child: the child of @self to replace
11454 * @new_child: the #ClutterActor to replace @old_child
11456 * Replaces @old_child with @new_child in the list of children of @self.
11461 clutter_actor_replace_child (ClutterActor *self,
11462 ClutterActor *old_child,
11463 ClutterActor *new_child)
11465 ClutterActor *prev_sibling, *next_sibling;
11466 InsertBetweenData clos;
11468 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11469 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11470 g_return_if_fail (old_child->priv->parent == self);
11471 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11472 g_return_if_fail (old_child != new_child);
11473 g_return_if_fail (new_child != self);
11474 g_return_if_fail (new_child->priv->parent == NULL);
11476 prev_sibling = old_child->priv->prev_sibling;
11477 next_sibling = old_child->priv->next_sibling;
11478 clutter_actor_remove_child_internal (self, old_child,
11479 REMOVE_CHILD_DEFAULT_FLAGS);
11481 clos.prev_sibling = prev_sibling;
11482 clos.next_sibling = next_sibling;
11483 clutter_actor_add_child_internal (self, new_child,
11484 ADD_CHILD_DEFAULT_FLAGS,
11485 insert_child_between,
11490 * clutter_actor_unparent:
11491 * @self: a #ClutterActor
11493 * Removes the parent of @self.
11495 * This will cause the parent of @self to release the reference
11496 * acquired when calling clutter_actor_set_parent(), so if you
11497 * want to keep @self you will have to acquire a reference of
11498 * your own, through g_object_ref().
11500 * This function should only be called by legacy #ClutterActor<!-- -->s
11501 * implementing the #ClutterContainer interface.
11505 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11508 clutter_actor_unparent (ClutterActor *self)
11510 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11512 if (self->priv->parent == NULL)
11515 clutter_actor_remove_child_internal (self->priv->parent, self,
11516 REMOVE_CHILD_LEGACY_FLAGS);
11520 * clutter_actor_reparent:
11521 * @self: a #ClutterActor
11522 * @new_parent: the new #ClutterActor parent
11524 * Resets the parent actor of @self.
11526 * This function is logically equivalent to calling clutter_actor_unparent()
11527 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11528 * ensures the child is not finalized when unparented, and emits the
11529 * #ClutterActor::parent-set signal only once.
11531 * In reality, calling this function is less useful than it sounds, as some
11532 * application code may rely on changes in the intermediate state between
11533 * removal and addition of the actor from its old parent to the @new_parent.
11534 * Thus, it is strongly encouraged to avoid using this function in application
11539 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11540 * clutter_actor_add_child() instead; remember to take a reference on
11541 * the actor being removed before calling clutter_actor_remove_child()
11542 * to avoid the reference count dropping to zero and the actor being
11546 clutter_actor_reparent (ClutterActor *self,
11547 ClutterActor *new_parent)
11549 ClutterActorPrivate *priv;
11551 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11552 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11553 g_return_if_fail (self != new_parent);
11555 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11557 g_warning ("Cannot set a parent on a toplevel actor");
11561 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11563 g_warning ("Cannot set a parent currently being destroyed");
11569 if (priv->parent != new_parent)
11571 ClutterActor *old_parent;
11573 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11575 old_parent = priv->parent;
11577 g_object_ref (self);
11579 if (old_parent != NULL)
11581 /* go through the Container implementation if this is a regular
11582 * child and not an internal one
11584 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11586 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11588 /* this will have to call unparent() */
11589 clutter_container_remove_actor (parent, self);
11592 clutter_actor_remove_child_internal (old_parent, self,
11593 REMOVE_CHILD_LEGACY_FLAGS);
11596 /* Note, will call set_parent() */
11597 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11598 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11600 clutter_actor_add_child_internal (new_parent, self,
11601 ADD_CHILD_LEGACY_FLAGS,
11602 insert_child_at_depth,
11605 /* we emit the ::parent-set signal once */
11606 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11608 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11610 /* the IN_REPARENT flag suspends state updates */
11611 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11613 g_object_unref (self);
11618 * clutter_actor_contains:
11619 * @self: A #ClutterActor
11620 * @descendant: A #ClutterActor, possibly contained in @self
11622 * Determines if @descendant is contained inside @self (either as an
11623 * immediate child, or as a deeper descendant). If @self and
11624 * @descendant point to the same actor then it will also return %TRUE.
11626 * Return value: whether @descendent is contained within @self
11631 clutter_actor_contains (ClutterActor *self,
11632 ClutterActor *descendant)
11634 ClutterActor *actor;
11636 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11637 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11639 for (actor = descendant; actor; actor = actor->priv->parent)
11647 * clutter_actor_set_child_above_sibling:
11648 * @self: a #ClutterActor
11649 * @child: a #ClutterActor child of @self
11650 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11652 * Sets @child to be above @sibling in the list of children of @self.
11654 * If @sibling is %NULL, @child will be the new last child of @self.
11656 * This function is logically equivalent to removing @child and using
11657 * clutter_actor_insert_child_above(), but it will not emit signals
11658 * or change state on @child.
11663 clutter_actor_set_child_above_sibling (ClutterActor *self,
11664 ClutterActor *child,
11665 ClutterActor *sibling)
11667 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11668 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11669 g_return_if_fail (child->priv->parent == self);
11670 g_return_if_fail (child != sibling);
11671 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11673 if (sibling != NULL)
11674 g_return_if_fail (sibling->priv->parent == self);
11676 /* we don't want to change the state of child, or emit signals, or
11677 * regenerate ChildMeta instances here, but we still want to follow
11678 * the correct sequence of steps encoded in remove_child() and
11679 * add_child(), so that correctness is ensured, and we only go
11680 * through one known code path.
11682 g_object_ref (child);
11683 clutter_actor_remove_child_internal (self, child, 0);
11684 clutter_actor_add_child_internal (self, child,
11685 ADD_CHILD_NOTIFY_FIRST_LAST,
11686 insert_child_above,
11689 clutter_actor_queue_relayout (self);
11693 * clutter_actor_set_child_below_sibling:
11694 * @self: a #ClutterActor
11695 * @child: a #ClutterActor child of @self
11696 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11698 * Sets @child to be below @sibling in the list of children of @self.
11700 * If @sibling is %NULL, @child will be the new first child of @self.
11702 * This function is logically equivalent to removing @self and using
11703 * clutter_actor_insert_child_below(), but it will not emit signals
11704 * or change state on @child.
11709 clutter_actor_set_child_below_sibling (ClutterActor *self,
11710 ClutterActor *child,
11711 ClutterActor *sibling)
11713 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11714 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11715 g_return_if_fail (child->priv->parent == self);
11716 g_return_if_fail (child != sibling);
11717 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11719 if (sibling != NULL)
11720 g_return_if_fail (sibling->priv->parent == self);
11722 /* see the comment in set_child_above_sibling() */
11723 g_object_ref (child);
11724 clutter_actor_remove_child_internal (self, child, 0);
11725 clutter_actor_add_child_internal (self, child,
11726 ADD_CHILD_NOTIFY_FIRST_LAST,
11727 insert_child_below,
11730 clutter_actor_queue_relayout (self);
11734 * clutter_actor_set_child_at_index:
11735 * @self: a #ClutterActor
11736 * @child: a #ClutterActor child of @self
11737 * @index_: the new index for @child
11739 * Changes the index of @child in the list of children of @self.
11741 * This function is logically equivalent to removing @child and
11742 * calling clutter_actor_insert_child_at_index(), but it will not
11743 * emit signals or change state on @child.
11748 clutter_actor_set_child_at_index (ClutterActor *self,
11749 ClutterActor *child,
11752 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11753 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11754 g_return_if_fail (child->priv->parent == self);
11755 g_return_if_fail (index_ <= self->priv->n_children);
11757 g_object_ref (child);
11758 clutter_actor_remove_child_internal (self, child, 0);
11759 clutter_actor_add_child_internal (self, child,
11760 ADD_CHILD_NOTIFY_FIRST_LAST,
11761 insert_child_at_index,
11762 GINT_TO_POINTER (index_));
11764 clutter_actor_queue_relayout (self);
11768 * clutter_actor_raise:
11769 * @self: A #ClutterActor
11770 * @below: (allow-none): A #ClutterActor to raise above.
11772 * Puts @self above @below.
11774 * Both actors must have the same parent, and the parent must implement
11775 * the #ClutterContainer interface
11777 * This function calls clutter_container_raise_child() internally.
11779 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11782 clutter_actor_raise (ClutterActor *self,
11783 ClutterActor *below)
11785 ClutterActor *parent;
11787 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11789 parent = clutter_actor_get_parent (self);
11790 if (parent == NULL)
11792 g_warning ("%s: Actor '%s' is not inside a container",
11794 _clutter_actor_get_debug_name (self));
11800 if (parent != clutter_actor_get_parent (below))
11802 g_warning ("%s Actor '%s' is not in the same container as "
11805 _clutter_actor_get_debug_name (self),
11806 _clutter_actor_get_debug_name (below));
11811 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11815 * clutter_actor_lower:
11816 * @self: A #ClutterActor
11817 * @above: (allow-none): A #ClutterActor to lower below
11819 * Puts @self below @above.
11821 * Both actors must have the same parent, and the parent must implement
11822 * the #ClutterContainer interface.
11824 * This function calls clutter_container_lower_child() internally.
11826 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11829 clutter_actor_lower (ClutterActor *self,
11830 ClutterActor *above)
11832 ClutterActor *parent;
11834 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11836 parent = clutter_actor_get_parent (self);
11837 if (parent == NULL)
11839 g_warning ("%s: Actor of type %s is not inside a container",
11841 _clutter_actor_get_debug_name (self));
11847 if (parent != clutter_actor_get_parent (above))
11849 g_warning ("%s: Actor '%s' is not in the same container as "
11852 _clutter_actor_get_debug_name (self),
11853 _clutter_actor_get_debug_name (above));
11858 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11862 * clutter_actor_raise_top:
11863 * @self: A #ClutterActor
11865 * Raises @self to the top.
11867 * This function calls clutter_actor_raise() internally.
11869 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11870 * a %NULL sibling, instead.
11873 clutter_actor_raise_top (ClutterActor *self)
11875 clutter_actor_raise (self, NULL);
11879 * clutter_actor_lower_bottom:
11880 * @self: A #ClutterActor
11882 * Lowers @self to the bottom.
11884 * This function calls clutter_actor_lower() internally.
11886 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11887 * a %NULL sibling, instead.
11890 clutter_actor_lower_bottom (ClutterActor *self)
11892 clutter_actor_lower (self, NULL);
11900 * clutter_actor_event:
11901 * @actor: a #ClutterActor
11902 * @event: a #ClutterEvent
11903 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11905 * This function is used to emit an event on the main stage.
11906 * You should rarely need to use this function, except for
11907 * synthetising events.
11909 * Return value: the return value from the signal emission: %TRUE
11910 * if the actor handled the event, or %FALSE if the event was
11916 clutter_actor_event (ClutterActor *actor,
11917 ClutterEvent *event,
11920 gboolean retval = FALSE;
11921 gint signal_num = -1;
11923 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11924 g_return_val_if_fail (event != NULL, FALSE);
11926 g_object_ref (actor);
11930 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11936 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11940 switch (event->type)
11942 case CLUTTER_NOTHING:
11944 case CLUTTER_BUTTON_PRESS:
11945 signal_num = BUTTON_PRESS_EVENT;
11947 case CLUTTER_BUTTON_RELEASE:
11948 signal_num = BUTTON_RELEASE_EVENT;
11950 case CLUTTER_SCROLL:
11951 signal_num = SCROLL_EVENT;
11953 case CLUTTER_KEY_PRESS:
11954 signal_num = KEY_PRESS_EVENT;
11956 case CLUTTER_KEY_RELEASE:
11957 signal_num = KEY_RELEASE_EVENT;
11959 case CLUTTER_MOTION:
11960 signal_num = MOTION_EVENT;
11962 case CLUTTER_ENTER:
11963 signal_num = ENTER_EVENT;
11965 case CLUTTER_LEAVE:
11966 signal_num = LEAVE_EVENT;
11968 case CLUTTER_DELETE:
11969 case CLUTTER_DESTROY_NOTIFY:
11970 case CLUTTER_CLIENT_MESSAGE:
11976 if (signal_num != -1)
11977 g_signal_emit (actor, actor_signals[signal_num], 0,
11982 g_object_unref (actor);
11988 * clutter_actor_set_reactive:
11989 * @actor: a #ClutterActor
11990 * @reactive: whether the actor should be reactive to events
11992 * Sets @actor as reactive. Reactive actors will receive events.
11997 clutter_actor_set_reactive (ClutterActor *actor,
12000 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12002 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12006 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12008 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12010 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12014 * clutter_actor_get_reactive:
12015 * @actor: a #ClutterActor
12017 * Checks whether @actor is marked as reactive.
12019 * Return value: %TRUE if the actor is reactive
12024 clutter_actor_get_reactive (ClutterActor *actor)
12026 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12028 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12032 * clutter_actor_get_anchor_point:
12033 * @self: a #ClutterActor
12034 * @anchor_x: (out): return location for the X coordinate of the anchor point
12035 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12037 * Gets the current anchor point of the @actor in pixels.
12042 clutter_actor_get_anchor_point (ClutterActor *self,
12046 const ClutterTransformInfo *info;
12048 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12050 info = _clutter_actor_get_transform_info_or_defaults (self);
12051 clutter_anchor_coord_get_units (self, &info->anchor,
12058 * clutter_actor_set_anchor_point:
12059 * @self: a #ClutterActor
12060 * @anchor_x: X coordinate of the anchor point
12061 * @anchor_y: Y coordinate of the anchor point
12063 * Sets an anchor point for @self. The anchor point is a point in the
12064 * coordinate space of an actor to which the actor position within its
12065 * parent is relative; the default is (0, 0), i.e. the top-left corner
12071 clutter_actor_set_anchor_point (ClutterActor *self,
12075 ClutterTransformInfo *info;
12076 ClutterActorPrivate *priv;
12077 gboolean changed = FALSE;
12078 gfloat old_anchor_x, old_anchor_y;
12081 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12083 obj = G_OBJECT (self);
12085 info = _clutter_actor_get_transform_info (self);
12087 g_object_freeze_notify (obj);
12089 clutter_anchor_coord_get_units (self, &info->anchor,
12094 if (info->anchor.is_fractional)
12095 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12097 if (old_anchor_x != anchor_x)
12099 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12103 if (old_anchor_y != anchor_y)
12105 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12109 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12113 priv->transform_valid = FALSE;
12114 clutter_actor_queue_redraw (self);
12117 g_object_thaw_notify (obj);
12121 * clutter_actor_get_anchor_point_gravity:
12122 * @self: a #ClutterActor
12124 * Retrieves the anchor position expressed as a #ClutterGravity. If
12125 * the anchor point was specified using pixels or units this will
12126 * return %CLUTTER_GRAVITY_NONE.
12128 * Return value: the #ClutterGravity used by the anchor point
12133 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12135 const ClutterTransformInfo *info;
12137 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12139 info = _clutter_actor_get_transform_info_or_defaults (self);
12141 return clutter_anchor_coord_get_gravity (&info->anchor);
12145 * clutter_actor_move_anchor_point:
12146 * @self: a #ClutterActor
12147 * @anchor_x: X coordinate of the anchor point
12148 * @anchor_y: Y coordinate of the anchor point
12150 * Sets an anchor point for the actor, and adjusts the actor postion so that
12151 * the relative position of the actor toward its parent remains the same.
12156 clutter_actor_move_anchor_point (ClutterActor *self,
12160 gfloat old_anchor_x, old_anchor_y;
12161 const ClutterTransformInfo *info;
12163 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12165 info = _clutter_actor_get_transform_info (self);
12166 clutter_anchor_coord_get_units (self, &info->anchor,
12171 g_object_freeze_notify (G_OBJECT (self));
12173 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12175 if (self->priv->position_set)
12176 clutter_actor_move_by (self,
12177 anchor_x - old_anchor_x,
12178 anchor_y - old_anchor_y);
12180 g_object_thaw_notify (G_OBJECT (self));
12184 * clutter_actor_move_anchor_point_from_gravity:
12185 * @self: a #ClutterActor
12186 * @gravity: #ClutterGravity.
12188 * Sets an anchor point on the actor based on the given gravity, adjusting the
12189 * actor postion so that its relative position within its parent remains
12192 * Since version 1.0 the anchor point will be stored as a gravity so
12193 * that if the actor changes size then the anchor point will move. For
12194 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12195 * and later double the size of the actor, the anchor point will move
12196 * to the bottom right.
12201 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12202 ClutterGravity gravity)
12204 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12205 const ClutterTransformInfo *info;
12206 ClutterActorPrivate *priv;
12208 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12211 info = _clutter_actor_get_transform_info (self);
12213 g_object_freeze_notify (G_OBJECT (self));
12215 clutter_anchor_coord_get_units (self, &info->anchor,
12219 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12220 clutter_anchor_coord_get_units (self, &info->anchor,
12225 if (priv->position_set)
12226 clutter_actor_move_by (self,
12227 new_anchor_x - old_anchor_x,
12228 new_anchor_y - old_anchor_y);
12230 g_object_thaw_notify (G_OBJECT (self));
12234 * clutter_actor_set_anchor_point_from_gravity:
12235 * @self: a #ClutterActor
12236 * @gravity: #ClutterGravity.
12238 * Sets an anchor point on the actor, based on the given gravity (this is a
12239 * convenience function wrapping clutter_actor_set_anchor_point()).
12241 * Since version 1.0 the anchor point will be stored as a gravity so
12242 * that if the actor changes size then the anchor point will move. For
12243 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12244 * and later double the size of the actor, the anchor point will move
12245 * to the bottom right.
12250 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12251 ClutterGravity gravity)
12253 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12255 if (gravity == CLUTTER_GRAVITY_NONE)
12256 clutter_actor_set_anchor_point (self, 0, 0);
12259 GObject *obj = G_OBJECT (self);
12260 ClutterTransformInfo *info;
12262 g_object_freeze_notify (obj);
12264 info = _clutter_actor_get_transform_info (self);
12265 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12267 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12268 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12269 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12271 self->priv->transform_valid = FALSE;
12273 clutter_actor_queue_redraw (self);
12275 g_object_thaw_notify (obj);
12280 clutter_container_iface_init (ClutterContainerIface *iface)
12282 /* we don't override anything, as ClutterContainer already has a default
12283 * implementation that we can use, and which calls into our own API.
12298 parse_units (ClutterActor *self,
12299 ParseDimension dimension,
12302 GValue value = G_VALUE_INIT;
12305 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12308 json_node_get_value (node, &value);
12310 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12312 retval = (gfloat) g_value_get_int64 (&value);
12314 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12316 retval = g_value_get_double (&value);
12318 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12320 ClutterUnits units;
12323 res = clutter_units_from_string (&units, g_value_get_string (&value));
12325 retval = clutter_units_to_pixels (&units);
12328 g_warning ("Invalid value '%s': integers, strings or floating point "
12329 "values can be used for the x, y, width and height "
12330 "properties. Valid modifiers for strings are 'px', 'mm', "
12332 g_value_get_string (&value));
12338 g_warning ("Invalid value of type '%s': integers, strings of floating "
12339 "point values can be used for the x, y, width, height "
12340 "anchor-x and anchor-y properties.",
12341 g_type_name (G_VALUE_TYPE (&value)));
12344 g_value_unset (&value);
12350 ClutterRotateAxis axis;
12359 static inline gboolean
12360 parse_rotation_array (ClutterActor *actor,
12362 RotationInfo *info)
12366 if (json_array_get_length (array) != 2)
12370 element = json_array_get_element (array, 0);
12371 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12372 info->angle = json_node_get_double (element);
12377 element = json_array_get_element (array, 1);
12378 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12380 JsonArray *center = json_node_get_array (element);
12382 if (json_array_get_length (center) != 2)
12385 switch (info->axis)
12387 case CLUTTER_X_AXIS:
12388 info->center_y = parse_units (actor, PARSE_Y,
12389 json_array_get_element (center, 0));
12390 info->center_z = parse_units (actor, PARSE_Y,
12391 json_array_get_element (center, 1));
12394 case CLUTTER_Y_AXIS:
12395 info->center_x = parse_units (actor, PARSE_X,
12396 json_array_get_element (center, 0));
12397 info->center_z = parse_units (actor, PARSE_X,
12398 json_array_get_element (center, 1));
12401 case CLUTTER_Z_AXIS:
12402 info->center_x = parse_units (actor, PARSE_X,
12403 json_array_get_element (center, 0));
12404 info->center_y = parse_units (actor, PARSE_Y,
12405 json_array_get_element (center, 1));
12414 parse_rotation (ClutterActor *actor,
12416 RotationInfo *info)
12420 gboolean retval = FALSE;
12422 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12424 g_warning ("Invalid node of type '%s' found, expecting an array",
12425 json_node_type_name (node));
12429 array = json_node_get_array (node);
12430 len = json_array_get_length (array);
12432 for (i = 0; i < len; i++)
12434 JsonNode *element = json_array_get_element (array, i);
12435 JsonObject *object;
12438 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12440 g_warning ("Invalid node of type '%s' found, expecting an object",
12441 json_node_type_name (element));
12445 object = json_node_get_object (element);
12447 if (json_object_has_member (object, "x-axis"))
12449 member = json_object_get_member (object, "x-axis");
12451 info->axis = CLUTTER_X_AXIS;
12453 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12455 info->angle = json_node_get_double (member);
12458 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12459 retval = parse_rotation_array (actor,
12460 json_node_get_array (member),
12465 else if (json_object_has_member (object, "y-axis"))
12467 member = json_object_get_member (object, "y-axis");
12469 info->axis = CLUTTER_Y_AXIS;
12471 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12473 info->angle = json_node_get_double (member);
12476 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12477 retval = parse_rotation_array (actor,
12478 json_node_get_array (member),
12483 else if (json_object_has_member (object, "z-axis"))
12485 member = json_object_get_member (object, "z-axis");
12487 info->axis = CLUTTER_Z_AXIS;
12489 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12491 info->angle = json_node_get_double (member);
12494 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12495 retval = parse_rotation_array (actor,
12496 json_node_get_array (member),
12507 parse_actor_metas (ClutterScript *script,
12508 ClutterActor *actor,
12511 GList *elements, *l;
12512 GSList *retval = NULL;
12514 if (!JSON_NODE_HOLDS_ARRAY (node))
12517 elements = json_array_get_elements (json_node_get_array (node));
12519 for (l = elements; l != NULL; l = l->next)
12521 JsonNode *element = l->data;
12522 const gchar *id_ = _clutter_script_get_id_from_node (element);
12525 if (id_ == NULL || *id_ == '\0')
12528 meta = clutter_script_get_object (script, id_);
12532 retval = g_slist_prepend (retval, meta);
12535 g_list_free (elements);
12537 return g_slist_reverse (retval);
12541 parse_behaviours (ClutterScript *script,
12542 ClutterActor *actor,
12545 GList *elements, *l;
12546 GSList *retval = NULL;
12548 if (!JSON_NODE_HOLDS_ARRAY (node))
12551 elements = json_array_get_elements (json_node_get_array (node));
12553 for (l = elements; l != NULL; l = l->next)
12555 JsonNode *element = l->data;
12556 const gchar *id_ = _clutter_script_get_id_from_node (element);
12557 GObject *behaviour;
12559 if (id_ == NULL || *id_ == '\0')
12562 behaviour = clutter_script_get_object (script, id_);
12563 if (behaviour == NULL)
12566 retval = g_slist_prepend (retval, behaviour);
12569 g_list_free (elements);
12571 return g_slist_reverse (retval);
12575 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12576 ClutterScript *script,
12581 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12582 gboolean retval = FALSE;
12584 if ((name[0] == 'x' && name[1] == '\0') ||
12585 (name[0] == 'y' && name[1] == '\0') ||
12586 (strcmp (name, "width") == 0) ||
12587 (strcmp (name, "height") == 0) ||
12588 (strcmp (name, "anchor_x") == 0) ||
12589 (strcmp (name, "anchor_y") == 0))
12591 ParseDimension dimension;
12594 if (name[0] == 'x')
12595 dimension = PARSE_X;
12596 else if (name[0] == 'y')
12597 dimension = PARSE_Y;
12598 else if (name[0] == 'w')
12599 dimension = PARSE_WIDTH;
12600 else if (name[0] == 'h')
12601 dimension = PARSE_HEIGHT;
12602 else if (name[0] == 'a' && name[7] == 'x')
12603 dimension = PARSE_ANCHOR_X;
12604 else if (name[0] == 'a' && name[7] == 'y')
12605 dimension = PARSE_ANCHOR_Y;
12609 units = parse_units (actor, dimension, node);
12611 /* convert back to pixels: all properties are pixel-based */
12612 g_value_init (value, G_TYPE_FLOAT);
12613 g_value_set_float (value, units);
12617 else if (strcmp (name, "rotation") == 0)
12619 RotationInfo *info;
12621 info = g_slice_new0 (RotationInfo);
12622 retval = parse_rotation (actor, node, info);
12626 g_value_init (value, G_TYPE_POINTER);
12627 g_value_set_pointer (value, info);
12630 g_slice_free (RotationInfo, info);
12632 else if (strcmp (name, "behaviours") == 0)
12636 #ifdef CLUTTER_ENABLE_DEBUG
12637 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12638 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12639 "and it should not be used in newly "
12640 "written ClutterScript definitions.");
12643 l = parse_behaviours (script, actor, node);
12645 g_value_init (value, G_TYPE_POINTER);
12646 g_value_set_pointer (value, l);
12650 else if (strcmp (name, "actions") == 0 ||
12651 strcmp (name, "constraints") == 0 ||
12652 strcmp (name, "effects") == 0)
12656 l = parse_actor_metas (script, actor, node);
12658 g_value_init (value, G_TYPE_POINTER);
12659 g_value_set_pointer (value, l);
12668 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12669 ClutterScript *script,
12671 const GValue *value)
12673 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12675 #ifdef CLUTTER_ENABLE_DEBUG
12676 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12678 gchar *tmp = g_strdup_value_contents (value);
12680 CLUTTER_NOTE (SCRIPT,
12681 "in ClutterActor::set_custom_property('%s') = %s",
12687 #endif /* CLUTTER_ENABLE_DEBUG */
12689 if (strcmp (name, "rotation") == 0)
12691 RotationInfo *info;
12693 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12696 info = g_value_get_pointer (value);
12698 clutter_actor_set_rotation (actor,
12699 info->axis, info->angle,
12704 g_slice_free (RotationInfo, info);
12709 if (strcmp (name, "behaviours") == 0)
12711 GSList *behaviours, *l;
12713 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12716 behaviours = g_value_get_pointer (value);
12717 for (l = behaviours; l != NULL; l = l->next)
12719 ClutterBehaviour *behaviour = l->data;
12721 clutter_behaviour_apply (behaviour, actor);
12724 g_slist_free (behaviours);
12729 if (strcmp (name, "actions") == 0 ||
12730 strcmp (name, "constraints") == 0 ||
12731 strcmp (name, "effects") == 0)
12735 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12738 metas = g_value_get_pointer (value);
12739 for (l = metas; l != NULL; l = l->next)
12741 if (name[0] == 'a')
12742 clutter_actor_add_action (actor, l->data);
12744 if (name[0] == 'c')
12745 clutter_actor_add_constraint (actor, l->data);
12747 if (name[0] == 'e')
12748 clutter_actor_add_effect (actor, l->data);
12751 g_slist_free (metas);
12756 g_object_set_property (G_OBJECT (scriptable), name, value);
12760 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12762 iface->parse_custom_node = clutter_actor_parse_custom_node;
12763 iface->set_custom_property = clutter_actor_set_custom_property;
12766 static ClutterActorMeta *
12767 get_meta_from_animation_property (ClutterActor *actor,
12771 ClutterActorPrivate *priv = actor->priv;
12772 ClutterActorMeta *meta = NULL;
12775 /* if this is not a special property, fall through */
12776 if (name[0] != '@')
12779 /* detect the properties named using the following spec:
12781 * @<section>.<meta-name>.<property-name>
12783 * where <section> can be one of the following:
12789 * and <meta-name> is the name set on a specific ActorMeta
12792 tokens = g_strsplit (name + 1, ".", -1);
12793 if (tokens == NULL || g_strv_length (tokens) != 3)
12795 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12797 g_strfreev (tokens);
12801 if (strcmp (tokens[0], "actions") == 0)
12802 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12804 if (strcmp (tokens[0], "constraints") == 0)
12805 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12807 if (strcmp (tokens[0], "effects") == 0)
12808 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12810 if (name_p != NULL)
12811 *name_p = g_strdup (tokens[2]);
12813 CLUTTER_NOTE (ANIMATION,
12814 "Looking for property '%s' of object '%s' in section '%s'",
12819 g_strfreev (tokens);
12824 static GParamSpec *
12825 clutter_actor_find_property (ClutterAnimatable *animatable,
12826 const gchar *property_name)
12828 ClutterActorMeta *meta = NULL;
12829 GObjectClass *klass = NULL;
12830 GParamSpec *pspec = NULL;
12831 gchar *p_name = NULL;
12833 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12839 klass = G_OBJECT_GET_CLASS (meta);
12841 pspec = g_object_class_find_property (klass, p_name);
12845 klass = G_OBJECT_GET_CLASS (animatable);
12847 pspec = g_object_class_find_property (klass, property_name);
12856 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12857 const gchar *property_name,
12860 ClutterActorMeta *meta = NULL;
12861 gchar *p_name = NULL;
12863 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12868 g_object_get_property (G_OBJECT (meta), p_name, initial);
12870 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12876 * clutter_actor_set_animatable_property:
12877 * @actor: a #ClutterActor
12878 * @prop_id: the paramspec id
12879 * @value: the value to set
12880 * @pspec: the paramspec
12882 * Sets values of animatable properties.
12884 * This is a variant of clutter_actor_set_property() that gets called
12885 * by the #ClutterAnimatable implementation of #ClutterActor for the
12886 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12889 * Unlike the implementation of #GObjectClass.set_property(), this
12890 * function will not update the interval if a transition involving an
12891 * animatable property is in progress - this avoids cycles with the
12892 * transition API calling the public API.
12895 clutter_actor_set_animatable_property (ClutterActor *actor,
12897 const GValue *value,
12903 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12907 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12911 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12915 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12919 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12923 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12926 case PROP_BACKGROUND_COLOR:
12927 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12931 clutter_actor_set_scale_factor_internal (actor,
12932 g_value_get_double (value),
12937 clutter_actor_set_scale_factor_internal (actor,
12938 g_value_get_double (value),
12942 case PROP_ROTATION_ANGLE_X:
12943 clutter_actor_set_rotation_angle_internal (actor,
12945 g_value_get_double (value));
12948 case PROP_ROTATION_ANGLE_Y:
12949 clutter_actor_set_rotation_angle_internal (actor,
12951 g_value_get_double (value));
12954 case PROP_ROTATION_ANGLE_Z:
12955 clutter_actor_set_rotation_angle_internal (actor,
12957 g_value_get_double (value));
12961 g_object_set_property (G_OBJECT (actor), pspec->name, value);
12967 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12968 const gchar *property_name,
12969 const GValue *final)
12971 ClutterActor *actor = CLUTTER_ACTOR (animatable);
12972 ClutterActorMeta *meta = NULL;
12973 gchar *p_name = NULL;
12975 meta = get_meta_from_animation_property (actor,
12979 g_object_set_property (G_OBJECT (meta), p_name, final);
12982 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12985 pspec = g_object_class_find_property (obj_class, property_name);
12987 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12989 /* XXX - I'm going to the special hell for this */
12990 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12993 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13000 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13002 iface->find_property = clutter_actor_find_property;
13003 iface->get_initial_state = clutter_actor_get_initial_state;
13004 iface->set_final_state = clutter_actor_set_final_state;
13008 * clutter_actor_transform_stage_point:
13009 * @self: A #ClutterActor
13010 * @x: (in): x screen coordinate of the point to unproject
13011 * @y: (in): y screen coordinate of the point to unproject
13012 * @x_out: (out): return location for the unprojected x coordinance
13013 * @y_out: (out): return location for the unprojected y coordinance
13015 * This function translates screen coordinates (@x, @y) to
13016 * coordinates relative to the actor. For example, it can be used to translate
13017 * screen events from global screen coordinates into actor-local coordinates.
13019 * The conversion can fail, notably if the transform stack results in the
13020 * actor being projected on the screen as a mere line.
13022 * The conversion should not be expected to be pixel-perfect due to the
13023 * nature of the operation. In general the error grows when the skewing
13024 * of the actor rectangle on screen increases.
13026 * <note><para>This function can be computationally intensive.</para></note>
13028 * <note><para>This function only works when the allocation is up-to-date,
13029 * i.e. inside of paint().</para></note>
13031 * Return value: %TRUE if conversion was successful.
13036 clutter_actor_transform_stage_point (ClutterActor *self,
13042 ClutterVertex v[4];
13045 int du, dv, xi, yi;
13047 float xf, yf, wf, det;
13048 ClutterActorPrivate *priv;
13050 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13054 /* This implementation is based on the quad -> quad projection algorithm
13055 * described by Paul Heckbert in:
13057 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13059 * and the sample implementation at:
13061 * http://www.cs.cmu.edu/~ph/src/texfund/
13063 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13064 * quad to rectangle only, which significantly simplifies things; the
13065 * function calls have been unrolled, and most of the math is done in fixed
13069 clutter_actor_get_abs_allocation_vertices (self, v);
13071 /* Keeping these as ints simplifies the multiplication (no significant
13072 * loss of precision here).
13074 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13075 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13080 #define UX2FP(x) (x)
13081 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13083 /* First, find mapping from unit uv square to xy quadrilateral; this
13084 * equivalent to the pmap_square_quad() functions in the sample
13085 * implementation, which we can simplify, since our target is always
13088 px = v[0].x - v[1].x + v[3].x - v[2].x;
13089 py = v[0].y - v[1].y + v[3].y - v[2].y;
13093 /* affine transform */
13094 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13095 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13096 RQ[2][0] = UX2FP (v[0].x);
13097 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13098 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13099 RQ[2][1] = UX2FP (v[0].y);
13106 /* projective transform */
13107 double dx1, dx2, dy1, dy2, del;
13109 dx1 = UX2FP (v[1].x - v[3].x);
13110 dx2 = UX2FP (v[2].x - v[3].x);
13111 dy1 = UX2FP (v[1].y - v[3].y);
13112 dy2 = UX2FP (v[2].y - v[3].y);
13114 del = DET2FP (dx1, dx2, dy1, dy2);
13119 * The division here needs to be done in floating point for
13120 * precisions reasons.
13122 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13123 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13124 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13126 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13127 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13128 RQ[2][0] = UX2FP (v[0].x);
13129 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13130 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13131 RQ[2][1] = UX2FP (v[0].y);
13135 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13136 * square. Since our rectangle is based at 0,0 we only need to scale.
13146 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13149 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13150 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13151 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13152 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13153 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13154 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13155 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13156 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13157 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13160 * Check the resulting matrix is OK.
13162 det = (RQ[0][0] * ST[0][0])
13163 + (RQ[0][1] * ST[0][1])
13164 + (RQ[0][2] * ST[0][2]);
13169 * Now transform our point with the ST matrix; the notional w
13170 * coordinate is 1, hence the last part is simply added.
13175 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13176 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13177 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13195 static ClutterGeometry*
13196 clutter_geometry_copy (const ClutterGeometry *geometry)
13198 return g_slice_dup (ClutterGeometry, geometry);
13202 clutter_geometry_free (ClutterGeometry *geometry)
13204 if (G_LIKELY (geometry != NULL))
13205 g_slice_free (ClutterGeometry, geometry);
13209 * clutter_geometry_union:
13210 * @geometry_a: a #ClutterGeometry
13211 * @geometry_b: another #ClutterGeometry
13212 * @result: (out): location to store the result
13214 * Find the union of two rectangles represented as #ClutterGeometry.
13219 clutter_geometry_union (const ClutterGeometry *geometry_a,
13220 const ClutterGeometry *geometry_b,
13221 ClutterGeometry *result)
13223 /* We don't try to handle rectangles that can't be represented
13224 * as a signed integer box */
13225 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13226 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13227 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13228 geometry_b->x + (gint)geometry_b->width);
13229 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13230 geometry_b->y + (gint)geometry_b->height);
13233 result->width = x_2 - x_1;
13234 result->height = y_2 - y_1;
13238 * clutter_geometry_intersects:
13239 * @geometry0: The first geometry to test
13240 * @geometry1: The second geometry to test
13242 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13243 * they do else %FALSE.
13245 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13251 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13252 const ClutterGeometry *geometry1)
13254 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13255 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13256 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13257 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13264 clutter_geometry_progress (const GValue *a,
13269 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13270 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13271 ClutterGeometry res = { 0, };
13272 gint a_width = a_geom->width;
13273 gint b_width = b_geom->width;
13274 gint a_height = a_geom->height;
13275 gint b_height = b_geom->height;
13277 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13278 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13280 res.width = a_width + (b_width - a_width) * progress;
13281 res.height = a_height + (b_height - a_height) * progress;
13283 g_value_set_boxed (retval, &res);
13288 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13289 clutter_geometry_copy,
13290 clutter_geometry_free,
13291 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13298 * clutter_vertex_new:
13303 * Creates a new #ClutterVertex for the point in 3D space
13304 * identified by the 3 coordinates @x, @y, @z
13306 * Return value: the newly allocate #ClutterVertex. Use
13307 * clutter_vertex_free() to free the resources
13312 clutter_vertex_new (gfloat x,
13316 ClutterVertex *vertex;
13318 vertex = g_slice_new (ClutterVertex);
13319 clutter_vertex_init (vertex, x, y, z);
13325 * clutter_vertex_init:
13326 * @vertex: a #ClutterVertex
13331 * Initializes @vertex with the given coordinates.
13336 clutter_vertex_init (ClutterVertex *vertex,
13341 g_return_if_fail (vertex != NULL);
13349 * clutter_vertex_copy:
13350 * @vertex: a #ClutterVertex
13354 * Return value: a newly allocated copy of #ClutterVertex. Use
13355 * clutter_vertex_free() to free the allocated resources
13360 clutter_vertex_copy (const ClutterVertex *vertex)
13362 if (G_LIKELY (vertex != NULL))
13363 return g_slice_dup (ClutterVertex, vertex);
13369 * clutter_vertex_free:
13370 * @vertex: a #ClutterVertex
13372 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13377 clutter_vertex_free (ClutterVertex *vertex)
13379 if (G_UNLIKELY (vertex != NULL))
13380 g_slice_free (ClutterVertex, vertex);
13384 * clutter_vertex_equal:
13385 * @vertex_a: a #ClutterVertex
13386 * @vertex_b: a #ClutterVertex
13388 * Compares @vertex_a and @vertex_b for equality
13390 * Return value: %TRUE if the passed #ClutterVertex are equal
13395 clutter_vertex_equal (const ClutterVertex *vertex_a,
13396 const ClutterVertex *vertex_b)
13398 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13400 if (vertex_a == vertex_b)
13403 return vertex_a->x == vertex_b->x &&
13404 vertex_a->y == vertex_b->y &&
13405 vertex_a->z == vertex_b->z;
13409 clutter_vertex_progress (const GValue *a,
13414 const ClutterVertex *av = g_value_get_boxed (a);
13415 const ClutterVertex *bv = g_value_get_boxed (b);
13416 ClutterVertex res = { 0, };
13418 res.x = av->x + (bv->x - av->x) * progress;
13419 res.y = av->y + (bv->y - av->y) * progress;
13420 res.z = av->z + (bv->z - av->z) * progress;
13422 g_value_set_boxed (retval, &res);
13427 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13428 clutter_vertex_copy,
13429 clutter_vertex_free,
13430 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13433 * clutter_actor_is_rotated:
13434 * @self: a #ClutterActor
13436 * Checks whether any rotation is applied to the actor.
13438 * Return value: %TRUE if the actor is rotated.
13443 clutter_actor_is_rotated (ClutterActor *self)
13445 const ClutterTransformInfo *info;
13447 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13449 info = _clutter_actor_get_transform_info_or_defaults (self);
13451 if (info->rx_angle || info->ry_angle || info->rz_angle)
13458 * clutter_actor_is_scaled:
13459 * @self: a #ClutterActor
13461 * Checks whether the actor is scaled in either dimension.
13463 * Return value: %TRUE if the actor is scaled.
13468 clutter_actor_is_scaled (ClutterActor *self)
13470 const ClutterTransformInfo *info;
13472 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13474 info = _clutter_actor_get_transform_info_or_defaults (self);
13476 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13483 _clutter_actor_get_stage_internal (ClutterActor *actor)
13485 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13486 actor = actor->priv->parent;
13492 * clutter_actor_get_stage:
13493 * @actor: a #ClutterActor
13495 * Retrieves the #ClutterStage where @actor is contained.
13497 * Return value: (transfer none) (type Clutter.Stage): the stage
13498 * containing the actor, or %NULL
13503 clutter_actor_get_stage (ClutterActor *actor)
13505 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13507 return _clutter_actor_get_stage_internal (actor);
13511 * clutter_actor_allocate_available_size:
13512 * @self: a #ClutterActor
13513 * @x: the actor's X coordinate
13514 * @y: the actor's Y coordinate
13515 * @available_width: the maximum available width, or -1 to use the
13516 * actor's natural width
13517 * @available_height: the maximum available height, or -1 to use the
13518 * actor's natural height
13519 * @flags: flags controlling the allocation
13521 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13522 * preferred size, but limiting it to the maximum available width
13523 * and height provided.
13525 * This function will do the right thing when dealing with the
13526 * actor's request mode.
13528 * The implementation of this function is equivalent to:
13531 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13533 * clutter_actor_get_preferred_width (self, available_height,
13535 * &natural_width);
13536 * width = CLAMP (natural_width, min_width, available_width);
13538 * clutter_actor_get_preferred_height (self, width,
13540 * &natural_height);
13541 * height = CLAMP (natural_height, min_height, available_height);
13545 * clutter_actor_get_preferred_height (self, available_width,
13547 * &natural_height);
13548 * height = CLAMP (natural_height, min_height, available_height);
13550 * clutter_actor_get_preferred_width (self, height,
13552 * &natural_width);
13553 * width = CLAMP (natural_width, min_width, available_width);
13556 * box.x1 = x; box.y1 = y;
13557 * box.x2 = box.x1 + available_width;
13558 * box.y2 = box.y1 + available_height;
13559 * clutter_actor_allocate (self, &box, flags);
13562 * This function can be used by fluid layout managers to allocate
13563 * an actor's preferred size without making it bigger than the area
13564 * available for the container.
13569 clutter_actor_allocate_available_size (ClutterActor *self,
13572 gfloat available_width,
13573 gfloat available_height,
13574 ClutterAllocationFlags flags)
13576 ClutterActorPrivate *priv;
13577 gfloat width, height;
13578 gfloat min_width, min_height;
13579 gfloat natural_width, natural_height;
13580 ClutterActorBox box;
13582 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13586 width = height = 0.0;
13588 switch (priv->request_mode)
13590 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13591 clutter_actor_get_preferred_width (self, available_height,
13594 width = CLAMP (natural_width, min_width, available_width);
13596 clutter_actor_get_preferred_height (self, width,
13599 height = CLAMP (natural_height, min_height, available_height);
13602 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13603 clutter_actor_get_preferred_height (self, available_width,
13606 height = CLAMP (natural_height, min_height, available_height);
13608 clutter_actor_get_preferred_width (self, height,
13611 width = CLAMP (natural_width, min_width, available_width);
13618 box.x2 = box.x1 + width;
13619 box.y2 = box.y1 + height;
13620 clutter_actor_allocate (self, &box, flags);
13624 * clutter_actor_allocate_preferred_size:
13625 * @self: a #ClutterActor
13626 * @flags: flags controlling the allocation
13628 * Allocates the natural size of @self.
13630 * This function is a utility call for #ClutterActor implementations
13631 * that allocates the actor's preferred natural size. It can be used
13632 * by fixed layout managers (like #ClutterGroup or so called
13633 * 'composite actors') inside the ClutterActor::allocate
13634 * implementation to give each child exactly how much space it
13637 * This function is not meant to be used by applications. It is also
13638 * not meant to be used outside the implementation of the
13639 * ClutterActor::allocate virtual function.
13644 clutter_actor_allocate_preferred_size (ClutterActor *self,
13645 ClutterAllocationFlags flags)
13647 gfloat actor_x, actor_y;
13648 gfloat natural_width, natural_height;
13649 ClutterActorBox actor_box;
13651 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13653 actor_x = clutter_actor_get_x (self);
13654 actor_y = clutter_actor_get_y (self);
13656 clutter_actor_get_preferred_size (self,
13661 actor_box.x1 = actor_x;
13662 actor_box.y1 = actor_y;
13663 actor_box.x2 = actor_box.x1 + natural_width;
13664 actor_box.y2 = actor_box.y1 + natural_height;
13666 clutter_actor_allocate (self, &actor_box, flags);
13670 * clutter_actor_allocate_align_fill:
13671 * @self: a #ClutterActor
13672 * @box: a #ClutterActorBox, containing the available width and height
13673 * @x_align: the horizontal alignment, between 0 and 1
13674 * @y_align: the vertical alignment, between 0 and 1
13675 * @x_fill: whether the actor should fill horizontally
13676 * @y_fill: whether the actor should fill vertically
13677 * @flags: allocation flags to be passed to clutter_actor_allocate()
13679 * Allocates @self by taking into consideration the available allocation
13680 * area; an alignment factor on either axis; and whether the actor should
13681 * fill the allocation on either axis.
13683 * The @box should contain the available allocation width and height;
13684 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13685 * allocation will be offset by their value.
13687 * This function takes into consideration the geometry request specified by
13688 * the #ClutterActor:request-mode property, and the text direction.
13690 * This function is useful for fluid layout managers, like #ClutterBinLayout
13691 * or #ClutterTableLayout
13696 clutter_actor_allocate_align_fill (ClutterActor *self,
13697 const ClutterActorBox *box,
13702 ClutterAllocationFlags flags)
13704 ClutterActorPrivate *priv;
13705 ClutterActorBox allocation = { 0, };
13706 gfloat x_offset, y_offset;
13707 gfloat available_width, available_height;
13708 gfloat child_width, child_height;
13710 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13711 g_return_if_fail (box != NULL);
13712 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13713 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13717 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13718 clutter_actor_box_get_size (box, &available_width, &available_height);
13720 if (available_width < 0)
13721 available_width = 0;
13723 if (available_height < 0)
13724 available_height = 0;
13728 allocation.x1 = x_offset;
13729 allocation.x2 = allocation.x1 + available_width;
13734 allocation.y1 = y_offset;
13735 allocation.y2 = allocation.y1 + available_height;
13738 /* if we are filling horizontally and vertically then we're done */
13739 if (x_fill && y_fill)
13742 child_width = child_height = 0.0f;
13744 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13746 gfloat min_width, natural_width;
13747 gfloat min_height, natural_height;
13749 clutter_actor_get_preferred_width (self, available_height,
13753 child_width = CLAMP (natural_width, min_width, available_width);
13757 clutter_actor_get_preferred_height (self, child_width,
13761 child_height = CLAMP (natural_height, min_height, available_height);
13766 gfloat min_width, natural_width;
13767 gfloat min_height, natural_height;
13769 clutter_actor_get_preferred_height (self, available_width,
13773 child_height = CLAMP (natural_height, min_height, available_height);
13777 clutter_actor_get_preferred_width (self, child_height,
13781 child_width = CLAMP (natural_width, min_width, available_width);
13785 /* invert the horizontal alignment for RTL languages */
13786 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13787 x_align = 1.0 - x_align;
13791 allocation.x1 = x_offset
13792 + ((available_width - child_width) * x_align);
13793 allocation.x2 = allocation.x1 + child_width;
13798 allocation.y1 = y_offset
13799 + ((available_height - child_height) * y_align);
13800 allocation.y2 = allocation.y1 + child_height;
13804 clutter_actor_box_clamp_to_pixel (&allocation);
13805 clutter_actor_allocate (self, &allocation, flags);
13809 * clutter_actor_grab_key_focus:
13810 * @self: a #ClutterActor
13812 * Sets the key focus of the #ClutterStage including @self
13813 * to this #ClutterActor.
13818 clutter_actor_grab_key_focus (ClutterActor *self)
13820 ClutterActor *stage;
13822 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13824 stage = _clutter_actor_get_stage_internal (self);
13826 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13830 * clutter_actor_get_pango_context:
13831 * @self: a #ClutterActor
13833 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13834 * is already configured using the appropriate font map, resolution
13835 * and font options.
13837 * Unlike clutter_actor_create_pango_context(), this context is owend
13838 * by the #ClutterActor and it will be updated each time the options
13839 * stored by the #ClutterBackend change.
13841 * You can use the returned #PangoContext to create a #PangoLayout
13842 * and render text using cogl_pango_render_layout() to reuse the
13843 * glyphs cache also used by Clutter.
13845 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13846 * The returned #PangoContext is owned by the actor and should not be
13847 * unreferenced by the application code
13852 clutter_actor_get_pango_context (ClutterActor *self)
13854 ClutterActorPrivate *priv;
13856 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13860 if (priv->pango_context != NULL)
13861 return priv->pango_context;
13863 priv->pango_context = _clutter_context_get_pango_context ();
13864 g_object_ref (priv->pango_context);
13866 return priv->pango_context;
13870 * clutter_actor_create_pango_context:
13871 * @self: a #ClutterActor
13873 * Creates a #PangoContext for the given actor. The #PangoContext
13874 * is already configured using the appropriate font map, resolution
13875 * and font options.
13877 * See also clutter_actor_get_pango_context().
13879 * Return value: (transfer full): the newly created #PangoContext.
13880 * Use g_object_unref() on the returned value to deallocate its
13886 clutter_actor_create_pango_context (ClutterActor *self)
13888 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13890 return _clutter_context_create_pango_context ();
13894 * clutter_actor_create_pango_layout:
13895 * @self: a #ClutterActor
13896 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13898 * Creates a new #PangoLayout from the same #PangoContext used
13899 * by the #ClutterActor. The #PangoLayout is already configured
13900 * with the font map, resolution and font options, and the
13903 * If you want to keep around a #PangoLayout created by this
13904 * function you will have to connect to the #ClutterBackend::font-changed
13905 * and #ClutterBackend::resolution-changed signals, and call
13906 * pango_layout_context_changed() in response to them.
13908 * Return value: (transfer full): the newly created #PangoLayout.
13909 * Use g_object_unref() when done
13914 clutter_actor_create_pango_layout (ClutterActor *self,
13917 PangoContext *context;
13918 PangoLayout *layout;
13920 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13922 context = clutter_actor_get_pango_context (self);
13923 layout = pango_layout_new (context);
13926 pango_layout_set_text (layout, text, -1);
13931 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13932 * ClutterOffscreenEffect.
13935 _clutter_actor_set_opacity_override (ClutterActor *self,
13938 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13940 self->priv->opacity_override = opacity;
13944 _clutter_actor_get_opacity_override (ClutterActor *self)
13946 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13948 return self->priv->opacity_override;
13951 /* Allows you to disable applying the actors model view transform during
13952 * a paint. Used by ClutterClone. */
13954 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13957 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13959 self->priv->enable_model_view_transform = enable;
13963 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13966 ClutterActorPrivate *priv;
13968 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13972 priv->enable_paint_unmapped = enable;
13974 if (priv->enable_paint_unmapped)
13976 /* Make sure that the parents of the widget are realized first;
13977 * otherwise checks in clutter_actor_update_map_state() will
13980 clutter_actor_realize (self);
13982 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13986 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13991 clutter_anchor_coord_get_units (ClutterActor *self,
13992 const AnchorCoord *coord,
13997 if (coord->is_fractional)
13999 gfloat actor_width, actor_height;
14001 clutter_actor_get_size (self, &actor_width, &actor_height);
14004 *x = actor_width * coord->v.fraction.x;
14007 *y = actor_height * coord->v.fraction.y;
14015 *x = coord->v.units.x;
14018 *y = coord->v.units.y;
14021 *z = coord->v.units.z;
14026 clutter_anchor_coord_set_units (AnchorCoord *coord,
14031 coord->is_fractional = FALSE;
14032 coord->v.units.x = x;
14033 coord->v.units.y = y;
14034 coord->v.units.z = z;
14037 static ClutterGravity
14038 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14040 if (coord->is_fractional)
14042 if (coord->v.fraction.x == 0.0)
14044 if (coord->v.fraction.y == 0.0)
14045 return CLUTTER_GRAVITY_NORTH_WEST;
14046 else if (coord->v.fraction.y == 0.5)
14047 return CLUTTER_GRAVITY_WEST;
14048 else if (coord->v.fraction.y == 1.0)
14049 return CLUTTER_GRAVITY_SOUTH_WEST;
14051 return CLUTTER_GRAVITY_NONE;
14053 else if (coord->v.fraction.x == 0.5)
14055 if (coord->v.fraction.y == 0.0)
14056 return CLUTTER_GRAVITY_NORTH;
14057 else if (coord->v.fraction.y == 0.5)
14058 return CLUTTER_GRAVITY_CENTER;
14059 else if (coord->v.fraction.y == 1.0)
14060 return CLUTTER_GRAVITY_SOUTH;
14062 return CLUTTER_GRAVITY_NONE;
14064 else if (coord->v.fraction.x == 1.0)
14066 if (coord->v.fraction.y == 0.0)
14067 return CLUTTER_GRAVITY_NORTH_EAST;
14068 else if (coord->v.fraction.y == 0.5)
14069 return CLUTTER_GRAVITY_EAST;
14070 else if (coord->v.fraction.y == 1.0)
14071 return CLUTTER_GRAVITY_SOUTH_EAST;
14073 return CLUTTER_GRAVITY_NONE;
14076 return CLUTTER_GRAVITY_NONE;
14079 return CLUTTER_GRAVITY_NONE;
14083 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14084 ClutterGravity gravity)
14088 case CLUTTER_GRAVITY_NORTH:
14089 coord->v.fraction.x = 0.5;
14090 coord->v.fraction.y = 0.0;
14093 case CLUTTER_GRAVITY_NORTH_EAST:
14094 coord->v.fraction.x = 1.0;
14095 coord->v.fraction.y = 0.0;
14098 case CLUTTER_GRAVITY_EAST:
14099 coord->v.fraction.x = 1.0;
14100 coord->v.fraction.y = 0.5;
14103 case CLUTTER_GRAVITY_SOUTH_EAST:
14104 coord->v.fraction.x = 1.0;
14105 coord->v.fraction.y = 1.0;
14108 case CLUTTER_GRAVITY_SOUTH:
14109 coord->v.fraction.x = 0.5;
14110 coord->v.fraction.y = 1.0;
14113 case CLUTTER_GRAVITY_SOUTH_WEST:
14114 coord->v.fraction.x = 0.0;
14115 coord->v.fraction.y = 1.0;
14118 case CLUTTER_GRAVITY_WEST:
14119 coord->v.fraction.x = 0.0;
14120 coord->v.fraction.y = 0.5;
14123 case CLUTTER_GRAVITY_NORTH_WEST:
14124 coord->v.fraction.x = 0.0;
14125 coord->v.fraction.y = 0.0;
14128 case CLUTTER_GRAVITY_CENTER:
14129 coord->v.fraction.x = 0.5;
14130 coord->v.fraction.y = 0.5;
14134 coord->v.fraction.x = 0.0;
14135 coord->v.fraction.y = 0.0;
14139 coord->is_fractional = TRUE;
14143 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14145 if (coord->is_fractional)
14146 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14148 return (coord->v.units.x == 0.0
14149 && coord->v.units.y == 0.0
14150 && coord->v.units.z == 0.0);
14154 * clutter_actor_get_flags:
14155 * @self: a #ClutterActor
14157 * Retrieves the flags set on @self
14159 * Return value: a bitwise or of #ClutterActorFlags or 0
14164 clutter_actor_get_flags (ClutterActor *self)
14166 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14168 return self->flags;
14172 * clutter_actor_set_flags:
14173 * @self: a #ClutterActor
14174 * @flags: the flags to set
14176 * Sets @flags on @self
14178 * This function will emit notifications for the changed properties
14183 clutter_actor_set_flags (ClutterActor *self,
14184 ClutterActorFlags flags)
14186 ClutterActorFlags old_flags;
14188 gboolean was_reactive_set, reactive_set;
14189 gboolean was_realized_set, realized_set;
14190 gboolean was_mapped_set, mapped_set;
14191 gboolean was_visible_set, visible_set;
14193 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14195 if (self->flags == flags)
14198 obj = G_OBJECT (self);
14199 g_object_ref (obj);
14200 g_object_freeze_notify (obj);
14202 old_flags = self->flags;
14204 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14205 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14206 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14207 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14209 self->flags |= flags;
14211 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14212 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14213 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14214 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14216 if (reactive_set != was_reactive_set)
14217 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14219 if (realized_set != was_realized_set)
14220 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14222 if (mapped_set != was_mapped_set)
14223 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14225 if (visible_set != was_visible_set)
14226 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14228 g_object_thaw_notify (obj);
14229 g_object_unref (obj);
14233 * clutter_actor_unset_flags:
14234 * @self: a #ClutterActor
14235 * @flags: the flags to unset
14237 * Unsets @flags on @self
14239 * This function will emit notifications for the changed properties
14244 clutter_actor_unset_flags (ClutterActor *self,
14245 ClutterActorFlags flags)
14247 ClutterActorFlags old_flags;
14249 gboolean was_reactive_set, reactive_set;
14250 gboolean was_realized_set, realized_set;
14251 gboolean was_mapped_set, mapped_set;
14252 gboolean was_visible_set, visible_set;
14254 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14256 obj = G_OBJECT (self);
14257 g_object_freeze_notify (obj);
14259 old_flags = self->flags;
14261 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14262 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14263 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14264 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14266 self->flags &= ~flags;
14268 if (self->flags == old_flags)
14271 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14272 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14273 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14274 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14276 if (reactive_set != was_reactive_set)
14277 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14279 if (realized_set != was_realized_set)
14280 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14282 if (mapped_set != was_mapped_set)
14283 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14285 if (visible_set != was_visible_set)
14286 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14288 g_object_thaw_notify (obj);
14292 * clutter_actor_get_transformation_matrix:
14293 * @self: a #ClutterActor
14294 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14296 * Retrieves the transformations applied to @self relative to its
14302 clutter_actor_get_transformation_matrix (ClutterActor *self,
14303 CoglMatrix *matrix)
14305 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14307 cogl_matrix_init_identity (matrix);
14309 _clutter_actor_apply_modelview_transform (self, matrix);
14313 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14314 gboolean is_in_clone_paint)
14316 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14317 self->priv->in_clone_paint = is_in_clone_paint;
14321 * clutter_actor_is_in_clone_paint:
14322 * @self: a #ClutterActor
14324 * Checks whether @self is being currently painted by a #ClutterClone
14326 * This function is useful only inside the ::paint virtual function
14327 * implementations or within handlers for the #ClutterActor::paint
14330 * This function should not be used by applications
14332 * Return value: %TRUE if the #ClutterActor is currently being painted
14333 * by a #ClutterClone, and %FALSE otherwise
14338 clutter_actor_is_in_clone_paint (ClutterActor *self)
14340 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14342 return self->priv->in_clone_paint;
14346 set_direction_recursive (ClutterActor *actor,
14347 gpointer user_data)
14349 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14351 clutter_actor_set_text_direction (actor, text_dir);
14357 * clutter_actor_set_text_direction:
14358 * @self: a #ClutterActor
14359 * @text_dir: the text direction for @self
14361 * Sets the #ClutterTextDirection for an actor
14363 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14365 * If @self implements #ClutterContainer then this function will recurse
14366 * inside all the children of @self (including the internal ones).
14368 * Composite actors not implementing #ClutterContainer, or actors requiring
14369 * special handling when the text direction changes, should connect to
14370 * the #GObject::notify signal for the #ClutterActor:text-direction property
14375 clutter_actor_set_text_direction (ClutterActor *self,
14376 ClutterTextDirection text_dir)
14378 ClutterActorPrivate *priv;
14380 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14381 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14385 if (priv->text_direction != text_dir)
14387 priv->text_direction = text_dir;
14389 /* we need to emit the notify::text-direction first, so that
14390 * the sub-classes can catch that and do specific handling of
14391 * the text direction; see clutter_text_direction_changed_cb()
14392 * inside clutter-text.c
14394 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14396 _clutter_actor_foreach_child (self, set_direction_recursive,
14397 GINT_TO_POINTER (text_dir));
14399 clutter_actor_queue_relayout (self);
14404 _clutter_actor_set_has_pointer (ClutterActor *self,
14405 gboolean has_pointer)
14407 ClutterActorPrivate *priv = self->priv;
14409 if (priv->has_pointer != has_pointer)
14411 priv->has_pointer = has_pointer;
14413 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14418 * clutter_actor_get_text_direction:
14419 * @self: a #ClutterActor
14421 * Retrieves the value set using clutter_actor_set_text_direction()
14423 * If no text direction has been previously set, the default text
14424 * direction, as returned by clutter_get_default_text_direction(), will
14425 * be returned instead
14427 * Return value: the #ClutterTextDirection for the actor
14431 ClutterTextDirection
14432 clutter_actor_get_text_direction (ClutterActor *self)
14434 ClutterActorPrivate *priv;
14436 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14437 CLUTTER_TEXT_DIRECTION_LTR);
14441 /* if no direction has been set yet use the default */
14442 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14443 priv->text_direction = clutter_get_default_text_direction ();
14445 return priv->text_direction;
14449 * clutter_actor_push_internal:
14450 * @self: a #ClutterActor
14452 * Should be used by actors implementing the #ClutterContainer and with
14453 * internal children added through clutter_actor_set_parent(), for instance:
14457 * my_actor_init (MyActor *self)
14459 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14461 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14463 * /* calling clutter_actor_set_parent() now will result in
14464 * * the internal flag being set on a child of MyActor
14467 * /* internal child - a background texture */
14468 * self->priv->background_tex = clutter_texture_new ();
14469 * clutter_actor_set_parent (self->priv->background_tex,
14470 * CLUTTER_ACTOR (self));
14472 * /* internal child - a label */
14473 * self->priv->label = clutter_text_new ();
14474 * clutter_actor_set_parent (self->priv->label,
14475 * CLUTTER_ACTOR (self));
14477 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14479 * /* calling clutter_actor_set_parent() now will not result in
14480 * * the internal flag being set on a child of MyActor
14485 * This function will be used by Clutter to toggle an "internal child"
14486 * flag whenever clutter_actor_set_parent() is called; internal children
14487 * are handled differently by Clutter, specifically when destroying their
14490 * Call clutter_actor_pop_internal() when you finished adding internal
14493 * Nested calls to clutter_actor_push_internal() are allowed, but each
14494 * one must by followed by a clutter_actor_pop_internal() call.
14498 * Deprecated: 1.10: All children of an actor are accessible through
14499 * the #ClutterActor API, and #ClutterActor implements the
14500 * #ClutterContainer interface, so this function is only useful
14501 * for legacy containers overriding the default implementation.
14504 clutter_actor_push_internal (ClutterActor *self)
14506 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14508 self->priv->internal_child += 1;
14512 * clutter_actor_pop_internal:
14513 * @self: a #ClutterActor
14515 * Disables the effects of clutter_actor_push_internal().
14519 * Deprecated: 1.10: All children of an actor are accessible through
14520 * the #ClutterActor API. This function is only useful for legacy
14521 * containers overriding the default implementation of the
14522 * #ClutterContainer interface.
14525 clutter_actor_pop_internal (ClutterActor *self)
14527 ClutterActorPrivate *priv;
14529 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14533 if (priv->internal_child == 0)
14535 g_warning ("Mismatched %s: you need to call "
14536 "clutter_actor_push_composite() at least once before "
14537 "calling this function", G_STRFUNC);
14541 priv->internal_child -= 1;
14545 * clutter_actor_has_pointer:
14546 * @self: a #ClutterActor
14548 * Checks whether an actor contains the pointer of a
14549 * #ClutterInputDevice
14551 * Return value: %TRUE if the actor contains the pointer, and
14557 clutter_actor_has_pointer (ClutterActor *self)
14559 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14561 return self->priv->has_pointer;
14564 /* XXX: This is a workaround for not being able to break the ABI of
14565 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14566 * clutter_actor_queue_clipped_redraw() for details.
14568 ClutterPaintVolume *
14569 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14571 return g_object_get_data (G_OBJECT (self),
14572 "-clutter-actor-queue-redraw-clip");
14576 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14577 ClutterPaintVolume *clip)
14579 g_object_set_data (G_OBJECT (self),
14580 "-clutter-actor-queue-redraw-clip",
14585 * clutter_actor_has_allocation:
14586 * @self: a #ClutterActor
14588 * Checks if the actor has an up-to-date allocation assigned to
14589 * it. This means that the actor should have an allocation: it's
14590 * visible and has a parent. It also means that there is no
14591 * outstanding relayout request in progress for the actor or its
14592 * children (There might be other outstanding layout requests in
14593 * progress that will cause the actor to get a new allocation
14594 * when the stage is laid out, however).
14596 * If this function returns %FALSE, then the actor will normally
14597 * be allocated before it is next drawn on the screen.
14599 * Return value: %TRUE if the actor has an up-to-date allocation
14604 clutter_actor_has_allocation (ClutterActor *self)
14606 ClutterActorPrivate *priv;
14608 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14612 return priv->parent != NULL &&
14613 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14614 !priv->needs_allocation;
14618 * clutter_actor_add_action:
14619 * @self: a #ClutterActor
14620 * @action: a #ClutterAction
14622 * Adds @action to the list of actions applied to @self
14624 * A #ClutterAction can only belong to one actor at a time
14626 * The #ClutterActor will hold a reference on @action until either
14627 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14633 clutter_actor_add_action (ClutterActor *self,
14634 ClutterAction *action)
14636 ClutterActorPrivate *priv;
14638 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14639 g_return_if_fail (CLUTTER_IS_ACTION (action));
14643 if (priv->actions == NULL)
14645 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14646 priv->actions->actor = self;
14649 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14651 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14655 * clutter_actor_add_action_with_name:
14656 * @self: a #ClutterActor
14657 * @name: the name to set on the action
14658 * @action: a #ClutterAction
14660 * A convenience function for setting the name of a #ClutterAction
14661 * while adding it to the list of actions applied to @self
14663 * This function is the logical equivalent of:
14666 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14667 * clutter_actor_add_action (self, action);
14673 clutter_actor_add_action_with_name (ClutterActor *self,
14675 ClutterAction *action)
14677 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14678 g_return_if_fail (name != NULL);
14679 g_return_if_fail (CLUTTER_IS_ACTION (action));
14681 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14682 clutter_actor_add_action (self, action);
14686 * clutter_actor_remove_action:
14687 * @self: a #ClutterActor
14688 * @action: a #ClutterAction
14690 * Removes @action from the list of actions applied to @self
14692 * The reference held by @self on the #ClutterAction will be released
14697 clutter_actor_remove_action (ClutterActor *self,
14698 ClutterAction *action)
14700 ClutterActorPrivate *priv;
14702 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14703 g_return_if_fail (CLUTTER_IS_ACTION (action));
14707 if (priv->actions == NULL)
14710 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14712 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14716 * clutter_actor_remove_action_by_name:
14717 * @self: a #ClutterActor
14718 * @name: the name of the action to remove
14720 * Removes the #ClutterAction with the given name from the list
14721 * of actions applied to @self
14726 clutter_actor_remove_action_by_name (ClutterActor *self,
14729 ClutterActorPrivate *priv;
14730 ClutterActorMeta *meta;
14732 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14733 g_return_if_fail (name != NULL);
14737 if (priv->actions == NULL)
14740 meta = _clutter_meta_group_get_meta (priv->actions, name);
14744 _clutter_meta_group_remove_meta (priv->actions, meta);
14746 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14750 * clutter_actor_get_actions:
14751 * @self: a #ClutterActor
14753 * Retrieves the list of actions applied to @self
14755 * Return value: (transfer container) (element-type Clutter.Action): a copy
14756 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14757 * owned by the #ClutterActor. Use g_list_free() to free the resources
14758 * allocated by the returned #GList
14763 clutter_actor_get_actions (ClutterActor *self)
14765 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14767 if (self->priv->actions == NULL)
14770 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14774 * clutter_actor_get_action:
14775 * @self: a #ClutterActor
14776 * @name: the name of the action to retrieve
14778 * Retrieves the #ClutterAction with the given name in the list
14779 * of actions applied to @self
14781 * Return value: (transfer none): a #ClutterAction for the given
14782 * name, or %NULL. The returned #ClutterAction is owned by the
14783 * actor and it should not be unreferenced directly
14788 clutter_actor_get_action (ClutterActor *self,
14791 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14792 g_return_val_if_fail (name != NULL, NULL);
14794 if (self->priv->actions == NULL)
14797 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14801 * clutter_actor_clear_actions:
14802 * @self: a #ClutterActor
14804 * Clears the list of actions applied to @self
14809 clutter_actor_clear_actions (ClutterActor *self)
14811 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14813 if (self->priv->actions == NULL)
14816 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14820 * clutter_actor_add_constraint:
14821 * @self: a #ClutterActor
14822 * @constraint: a #ClutterConstraint
14824 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14827 * The #ClutterActor will hold a reference on the @constraint until
14828 * either clutter_actor_remove_constraint() or
14829 * clutter_actor_clear_constraints() is called.
14834 clutter_actor_add_constraint (ClutterActor *self,
14835 ClutterConstraint *constraint)
14837 ClutterActorPrivate *priv;
14839 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14840 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14844 if (priv->constraints == NULL)
14846 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14847 priv->constraints->actor = self;
14850 _clutter_meta_group_add_meta (priv->constraints,
14851 CLUTTER_ACTOR_META (constraint));
14852 clutter_actor_queue_relayout (self);
14854 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14858 * clutter_actor_add_constraint_with_name:
14859 * @self: a #ClutterActor
14860 * @name: the name to set on the constraint
14861 * @constraint: a #ClutterConstraint
14863 * A convenience function for setting the name of a #ClutterConstraint
14864 * while adding it to the list of constraints applied to @self
14866 * This function is the logical equivalent of:
14869 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14870 * clutter_actor_add_constraint (self, constraint);
14876 clutter_actor_add_constraint_with_name (ClutterActor *self,
14878 ClutterConstraint *constraint)
14880 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14881 g_return_if_fail (name != NULL);
14882 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14884 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14885 clutter_actor_add_constraint (self, constraint);
14889 * clutter_actor_remove_constraint:
14890 * @self: a #ClutterActor
14891 * @constraint: a #ClutterConstraint
14893 * Removes @constraint from the list of constraints applied to @self
14895 * The reference held by @self on the #ClutterConstraint will be released
14900 clutter_actor_remove_constraint (ClutterActor *self,
14901 ClutterConstraint *constraint)
14903 ClutterActorPrivate *priv;
14905 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14906 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14910 if (priv->constraints == NULL)
14913 _clutter_meta_group_remove_meta (priv->constraints,
14914 CLUTTER_ACTOR_META (constraint));
14915 clutter_actor_queue_relayout (self);
14917 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14921 * clutter_actor_remove_constraint_by_name:
14922 * @self: a #ClutterActor
14923 * @name: the name of the constraint to remove
14925 * Removes the #ClutterConstraint with the given name from the list
14926 * of constraints applied to @self
14931 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14934 ClutterActorPrivate *priv;
14935 ClutterActorMeta *meta;
14937 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14938 g_return_if_fail (name != NULL);
14942 if (priv->constraints == NULL)
14945 meta = _clutter_meta_group_get_meta (priv->constraints, name);
14949 _clutter_meta_group_remove_meta (priv->constraints, meta);
14950 clutter_actor_queue_relayout (self);
14954 * clutter_actor_get_constraints:
14955 * @self: a #ClutterActor
14957 * Retrieves the list of constraints applied to @self
14959 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14960 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14961 * owned by the #ClutterActor. Use g_list_free() to free the resources
14962 * allocated by the returned #GList
14967 clutter_actor_get_constraints (ClutterActor *self)
14969 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14971 if (self->priv->constraints == NULL)
14974 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14978 * clutter_actor_get_constraint:
14979 * @self: a #ClutterActor
14980 * @name: the name of the constraint to retrieve
14982 * Retrieves the #ClutterConstraint with the given name in the list
14983 * of constraints applied to @self
14985 * Return value: (transfer none): a #ClutterConstraint for the given
14986 * name, or %NULL. The returned #ClutterConstraint is owned by the
14987 * actor and it should not be unreferenced directly
14991 ClutterConstraint *
14992 clutter_actor_get_constraint (ClutterActor *self,
14995 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14996 g_return_val_if_fail (name != NULL, NULL);
14998 if (self->priv->constraints == NULL)
15001 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15005 * clutter_actor_clear_constraints:
15006 * @self: a #ClutterActor
15008 * Clears the list of constraints applied to @self
15013 clutter_actor_clear_constraints (ClutterActor *self)
15015 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15017 if (self->priv->constraints == NULL)
15020 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15022 clutter_actor_queue_relayout (self);
15026 * clutter_actor_set_clip_to_allocation:
15027 * @self: a #ClutterActor
15028 * @clip_set: %TRUE to apply a clip tracking the allocation
15030 * Sets whether @self should be clipped to the same size as its
15036 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15039 ClutterActorPrivate *priv;
15041 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15043 clip_set = !!clip_set;
15047 if (priv->clip_to_allocation != clip_set)
15049 priv->clip_to_allocation = clip_set;
15051 clutter_actor_queue_redraw (self);
15053 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15058 * clutter_actor_get_clip_to_allocation:
15059 * @self: a #ClutterActor
15061 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15063 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15068 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15070 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15072 return self->priv->clip_to_allocation;
15076 * clutter_actor_add_effect:
15077 * @self: a #ClutterActor
15078 * @effect: a #ClutterEffect
15080 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15082 * The #ClutterActor will hold a reference on the @effect until either
15083 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15089 clutter_actor_add_effect (ClutterActor *self,
15090 ClutterEffect *effect)
15092 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15093 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15095 _clutter_actor_add_effect_internal (self, effect);
15097 clutter_actor_queue_redraw (self);
15099 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15103 * clutter_actor_add_effect_with_name:
15104 * @self: a #ClutterActor
15105 * @name: the name to set on the effect
15106 * @effect: a #ClutterEffect
15108 * A convenience function for setting the name of a #ClutterEffect
15109 * while adding it to the list of effectss applied to @self
15111 * This function is the logical equivalent of:
15114 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15115 * clutter_actor_add_effect (self, effect);
15121 clutter_actor_add_effect_with_name (ClutterActor *self,
15123 ClutterEffect *effect)
15125 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15126 g_return_if_fail (name != NULL);
15127 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15129 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15130 clutter_actor_add_effect (self, effect);
15134 * clutter_actor_remove_effect:
15135 * @self: a #ClutterActor
15136 * @effect: a #ClutterEffect
15138 * Removes @effect from the list of effects applied to @self
15140 * The reference held by @self on the #ClutterEffect will be released
15145 clutter_actor_remove_effect (ClutterActor *self,
15146 ClutterEffect *effect)
15148 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15149 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15151 _clutter_actor_remove_effect_internal (self, effect);
15153 clutter_actor_queue_redraw (self);
15155 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15159 * clutter_actor_remove_effect_by_name:
15160 * @self: a #ClutterActor
15161 * @name: the name of the effect to remove
15163 * Removes the #ClutterEffect with the given name from the list
15164 * of effects applied to @self
15169 clutter_actor_remove_effect_by_name (ClutterActor *self,
15172 ClutterActorPrivate *priv;
15173 ClutterActorMeta *meta;
15175 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15176 g_return_if_fail (name != NULL);
15180 if (priv->effects == NULL)
15183 meta = _clutter_meta_group_get_meta (priv->effects, name);
15187 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15191 * clutter_actor_get_effects:
15192 * @self: a #ClutterActor
15194 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15196 * Return value: (transfer container) (element-type Clutter.Effect): a list
15197 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15198 * list are owned by Clutter and they should not be freed. You should
15199 * free the returned list using g_list_free() when done
15204 clutter_actor_get_effects (ClutterActor *self)
15206 ClutterActorPrivate *priv;
15208 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15212 if (priv->effects == NULL)
15215 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15219 * clutter_actor_get_effect:
15220 * @self: a #ClutterActor
15221 * @name: the name of the effect to retrieve
15223 * Retrieves the #ClutterEffect with the given name in the list
15224 * of effects applied to @self
15226 * Return value: (transfer none): a #ClutterEffect for the given
15227 * name, or %NULL. The returned #ClutterEffect is owned by the
15228 * actor and it should not be unreferenced directly
15233 clutter_actor_get_effect (ClutterActor *self,
15236 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15237 g_return_val_if_fail (name != NULL, NULL);
15239 if (self->priv->effects == NULL)
15242 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15246 * clutter_actor_clear_effects:
15247 * @self: a #ClutterActor
15249 * Clears the list of effects applied to @self
15254 clutter_actor_clear_effects (ClutterActor *self)
15256 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15258 if (self->priv->effects == NULL)
15261 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15263 clutter_actor_queue_redraw (self);
15267 * clutter_actor_has_key_focus:
15268 * @self: a #ClutterActor
15270 * Checks whether @self is the #ClutterActor that has key focus
15272 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15277 clutter_actor_has_key_focus (ClutterActor *self)
15279 ClutterActor *stage;
15281 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15283 stage = _clutter_actor_get_stage_internal (self);
15287 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15291 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15292 ClutterPaintVolume *pv)
15294 ClutterActorPrivate *priv = self->priv;
15296 /* Actors are only expected to report a valid paint volume
15297 * while they have a valid allocation. */
15298 if (G_UNLIKELY (priv->needs_allocation))
15300 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15301 "Actor needs allocation",
15302 _clutter_actor_get_debug_name (self));
15306 /* Check if there are any handlers connected to the paint
15307 * signal. If there are then all bets are off for what the paint
15308 * volume for this actor might possibly be!
15310 * XXX: It's expected that this is going to end up being quite a
15311 * costly check to have to do here, but we haven't come up with
15312 * another solution that can reliably catch paint signal handlers at
15313 * the right time to either avoid artefacts due to invalid stage
15314 * clipping or due to incorrect culling.
15316 * Previously we checked in clutter_actor_paint(), but at that time
15317 * we may already be using a stage clip that could be derived from
15318 * an invalid paint-volume. We used to try and handle that by
15319 * queuing a follow up, unclipped, redraw but still the previous
15320 * checking wasn't enough to catch invalid volumes involved in
15321 * culling (considering that containers may derive their volume from
15322 * children that haven't yet been painted)
15324 * Longer term, improved solutions could be:
15325 * - Disallow painting in the paint signal, only allow using it
15326 * for tracking when paints happen. We can add another API that
15327 * allows monkey patching the paint of arbitrary actors but in a
15328 * more controlled way and that also supports modifying the
15330 * - If we could be notified somehow when signal handlers are
15331 * connected we wouldn't have to poll for handlers like this.
15333 if (g_signal_has_handler_pending (self,
15334 actor_signals[PAINT],
15338 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15339 "Actor has \"paint\" signal handlers",
15340 _clutter_actor_get_debug_name (self));
15344 _clutter_paint_volume_init_static (pv, self);
15346 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15348 clutter_paint_volume_free (pv);
15349 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15350 "Actor failed to report a volume",
15351 _clutter_actor_get_debug_name (self));
15355 /* since effects can modify the paint volume, we allow them to actually
15356 * do this by making get_paint_volume() "context sensitive"
15358 if (priv->effects != NULL)
15360 if (priv->current_effect != NULL)
15362 const GList *effects, *l;
15364 /* if we are being called from within the paint sequence of
15365 * an actor, get the paint volume up to the current effect
15367 effects = _clutter_meta_group_peek_metas (priv->effects);
15369 l != NULL || (l != NULL && l->data != priv->current_effect);
15372 if (!_clutter_effect_get_paint_volume (l->data, pv))
15374 clutter_paint_volume_free (pv);
15375 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15376 "Effect (%s) failed to report a volume",
15377 _clutter_actor_get_debug_name (self),
15378 _clutter_actor_meta_get_debug_name (l->data));
15385 const GList *effects, *l;
15387 /* otherwise, get the cumulative volume */
15388 effects = _clutter_meta_group_peek_metas (priv->effects);
15389 for (l = effects; l != NULL; l = l->next)
15390 if (!_clutter_effect_get_paint_volume (l->data, pv))
15392 clutter_paint_volume_free (pv);
15393 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15394 "Effect (%s) failed to report a volume",
15395 _clutter_actor_get_debug_name (self),
15396 _clutter_actor_meta_get_debug_name (l->data));
15405 /* The public clutter_actor_get_paint_volume API returns a const
15406 * pointer since we return a pointer directly to the cached
15407 * PaintVolume associated with the actor and don't want the user to
15408 * inadvertently modify it, but for internal uses we sometimes need
15409 * access to the same PaintVolume but need to apply some book-keeping
15410 * modifications to it so we don't want a const pointer.
15412 static ClutterPaintVolume *
15413 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15415 ClutterActorPrivate *priv;
15419 if (priv->paint_volume_valid)
15420 clutter_paint_volume_free (&priv->paint_volume);
15422 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15424 priv->paint_volume_valid = TRUE;
15425 return &priv->paint_volume;
15429 priv->paint_volume_valid = FALSE;
15435 * clutter_actor_get_paint_volume:
15436 * @self: a #ClutterActor
15438 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15439 * when a paint volume can't be determined.
15441 * The paint volume is defined as the 3D space occupied by an actor
15442 * when being painted.
15444 * This function will call the <function>get_paint_volume()</function>
15445 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15446 * should not usually care about overriding the default implementation,
15447 * unless they are, for instance: painting outside their allocation, or
15448 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15451 * <note>2D actors overriding <function>get_paint_volume()</function>
15452 * ensure their volume has a depth of 0. (This will be true so long as
15453 * you don't call clutter_paint_volume_set_depth().)</note>
15455 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15456 * or %NULL if no volume could be determined. The returned pointer
15457 * is not guaranteed to be valid across multiple frames; if you want
15458 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15462 const ClutterPaintVolume *
15463 clutter_actor_get_paint_volume (ClutterActor *self)
15465 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15467 return _clutter_actor_get_paint_volume_mutable (self);
15471 * clutter_actor_get_transformed_paint_volume:
15472 * @self: a #ClutterActor
15473 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15474 * (or %NULL for the stage)
15476 * Retrieves the 3D paint volume of an actor like
15477 * clutter_actor_get_paint_volume() does (Please refer to the
15478 * documentation of clutter_actor_get_paint_volume() for more
15479 * details.) and it additionally transforms the paint volume into the
15480 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15481 * is passed for @relative_to_ancestor)
15483 * This can be used by containers that base their paint volume on
15484 * the volume of their children. Such containers can query the
15485 * transformed paint volume of all of its children and union them
15486 * together using clutter_paint_volume_union().
15488 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15489 * or %NULL if no volume could be determined. The returned pointer is
15490 * not guaranteed to be valid across multiple frames; if you wish to
15491 * keep it, you will have to copy it using clutter_paint_volume_copy().
15495 const ClutterPaintVolume *
15496 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15497 ClutterActor *relative_to_ancestor)
15499 const ClutterPaintVolume *volume;
15500 ClutterActor *stage;
15501 ClutterPaintVolume *transformed_volume;
15503 stage = _clutter_actor_get_stage_internal (self);
15504 if (G_UNLIKELY (stage == NULL))
15507 if (relative_to_ancestor == NULL)
15508 relative_to_ancestor = stage;
15510 volume = clutter_actor_get_paint_volume (self);
15511 if (volume == NULL)
15514 transformed_volume =
15515 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15517 _clutter_paint_volume_copy_static (volume, transformed_volume);
15519 _clutter_paint_volume_transform_relative (transformed_volume,
15520 relative_to_ancestor);
15522 return transformed_volume;
15526 * clutter_actor_get_paint_box:
15527 * @self: a #ClutterActor
15528 * @box: (out): return location for a #ClutterActorBox
15530 * Retrieves the paint volume of the passed #ClutterActor, and
15531 * transforms it into a 2D bounding box in stage coordinates.
15533 * This function is useful to determine the on screen area occupied by
15534 * the actor. The box is only an approximation and may often be
15535 * considerably larger due to the optimizations used to calculate the
15536 * box. The box is never smaller though, so it can reliably be used
15539 * There are times when a 2D paint box can't be determined, e.g.
15540 * because the actor isn't yet parented under a stage or because
15541 * the actor is unable to determine a paint volume.
15543 * Return value: %TRUE if a 2D paint box could be determined, else
15549 clutter_actor_get_paint_box (ClutterActor *self,
15550 ClutterActorBox *box)
15552 ClutterActor *stage;
15553 ClutterPaintVolume *pv;
15555 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15556 g_return_val_if_fail (box != NULL, FALSE);
15558 stage = _clutter_actor_get_stage_internal (self);
15559 if (G_UNLIKELY (!stage))
15562 pv = _clutter_actor_get_paint_volume_mutable (self);
15563 if (G_UNLIKELY (!pv))
15566 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15572 * clutter_actor_has_overlaps:
15573 * @self: A #ClutterActor
15575 * Asks the actor's implementation whether it may contain overlapping
15578 * For example; Clutter may use this to determine whether the painting
15579 * should be redirected to an offscreen buffer to correctly implement
15580 * the opacity property.
15582 * Custom actors can override the default response by implementing the
15583 * #ClutterActor <function>has_overlaps</function> virtual function. See
15584 * clutter_actor_set_offscreen_redirect() for more information.
15586 * Return value: %TRUE if the actor may have overlapping primitives, and
15592 clutter_actor_has_overlaps (ClutterActor *self)
15594 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15596 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15600 * clutter_actor_has_effects:
15601 * @self: A #ClutterActor
15603 * Returns whether the actor has any effects applied.
15605 * Return value: %TRUE if the actor has any effects,
15611 clutter_actor_has_effects (ClutterActor *self)
15613 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15615 if (self->priv->effects == NULL)
15618 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15622 * clutter_actor_has_constraints:
15623 * @self: A #ClutterActor
15625 * Returns whether the actor has any constraints applied.
15627 * Return value: %TRUE if the actor has any constraints,
15633 clutter_actor_has_constraints (ClutterActor *self)
15635 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15637 return self->priv->constraints != NULL;
15641 * clutter_actor_has_actions:
15642 * @self: A #ClutterActor
15644 * Returns whether the actor has any actions applied.
15646 * Return value: %TRUE if the actor has any actions,
15652 clutter_actor_has_actions (ClutterActor *self)
15654 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15656 return self->priv->actions != NULL;
15660 * clutter_actor_get_n_children:
15661 * @self: a #ClutterActor
15663 * Retrieves the number of children of @self.
15665 * Return value: the number of children of an actor
15670 clutter_actor_get_n_children (ClutterActor *self)
15672 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15674 return self->priv->n_children;
15678 * clutter_actor_get_child_at_index:
15679 * @self: a #ClutterActor
15680 * @index_: the position in the list of children
15682 * Retrieves the actor at the given @index_ inside the list of
15683 * children of @self.
15685 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15690 clutter_actor_get_child_at_index (ClutterActor *self,
15693 ClutterActor *iter;
15696 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15697 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15699 for (iter = self->priv->first_child, i = 0;
15700 iter != NULL && i < index_;
15701 iter = iter->priv->next_sibling, i += 1)
15708 * _clutter_actor_foreach_child:
15709 * @actor: The actor whos children you want to iterate
15710 * @callback: The function to call for each child
15711 * @user_data: Private data to pass to @callback
15713 * Calls a given @callback once for each child of the specified @actor and
15714 * passing the @user_data pointer each time.
15716 * Return value: returns %TRUE if all children were iterated, else
15717 * %FALSE if a callback broke out of iteration early.
15720 _clutter_actor_foreach_child (ClutterActor *self,
15721 ClutterForeachCallback callback,
15722 gpointer user_data)
15724 ClutterActorPrivate *priv = self->priv;
15725 ClutterActor *iter;
15728 for (cont = TRUE, iter = priv->first_child;
15729 cont && iter != NULL;
15730 iter = iter->priv->next_sibling)
15732 cont = callback (iter, user_data);
15739 /* For debugging purposes this gives us a simple way to print out
15740 * the scenegraph e.g in gdb using:
15742 * _clutter_actor_traverse (stage,
15744 * clutter_debug_print_actor_cb,
15749 static ClutterActorTraverseVisitFlags
15750 clutter_debug_print_actor_cb (ClutterActor *actor,
15754 g_print ("%*s%s:%p\n",
15756 _clutter_actor_get_debug_name (actor),
15759 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15764 _clutter_actor_traverse_breadth (ClutterActor *actor,
15765 ClutterTraverseCallback callback,
15766 gpointer user_data)
15768 GQueue *queue = g_queue_new ();
15769 ClutterActor dummy;
15770 int current_depth = 0;
15772 g_queue_push_tail (queue, actor);
15773 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15775 while ((actor = g_queue_pop_head (queue)))
15777 ClutterActorTraverseVisitFlags flags;
15779 if (actor == &dummy)
15782 g_queue_push_tail (queue, &dummy);
15786 flags = callback (actor, current_depth, user_data);
15787 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15789 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15791 ClutterActor *iter;
15793 for (iter = actor->priv->first_child;
15795 iter = iter->priv->next_sibling)
15797 g_queue_push_tail (queue, iter);
15802 g_queue_free (queue);
15805 static ClutterActorTraverseVisitFlags
15806 _clutter_actor_traverse_depth (ClutterActor *actor,
15807 ClutterTraverseCallback before_children_callback,
15808 ClutterTraverseCallback after_children_callback,
15810 gpointer user_data)
15812 ClutterActorTraverseVisitFlags flags;
15814 flags = before_children_callback (actor, current_depth, user_data);
15815 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15816 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15818 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15820 ClutterActor *iter;
15822 for (iter = actor->priv->first_child;
15824 iter = iter->priv->next_sibling)
15826 flags = _clutter_actor_traverse_depth (iter,
15827 before_children_callback,
15828 after_children_callback,
15832 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15833 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15837 if (after_children_callback)
15838 return after_children_callback (actor, current_depth, user_data);
15840 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15843 /* _clutter_actor_traverse:
15844 * @actor: The actor to start traversing the graph from
15845 * @flags: These flags may affect how the traversal is done
15846 * @before_children_callback: A function to call before visiting the
15847 * children of the current actor.
15848 * @after_children_callback: A function to call after visiting the
15849 * children of the current actor. (Ignored if
15850 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15851 * @user_data: The private data to pass to the callbacks
15853 * Traverses the scenegraph starting at the specified @actor and
15854 * descending through all its children and its children's children.
15855 * For each actor traversed @before_children_callback and
15856 * @after_children_callback are called with the specified
15857 * @user_data, before and after visiting that actor's children.
15859 * The callbacks can return flags that affect the ongoing traversal
15860 * such as by skipping over an actors children or bailing out of
15861 * any further traversing.
15864 _clutter_actor_traverse (ClutterActor *actor,
15865 ClutterActorTraverseFlags flags,
15866 ClutterTraverseCallback before_children_callback,
15867 ClutterTraverseCallback after_children_callback,
15868 gpointer user_data)
15870 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15871 _clutter_actor_traverse_breadth (actor,
15872 before_children_callback,
15874 else /* DEPTH_FIRST */
15875 _clutter_actor_traverse_depth (actor,
15876 before_children_callback,
15877 after_children_callback,
15878 0, /* start depth */
15883 on_layout_manager_changed (ClutterLayoutManager *manager,
15884 ClutterActor *self)
15886 clutter_actor_queue_relayout (self);
15890 * clutter_actor_set_layout_manager:
15891 * @self: a #ClutterActor
15892 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15894 * Sets the #ClutterLayoutManager delegate object that will be used to
15895 * lay out the children of @self.
15897 * The #ClutterActor will take a reference on the passed @manager which
15898 * will be released either when the layout manager is removed, or when
15899 * the actor is destroyed.
15904 clutter_actor_set_layout_manager (ClutterActor *self,
15905 ClutterLayoutManager *manager)
15907 ClutterActorPrivate *priv;
15909 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15910 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15914 if (priv->layout_manager != NULL)
15916 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15917 G_CALLBACK (on_layout_manager_changed),
15919 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15920 g_object_unref (priv->layout_manager);
15923 priv->layout_manager = manager;
15925 if (priv->layout_manager != NULL)
15927 g_object_ref_sink (priv->layout_manager);
15928 clutter_layout_manager_set_container (priv->layout_manager,
15929 CLUTTER_CONTAINER (self));
15930 g_signal_connect (priv->layout_manager, "layout-changed",
15931 G_CALLBACK (on_layout_manager_changed),
15935 clutter_actor_queue_relayout (self);
15937 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15941 * clutter_actor_get_layout_manager:
15942 * @self: a #ClutterActor
15944 * Retrieves the #ClutterLayoutManager used by @self.
15946 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15951 ClutterLayoutManager *
15952 clutter_actor_get_layout_manager (ClutterActor *self)
15954 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15956 return self->priv->layout_manager;
15959 static const ClutterLayoutInfo default_layout_info = {
15962 { 0, 0, 0, 0 }, /* margin */
15963 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
15964 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
15965 0.f, 0.f, /* min_width, natural_width */
15966 0.f, 0.f, /* natual_width, natural_height */
15970 layout_info_free (gpointer data)
15972 if (G_LIKELY (data != NULL))
15973 g_slice_free (ClutterLayoutInfo, data);
15977 * _clutter_actor_get_layout_info:
15978 * @self: a #ClutterActor
15980 * Retrieves a pointer to the ClutterLayoutInfo structure.
15982 * If the actor does not have a ClutterLayoutInfo associated to it, one
15983 * will be created and initialized to the default values.
15985 * This function should be used for setters.
15987 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15990 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15992 ClutterLayoutInfo *
15993 _clutter_actor_get_layout_info (ClutterActor *self)
15995 ClutterLayoutInfo *retval;
15997 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15998 if (retval == NULL)
16000 retval = g_slice_new (ClutterLayoutInfo);
16002 *retval = default_layout_info;
16004 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16013 * _clutter_actor_get_layout_info_or_defaults:
16014 * @self: a #ClutterActor
16016 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16018 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16019 * then the default structure will be returned.
16021 * This function should only be used for getters.
16023 * Return value: a const pointer to the ClutterLayoutInfo structure
16025 const ClutterLayoutInfo *
16026 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16028 const ClutterLayoutInfo *info;
16030 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16032 return &default_layout_info;
16038 * clutter_actor_set_x_align:
16039 * @self: a #ClutterActor
16040 * @x_align: the horizontal alignment policy
16042 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16043 * actor received extra horizontal space.
16045 * See also the #ClutterActor:x-align property.
16050 clutter_actor_set_x_align (ClutterActor *self,
16051 ClutterActorAlign x_align)
16053 ClutterLayoutInfo *info;
16055 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16057 info = _clutter_actor_get_layout_info (self);
16059 if (info->x_align != x_align)
16061 info->x_align = x_align;
16063 clutter_actor_queue_relayout (self);
16065 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16070 * clutter_actor_get_x_align:
16071 * @self: a #ClutterActor
16073 * Retrieves the horizontal alignment policy set using
16074 * clutter_actor_set_x_align().
16076 * Return value: the horizontal alignment policy.
16081 clutter_actor_get_x_align (ClutterActor *self)
16083 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16085 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16089 * clutter_actor_set_y_align:
16090 * @self: a #ClutterActor
16091 * @y_align: the vertical alignment policy
16093 * Sets the vertical alignment policy of a #ClutterActor, in case the
16094 * actor received extra vertical space.
16096 * See also the #ClutterActor:y-align property.
16101 clutter_actor_set_y_align (ClutterActor *self,
16102 ClutterActorAlign y_align)
16104 ClutterLayoutInfo *info;
16106 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16108 info = _clutter_actor_get_layout_info (self);
16110 if (info->y_align != y_align)
16112 info->y_align = y_align;
16114 clutter_actor_queue_relayout (self);
16116 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16121 * clutter_actor_get_y_align:
16122 * @self: a #ClutterActor
16124 * Retrieves the vertical alignment policy set using
16125 * clutter_actor_set_y_align().
16127 * Return value: the vertical alignment policy.
16132 clutter_actor_get_y_align (ClutterActor *self)
16134 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16136 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16141 * clutter_margin_new:
16143 * Creates a new #ClutterMargin.
16145 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16146 * clutter_margin_free() to free the resources associated with it when
16152 clutter_margin_new (void)
16154 return g_slice_new0 (ClutterMargin);
16158 * clutter_margin_copy:
16159 * @margin_: a #ClutterMargin
16161 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16162 * the newly created structure.
16164 * Return value: (transfer full): a copy of the #ClutterMargin.
16169 clutter_margin_copy (const ClutterMargin *margin_)
16171 if (G_LIKELY (margin_ != NULL))
16172 return g_slice_dup (ClutterMargin, margin_);
16178 * clutter_margin_free:
16179 * @margin_: a #ClutterMargin
16181 * Frees the resources allocated by clutter_margin_new() and
16182 * clutter_margin_copy().
16187 clutter_margin_free (ClutterMargin *margin_)
16189 if (G_LIKELY (margin_ != NULL))
16190 g_slice_free (ClutterMargin, margin_);
16193 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16194 clutter_margin_copy,
16195 clutter_margin_free)
16198 * clutter_actor_set_margin:
16199 * @self: a #ClutterActor
16200 * @margin: a #ClutterMargin
16202 * Sets all the components of the margin of a #ClutterActor.
16207 clutter_actor_set_margin (ClutterActor *self,
16208 const ClutterMargin *margin)
16210 ClutterLayoutInfo *info;
16214 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16215 g_return_if_fail (margin != NULL);
16217 obj = G_OBJECT (self);
16220 g_object_freeze_notify (obj);
16222 info = _clutter_actor_get_layout_info (self);
16224 if (info->margin.top != margin->top)
16226 info->margin.top = margin->top;
16227 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16231 if (info->margin.right != margin->right)
16233 info->margin.right = margin->right;
16234 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16238 if (info->margin.bottom != margin->bottom)
16240 info->margin.bottom = margin->bottom;
16241 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16245 if (info->margin.left != margin->left)
16247 info->margin.left = margin->left;
16248 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16253 clutter_actor_queue_relayout (self);
16255 g_object_thaw_notify (obj);
16259 * clutter_actor_get_margin:
16260 * @self: a #ClutterActor
16261 * @margin: (out caller-allocates): return location for a #ClutterMargin
16263 * Retrieves all the components of the margin of a #ClutterActor.
16268 clutter_actor_get_margin (ClutterActor *self,
16269 ClutterMargin *margin)
16271 const ClutterLayoutInfo *info;
16273 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16274 g_return_if_fail (margin != NULL);
16276 info = _clutter_actor_get_layout_info_or_defaults (self);
16278 *margin = info->margin;
16282 * clutter_actor_set_margin_top:
16283 * @self: a #ClutterActor
16284 * @margin: the top margin
16286 * Sets the margin from the top of a #ClutterActor.
16291 clutter_actor_set_margin_top (ClutterActor *self,
16294 ClutterLayoutInfo *info;
16296 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16297 g_return_if_fail (margin >= 0.f);
16299 info = _clutter_actor_get_layout_info (self);
16301 if (info->margin.top == margin)
16304 info->margin.top = margin;
16306 clutter_actor_queue_relayout (self);
16308 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16312 * clutter_actor_get_margin_top:
16313 * @self: a #ClutterActor
16315 * Retrieves the top margin of a #ClutterActor.
16317 * Return value: the top margin
16322 clutter_actor_get_margin_top (ClutterActor *self)
16324 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16326 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16330 * clutter_actor_set_margin_bottom:
16331 * @self: a #ClutterActor
16332 * @margin: the bottom margin
16334 * Sets the margin from the bottom of a #ClutterActor.
16339 clutter_actor_set_margin_bottom (ClutterActor *self,
16342 ClutterLayoutInfo *info;
16344 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16345 g_return_if_fail (margin >= 0.f);
16347 info = _clutter_actor_get_layout_info (self);
16349 if (info->margin.bottom == margin)
16352 info->margin.bottom = margin;
16354 clutter_actor_queue_relayout (self);
16356 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16360 * clutter_actor_get_margin_bottom:
16361 * @self: a #ClutterActor
16363 * Retrieves the bottom margin of a #ClutterActor.
16365 * Return value: the bottom margin
16370 clutter_actor_get_margin_bottom (ClutterActor *self)
16372 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16374 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16378 * clutter_actor_set_margin_left:
16379 * @self: a #ClutterActor
16380 * @margin: the left margin
16382 * Sets the margin from the left of a #ClutterActor.
16387 clutter_actor_set_margin_left (ClutterActor *self,
16390 ClutterLayoutInfo *info;
16392 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16393 g_return_if_fail (margin >= 0.f);
16395 info = _clutter_actor_get_layout_info (self);
16397 if (info->margin.left == margin)
16400 info->margin.left = margin;
16402 clutter_actor_queue_relayout (self);
16404 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16408 * clutter_actor_get_margin_left:
16409 * @self: a #ClutterActor
16411 * Retrieves the left margin of a #ClutterActor.
16413 * Return value: the left margin
16418 clutter_actor_get_margin_left (ClutterActor *self)
16420 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16422 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16426 * clutter_actor_set_margin_right:
16427 * @self: a #ClutterActor
16428 * @margin: the right margin
16430 * Sets the margin from the right of a #ClutterActor.
16435 clutter_actor_set_margin_right (ClutterActor *self,
16438 ClutterLayoutInfo *info;
16440 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16441 g_return_if_fail (margin >= 0.f);
16443 info = _clutter_actor_get_layout_info (self);
16445 if (info->margin.right == margin)
16448 info->margin.right = margin;
16450 clutter_actor_queue_relayout (self);
16452 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16456 * clutter_actor_get_margin_right:
16457 * @self: a #ClutterActor
16459 * Retrieves the right margin of a #ClutterActor.
16461 * Return value: the right margin
16466 clutter_actor_get_margin_right (ClutterActor *self)
16468 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16470 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16474 clutter_actor_set_background_color_internal (ClutterActor *self,
16475 const ClutterColor *color)
16477 ClutterActorPrivate *priv = self->priv;
16480 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16483 obj = G_OBJECT (self);
16485 priv->bg_color = *color;
16486 priv->bg_color_set = TRUE;
16488 clutter_actor_queue_redraw (self);
16490 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16491 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16495 * clutter_actor_set_background_color:
16496 * @self: a #ClutterActor
16497 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16500 * Sets the background color of a #ClutterActor.
16502 * The background color will be used to cover the whole allocation of the
16503 * actor. The default background color of an actor is transparent.
16505 * To check whether an actor has a background color, you can use the
16506 * #ClutterActor:background-color-set actor property.
16508 * The #ClutterActor:background-color property is animatable.
16513 clutter_actor_set_background_color (ClutterActor *self,
16514 const ClutterColor *color)
16516 ClutterActorPrivate *priv;
16518 GParamSpec *bg_color_pspec;
16520 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16522 obj = G_OBJECT (self);
16528 priv->bg_color_set = FALSE;
16529 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16530 clutter_actor_queue_redraw (self);
16534 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16535 if (clutter_actor_get_easing_duration (self) != 0)
16537 ClutterTransition *transition;
16539 transition = _clutter_actor_get_transition (self, bg_color_pspec);
16540 if (transition == NULL)
16542 transition = _clutter_actor_create_transition (self, bg_color_pspec,
16545 clutter_timeline_start (CLUTTER_TIMELINE (transition));
16548 _clutter_actor_update_transition (self, bg_color_pspec, color);
16550 clutter_actor_queue_redraw (self);
16553 clutter_actor_set_background_color_internal (self, color);
16557 * clutter_actor_get_background_color:
16558 * @self: a #ClutterActor
16559 * @color: (out caller-allocates): return location for a #ClutterColor
16561 * Retrieves the color set using clutter_actor_set_background_color().
16566 clutter_actor_get_background_color (ClutterActor *self,
16567 ClutterColor *color)
16569 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16570 g_return_if_fail (color != NULL);
16572 *color = self->priv->bg_color;
16576 * clutter_actor_get_previous_sibling:
16577 * @self: a #ClutterActor
16579 * Retrieves the sibling of @self that comes before it in the list
16580 * of children of @self's parent.
16582 * The returned pointer is only valid until the scene graph changes; it
16583 * is not safe to modify the list of children of @self while iterating
16586 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16591 clutter_actor_get_previous_sibling (ClutterActor *self)
16593 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16595 return self->priv->prev_sibling;
16599 * clutter_actor_get_next_sibling:
16600 * @self: a #ClutterActor
16602 * Retrieves the sibling of @self that comes after it in the list
16603 * of children of @self's parent.
16605 * The returned pointer is only valid until the scene graph changes; it
16606 * is not safe to modify the list of children of @self while iterating
16609 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16614 clutter_actor_get_next_sibling (ClutterActor *self)
16616 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16618 return self->priv->next_sibling;
16622 * clutter_actor_get_first_child:
16623 * @self: a #ClutterActor
16625 * Retrieves the first child of @self.
16627 * The returned pointer is only valid until the scene graph changes; it
16628 * is not safe to modify the list of children of @self while iterating
16631 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16636 clutter_actor_get_first_child (ClutterActor *self)
16638 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16640 return self->priv->first_child;
16644 * clutter_actor_get_last_child:
16645 * @self: a #ClutterActor
16647 * Retrieves the last child of @self.
16649 * The returned pointer is only valid until the scene graph changes; it
16650 * is not safe to modify the list of children of @self while iterating
16653 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16658 clutter_actor_get_last_child (ClutterActor *self)
16660 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16662 return self->priv->last_child;
16665 /* easy way to have properly named fields instead of the dummy ones
16666 * we use in the public structure
16668 typedef struct _RealActorIter
16670 ClutterActor *root; /* dummy1 */
16671 ClutterActor *current; /* dummy2 */
16672 gpointer padding_1; /* dummy3 */
16673 gint age; /* dummy4 */
16674 gpointer padding_2; /* dummy5 */
16678 * clutter_actor_iter_init:
16679 * @iter: a #ClutterActorIter
16680 * @root: a #ClutterActor
16682 * Initializes a #ClutterActorIter, which can then be used to iterate
16683 * efficiently over a section of the scene graph, and associates it
16686 * Modifying the scene graph section that contains @root will invalidate
16690 * ClutterActorIter iter;
16691 * ClutterActor *child;
16693 * clutter_actor_iter_init (&iter, container);
16694 * while (clutter_actor_iter_next (&iter, &child))
16696 * /* do something with child */
16703 clutter_actor_iter_init (ClutterActorIter *iter,
16704 ClutterActor *root)
16706 RealActorIter *ri = (RealActorIter *) iter;
16708 g_return_if_fail (iter != NULL);
16709 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16712 ri->current = NULL;
16713 ri->age = root->priv->age;
16717 * clutter_actor_iter_next:
16718 * @iter: a #ClutterActorIter
16719 * @child: (out): return location for a #ClutterActor
16721 * Advances the @iter and retrieves the next child of the root #ClutterActor
16722 * that was used to initialize the #ClutterActorIterator.
16724 * If the iterator can advance, this function returns %TRUE and sets the
16727 * If the iterator cannot advance, this function returns %FALSE, and
16728 * the contents of @child are undefined.
16730 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16735 clutter_actor_iter_next (ClutterActorIter *iter,
16736 ClutterActor **child)
16738 RealActorIter *ri = (RealActorIter *) iter;
16740 g_return_val_if_fail (iter != NULL, FALSE);
16741 g_return_val_if_fail (ri->root != NULL, FALSE);
16742 #ifndef G_DISABLE_ASSERT
16743 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16746 if (ri->current == NULL)
16747 ri->current = ri->root->priv->first_child;
16749 ri->current = ri->current->priv->next_sibling;
16752 *child = ri->current;
16754 return ri->current != NULL;
16758 * clutter_actor_iter_prev:
16759 * @iter: a #ClutterActorIter
16760 * @child: (out): return location for a #ClutterActor
16762 * Advances the @iter and retrieves the previous child of the root
16763 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16765 * If the iterator can advance, this function returns %TRUE and sets the
16768 * If the iterator cannot advance, this function returns %FALSE, and
16769 * the contents of @child are undefined.
16771 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16776 clutter_actor_iter_prev (ClutterActorIter *iter,
16777 ClutterActor **child)
16779 RealActorIter *ri = (RealActorIter *) iter;
16781 g_return_val_if_fail (iter != NULL, FALSE);
16782 g_return_val_if_fail (ri->root != NULL, FALSE);
16783 #ifndef G_DISABLE_ASSERT
16784 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16787 if (ri->current == NULL)
16788 ri->current = ri->root->priv->last_child;
16790 ri->current = ri->current->priv->prev_sibling;
16793 *child = ri->current;
16795 return ri->current != NULL;
16799 * clutter_actor_iter_remove:
16800 * @iter: a #ClutterActorIter
16802 * Safely removes the #ClutterActor currently pointer to by the iterator
16805 * This function can only be called after clutter_actor_iter_next() or
16806 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16807 * than once for the same actor.
16809 * This function will call clutter_actor_remove_child() internally.
16814 clutter_actor_iter_remove (ClutterActorIter *iter)
16816 RealActorIter *ri = (RealActorIter *) iter;
16819 g_return_if_fail (iter != NULL);
16820 g_return_if_fail (ri->root != NULL);
16821 #ifndef G_DISABLE_ASSERT
16822 g_return_if_fail (ri->age == ri->root->priv->age);
16824 g_return_if_fail (ri->current != NULL);
16830 ri->current = cur->priv->prev_sibling;
16832 clutter_actor_remove_child_internal (ri->root, cur,
16833 REMOVE_CHILD_DEFAULT_FLAGS);
16840 * clutter_actor_iter_destroy:
16841 * @iter: a #ClutterActorIter
16843 * Safely destroys the #ClutterActor currently pointer to by the iterator
16846 * This function can only be called after clutter_actor_iter_next() or
16847 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16848 * than once for the same actor.
16850 * This function will call clutter_actor_destroy() internally.
16855 clutter_actor_iter_destroy (ClutterActorIter *iter)
16857 RealActorIter *ri = (RealActorIter *) iter;
16860 g_return_if_fail (iter != NULL);
16861 g_return_if_fail (ri->root != NULL);
16862 #ifndef G_DISABLE_ASSERT
16863 g_return_if_fail (ri->age == ri->root->priv->age);
16865 g_return_if_fail (ri->current != NULL);
16871 ri->current = cur->priv->prev_sibling;
16873 clutter_actor_destroy (cur);
16879 static const ClutterAnimationInfo default_animation_info = {
16880 NULL, /* transitions */
16882 NULL, /* cur_state */
16886 clutter_animation_info_free (gpointer data)
16890 ClutterAnimationInfo *info = data;
16892 if (info->transitions != NULL)
16893 g_hash_table_unref (info->transitions);
16895 if (info->states != NULL)
16896 g_array_unref (info->states);
16898 g_slice_free (ClutterAnimationInfo, info);
16902 const ClutterAnimationInfo *
16903 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16905 const ClutterAnimationInfo *res;
16906 GObject *obj = G_OBJECT (self);
16908 res = g_object_get_qdata (obj, quark_actor_animation_info);
16912 return &default_animation_info;
16915 ClutterAnimationInfo *
16916 _clutter_actor_get_animation_info (ClutterActor *self)
16918 GObject *obj = G_OBJECT (self);
16919 ClutterAnimationInfo *res;
16921 res = g_object_get_qdata (obj, quark_actor_animation_info);
16924 res = g_slice_new (ClutterAnimationInfo);
16926 *res = default_animation_info;
16928 g_object_set_qdata_full (obj, quark_actor_animation_info,
16930 clutter_animation_info_free);
16936 ClutterTransition *
16937 _clutter_actor_get_transition (ClutterActor *actor,
16940 const ClutterAnimationInfo *info;
16942 info = _clutter_actor_get_animation_info_or_defaults (actor);
16944 if (info->transitions == NULL)
16947 return g_hash_table_lookup (info->transitions, pspec->name);
16950 typedef struct _TransitionClosure
16952 ClutterActor *actor;
16953 ClutterTransition *transition;
16955 gulong completed_id;
16956 } TransitionClosure;
16959 transition_closure_free (gpointer data)
16961 if (G_LIKELY (data != NULL))
16963 TransitionClosure *clos = data;
16965 g_signal_handler_disconnect (clos->transition, clos->completed_id);
16966 g_free (clos->name);
16968 g_slice_free (TransitionClosure, clos);
16973 on_transition_completed (ClutterTransition *transition,
16974 TransitionClosure *clos)
16976 ClutterActor *actor = clos->actor;
16977 ClutterAnimationInfo *info;
16979 info = _clutter_actor_get_animation_info (actor);
16981 /* this will take care of cleaning clos for us */
16982 g_hash_table_remove (info->transitions, clos->name);
16984 /* if it's the last transition then we clean up */
16985 if (g_hash_table_size (info->transitions) == 0)
16987 g_hash_table_unref (info->transitions);
16988 info->transitions = NULL;
16990 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
16991 _clutter_actor_get_debug_name (actor));
16993 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
16998 _clutter_actor_update_transition (ClutterActor *actor,
17002 TransitionClosure *clos;
17003 ClutterInterval *interval;
17004 const ClutterAnimationInfo *info;
17007 GValue initial = G_VALUE_INIT;
17008 GValue final = G_VALUE_INIT;
17009 char *error = NULL;
17011 info = _clutter_actor_get_animation_info_or_defaults (actor);
17013 if (info->transitions == NULL)
17016 clos = g_hash_table_lookup (info->transitions, pspec->name);
17020 va_start (var_args, pspec);
17022 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17024 g_value_init (&initial, ptype);
17025 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17029 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17032 g_critical ("%s: %s", G_STRLOC, error);
17037 interval = clutter_transition_get_interval (clos->transition);
17038 clutter_interval_set_initial_value (interval, &initial);
17039 clutter_interval_set_final_value (interval, &final);
17041 clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
17044 g_value_unset (&initial);
17045 g_value_unset (&final);
17051 * _clutter_actor_create_transition:
17052 * @actor: a #ClutterActor
17053 * @pspec: the property used for the transition
17054 * @...: initial and final state
17056 * Creates a #ClutterTransition for the property represented by @pspec.
17058 * Return value: a #ClutterTransition
17060 ClutterTransition *
17061 _clutter_actor_create_transition (ClutterActor *actor,
17065 ClutterAnimationInfo *info;
17066 ClutterTransition *res = NULL;
17067 gboolean call_restore = FALSE;
17068 TransitionClosure *clos;
17071 info = _clutter_actor_get_animation_info (actor);
17073 if (info->states == NULL)
17075 clutter_actor_save_easing_state (actor);
17076 call_restore = TRUE;
17079 if (info->transitions == NULL)
17080 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17082 transition_closure_free);
17084 va_start (var_args, pspec);
17086 clos = g_hash_table_lookup (info->transitions, pspec->name);
17089 ClutterInterval *interval;
17090 GValue initial = G_VALUE_INIT;
17091 GValue final = G_VALUE_INIT;
17095 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17097 G_VALUE_COLLECT_INIT (&initial, ptype,
17102 g_critical ("%s: %s", G_STRLOC, error);
17107 G_VALUE_COLLECT_INIT (&final, ptype,
17113 g_critical ("%s: %s", G_STRLOC, error);
17114 g_value_unset (&initial);
17119 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17121 g_value_unset (&initial);
17122 g_value_unset (&final);
17124 res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17127 clutter_transition_set_interval (res, interval);
17128 clutter_transition_set_remove_on_complete (res, TRUE);
17130 clutter_actor_add_transition (actor, pspec->name, res);
17133 res = clos->transition;
17137 clutter_actor_restore_easing_state (actor);
17145 * clutter_actor_add_transition:
17146 * @self: a #ClutterActor
17147 * @name: the name of the transition to add
17148 * @transition: the #ClutterTransition to add
17150 * Adds a @transition to the #ClutterActor's list of animations.
17152 * The @name string is a per-actor unique identifier of the @transition: only
17153 * one #ClutterTransition can be associated to the specified @name.
17155 * The @transition will be given the easing duration, mode, and delay
17156 * associated to the actor's current easing state; it is possible to modify
17157 * these values after calling clutter_actor_add_transition().
17159 * This function is usually called implicitly when modifying an animatable
17165 clutter_actor_add_transition (ClutterActor *self,
17167 ClutterTransition *transition)
17169 ClutterTimeline *timeline;
17170 TransitionClosure *clos;
17171 ClutterAnimationInfo *info;
17173 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17174 g_return_if_fail (name != NULL);
17175 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17177 info = _clutter_actor_get_animation_info (self);
17179 if (info->cur_state == NULL)
17181 g_warning ("No easing state is defined for the actor '%s'; you "
17182 "must call clutter_actor_save_easing_state() before "
17183 "calling clutter_actor_add_transition().",
17184 _clutter_actor_get_debug_name (self));
17188 if (info->transitions == NULL)
17189 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17191 transition_closure_free);
17193 if (g_hash_table_lookup (info->transitions, name) != NULL)
17195 g_warning ("A transition with name '%s' already exists for "
17198 _clutter_actor_get_debug_name (self));
17202 timeline = CLUTTER_TIMELINE (transition);
17204 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17205 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17206 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17208 clos = g_slice_new (TransitionClosure);
17209 clos->actor = self;
17210 clos->transition = transition;
17211 clos->name = g_strdup (name);
17212 clos->completed_id = g_signal_connect (timeline, "completed",
17213 G_CALLBACK (on_transition_completed),
17216 g_hash_table_insert (info->transitions, clos->name, clos);
17220 * clutter_actor_remove_transition:
17221 * @self: a #ClutterActor
17222 * @name: the name of the transition to remove
17224 * Removes the transition stored inside a #ClutterActor using @name
17230 clutter_actor_remove_transition (ClutterActor *self,
17233 const ClutterAnimationInfo *info;
17235 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17236 g_return_if_fail (name != NULL);
17238 info = _clutter_actor_get_animation_info_or_defaults (self);
17240 if (info->transitions == NULL)
17243 g_hash_table_remove (info->transitions, name);
17247 * clutter_actor_remove_all_transitions:
17248 * @self: a #ClutterActor
17250 * Removes all transitions associated to @self.
17255 clutter_actor_remove_all_transitions (ClutterActor *self)
17257 const ClutterAnimationInfo *info;
17259 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17261 info = _clutter_actor_get_animation_info_or_defaults (self);
17262 if (info->transitions == NULL)
17265 g_hash_table_remove_all (info->transitions);
17269 * clutter_actor_set_easing_duration:
17270 * @self: a #ClutterActor
17271 * @msecs: the duration of the easing, or %NULL
17273 * Sets the duration of the tweening for animatable properties
17274 * of @self for the current easing state.
17279 clutter_actor_set_easing_duration (ClutterActor *self,
17282 ClutterAnimationInfo *info;
17284 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17286 info = _clutter_actor_get_animation_info (self);
17288 if (info->cur_state == NULL)
17290 g_warning ("You must call clutter_actor_save_easing_state() prior "
17291 "to calling clutter_actor_set_easing_duration().");
17295 if (info->cur_state->easing_duration != msecs)
17296 info->cur_state->easing_duration = msecs;
17300 * clutter_actor_get_easing_duration:
17301 * @self: a #ClutterActor
17303 * Retrieves the duration of the tweening for animatable
17304 * properties of @self for the current easing state.
17306 * Return value: the duration of the tweening, in milliseconds
17311 clutter_actor_get_easing_duration (ClutterActor *self)
17313 const ClutterAnimationInfo *info;
17315 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17317 info = _clutter_actor_get_animation_info_or_defaults (self);
17319 if (info->cur_state != NULL)
17320 return info->cur_state->easing_duration;
17326 * clutter_actor_set_easing_mode:
17327 * @self: a #ClutterActor
17328 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17330 * Sets the easing mode for the tweening of animatable properties
17336 clutter_actor_set_easing_mode (ClutterActor *self,
17337 ClutterAnimationMode mode)
17339 ClutterAnimationInfo *info;
17341 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17342 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17343 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17345 info = _clutter_actor_get_animation_info (self);
17347 if (info->cur_state == NULL)
17349 g_warning ("You must call clutter_actor_save_easing_state() prior "
17350 "to calling clutter_actor_set_easing_mode().");
17354 if (info->cur_state->easing_mode != mode)
17355 info->cur_state->easing_mode = mode;
17359 * clutter_actor_get_easing_mode:
17360 * @self: a #ClutterActor
17362 * Retrieves the easing mode for the tweening of animatable properties
17363 * of @self for the current easing state.
17365 * Return value: an easing mode
17369 ClutterAnimationMode
17370 clutter_actor_get_easing_mode (ClutterActor *self)
17372 const ClutterAnimationInfo *info;
17374 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17376 info = _clutter_actor_get_animation_info_or_defaults (self);
17378 if (info->cur_state != NULL)
17379 return info->cur_state->easing_mode;
17381 return CLUTTER_EASE_OUT_CUBIC;
17385 * clutter_actor_set_easing_delay:
17386 * @self: a #ClutterActor
17387 * @msecs: the delay before the start of the tweening, in milliseconds
17389 * Sets the delay that should be applied before tweening animatable
17395 clutter_actor_set_easing_delay (ClutterActor *self,
17398 ClutterAnimationInfo *info;
17400 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17402 info = _clutter_actor_get_animation_info (self);
17404 if (info->cur_state == NULL)
17406 g_warning ("You must call clutter_actor_save_easing_state() prior "
17407 "to calling clutter_actor_set_easing_delay().");
17411 if (info->cur_state->easing_delay != msecs)
17412 info->cur_state->easing_delay = msecs;
17416 * clutter_actor_get_easing_delay:
17417 * @self: a #ClutterActor
17419 * Retrieves the delay that should be applied when tweening animatable
17422 * Return value: a delay, in milliseconds
17427 clutter_actor_get_easing_delay (ClutterActor *self)
17429 const ClutterAnimationInfo *info;
17431 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17433 info = _clutter_actor_get_animation_info_or_defaults (self);
17435 if (info->cur_state != NULL)
17436 return info->cur_state->easing_delay;
17442 * clutter_actor_get_transition:
17443 * @self: a #ClutterActor
17444 * @name: the name of the transition
17446 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17447 * transition @name.
17449 * Transitions created for animatable properties use the name of the
17450 * property itself, for instance the code below:
17453 * clutter_actor_set_easing_duration (actor, 1000);
17454 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17456 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17457 * g_signal_connect (transition, "completed",
17458 * G_CALLBACK (on_transition_complete),
17462 * will call the <function>on_transition_complete</function> callback when
17463 * the transition is complete.
17465 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17466 * was found to match the passed name; the returned instance is owned
17467 * by Clutter and it should not be freed
17471 ClutterTransition *
17472 clutter_actor_get_transition (ClutterActor *self,
17475 TransitionClosure *clos;
17476 const ClutterAnimationInfo *info;
17478 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17479 g_return_val_if_fail (name != NULL, NULL);
17481 info = _clutter_actor_get_animation_info_or_defaults (self);
17483 if (info->transitions == NULL)
17486 clos = g_hash_table_lookup (info->transitions, name);
17490 return clos->transition;
17494 * clutter_actor_save_easing_state:
17495 * @self: a #ClutterActor
17497 * Saves the current easing state for animatable properties, and creates
17498 * a new state with the default values for easing mode and duration.
17503 clutter_actor_save_easing_state (ClutterActor *self)
17505 ClutterAnimationInfo *info;
17508 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17510 info = _clutter_actor_get_animation_info (self);
17512 if (info->states == NULL)
17513 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17515 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17516 new_state.easing_duration = 250;
17517 new_state.easing_delay = 0;
17519 g_array_append_val (info->states, new_state);
17521 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17525 * clutter_actor_restore_easing_state:
17526 * @self: a #ClutterActor
17528 * Restores the easing state as it was prior to a call to
17529 * clutter_actor_save_easing_state().
17534 clutter_actor_restore_easing_state (ClutterActor *self)
17536 ClutterAnimationInfo *info;
17538 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17540 info = _clutter_actor_get_animation_info (self);
17542 if (info->states == NULL)
17544 g_critical ("The function clutter_actor_restore_easing_state() has "
17545 "called without a previous call to "
17546 "clutter_actor_save_easing_state().");
17550 g_array_remove_index (info->states, info->states->len - 1);
17552 if (info->states->len > 0)
17553 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17556 g_array_unref (info->states);
17557 info->states = NULL;
17562 * clutter_actor_set_content:
17563 * @self: a #ClutterActor
17564 * @content: (allow-none): a #ClutterContent, or %NULL
17566 * Sets the contents of a #ClutterActor.
17571 clutter_actor_set_content (ClutterActor *self,
17572 ClutterContent *content)
17574 ClutterActorPrivate *priv;
17576 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17577 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17581 if (priv->content != NULL)
17583 _clutter_content_detached (priv->content, self);
17584 g_object_unref (priv->content);
17587 priv->content = content;
17589 if (priv->content != NULL)
17591 g_object_ref (priv->content);
17592 _clutter_content_attached (priv->content, self);
17595 /* given that the content is always painted within the allocation,
17596 * we only need to queue a redraw here
17598 clutter_actor_queue_redraw (self);
17600 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17602 /* if the content gravity is not resize-fill, and the new content has a
17603 * different preferred size than the previous one, then the content box
17604 * may have been changed. since we compute that lazily, we just notify
17605 * here, and let whomever watches :content-box do whatever they need to
17608 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17609 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17613 * clutter_actor_get_content:
17614 * @self: a #ClutterActor
17616 * Retrieves the contents of @self.
17618 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17619 * or %NULL if none was set
17624 clutter_actor_get_content (ClutterActor *self)
17626 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17628 return self->priv->content;
17632 * clutter_actor_set_content_gravity:
17633 * @self: a #ClutterActor
17634 * @gravity: the #ClutterContentGravity
17636 * Sets the gravity of the #ClutterContent used by @self.
17638 * See the description of the #ClutterActor:content-gravity property for
17639 * more information.
17644 clutter_actor_set_content_gravity (ClutterActor *self,
17645 ClutterContentGravity gravity)
17647 ClutterActorPrivate *priv;
17649 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17653 if (priv->content_gravity == gravity)
17656 priv->content_gravity = gravity;
17658 clutter_actor_queue_redraw (self);
17660 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17661 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17665 * clutter_actor_get_content_gravity:
17666 * @self: a #ClutterActor
17668 * Retrieves the content gravity as set using
17669 * clutter_actor_get_content_gravity().
17671 * Return value: the content gravity
17675 ClutterContentGravity
17676 clutter_actor_get_content_gravity (ClutterActor *self)
17678 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17679 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17681 return self->priv->content_gravity;
17685 * clutter_actor_get_content_box:
17686 * @self: a #ClutterActor
17687 * @box: (out caller-allocates): the return location for the bounding
17688 * box for the #ClutterContent
17690 * Retrieves the bounding box for the #ClutterContent of @self.
17692 * The bounding box is relative to the actor's allocation.
17694 * If no #ClutterContent is set for @self, or if @self has not been
17695 * allocated yet, then the result is undefined.
17697 * The content box is guaranteed to be, at most, as big as the allocation
17698 * of the #ClutterActor.
17700 * If the #ClutterContent used by the actor has a preferred size, then
17701 * it is possible to modify the content box by using the
17702 * #ClutterActor:content-gravity property.
17707 clutter_actor_get_content_box (ClutterActor *self,
17708 ClutterActorBox *box)
17710 ClutterActorPrivate *priv;
17711 gfloat content_w, content_h;
17712 gfloat alloc_w, alloc_h;
17714 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17715 g_return_if_fail (box != NULL);
17721 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17722 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17724 if (priv->content == NULL)
17727 /* no need to do any more work */
17728 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17731 /* if the content does not have a preferred size then there is
17732 * no point in computing the content box
17734 if (!clutter_content_get_preferred_size (priv->content,
17742 switch (priv->content_gravity)
17744 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17745 box->x2 = box->x1 + MIN (content_w, alloc_w);
17746 box->y2 = box->y1 + MIN (content_h, alloc_h);
17749 case CLUTTER_CONTENT_GRAVITY_TOP:
17750 if (alloc_w > content_w)
17752 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17753 box->x2 = box->x1 + content_w;
17755 box->y2 = box->y1 + MIN (content_h, alloc_h);
17758 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17759 if (alloc_w > content_w)
17761 box->x1 += (alloc_w - content_w);
17762 box->x2 = box->x1 + content_w;
17764 box->y2 = box->y1 + MIN (content_h, alloc_h);
17767 case CLUTTER_CONTENT_GRAVITY_LEFT:
17768 box->x2 = box->x1 + MIN (content_w, alloc_w);
17769 if (alloc_h > content_h)
17771 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17772 box->y2 = box->y1 + content_h;
17776 case CLUTTER_CONTENT_GRAVITY_CENTER:
17777 if (alloc_w > content_w)
17779 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17780 box->x2 = box->x1 + content_w;
17782 if (alloc_h > content_h)
17784 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17785 box->y2 = box->y1 + content_h;
17789 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17790 if (alloc_w > content_w)
17792 box->x1 += (alloc_w - content_w);
17793 box->x2 = box->x1 + content_w;
17795 if (alloc_h > content_h)
17797 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17798 box->y2 = box->y1 + content_h;
17802 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17803 box->x2 = box->x1 + MIN (content_w, alloc_w);
17804 if (alloc_h > content_h)
17806 box->y1 += (alloc_h - content_h);
17807 box->y2 = box->y1 + content_h;
17811 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17812 if (alloc_w > content_w)
17814 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17815 box->x2 = box->x1 + content_w;
17817 if (alloc_h > content_h)
17819 box->y1 += (alloc_h - content_h);
17820 box->y2 = box->y1 + content_h;
17824 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17825 if (alloc_w > content_w)
17827 box->x1 += (alloc_w - content_w);
17828 box->x2 = box->x1 + content_w;
17830 if (alloc_h > content_h)
17832 box->y1 += (alloc_h - content_h);
17833 box->y2 = box->y1 + content_h;
17837 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17838 g_assert_not_reached ();
17841 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17843 double r_c = content_w / content_h;
17844 double r_a = alloc_w / alloc_h;
17853 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17854 box->y2 = box->y1 + (alloc_w * r_c);
17861 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17862 box->x2 = box->x1 + (alloc_h * r_c);
17872 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17873 box->x2 = box->x1 + (alloc_h * r_c);
17880 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17881 box->y2 = box->y1 + (alloc_w * r_c);
17890 * clutter_actor_set_content_scaling_filters:
17891 * @self: a #ClutterActor
17892 * @min_filter: the minification filter for the content
17893 * @mag_filter: the magnification filter for the content
17895 * Sets the minification and magnification filter to be applied when
17896 * scaling the #ClutterActor:content of a #ClutterActor.
17898 * The #ClutterActor:minification-filter will be used when reducing
17899 * the size of the content; the #ClutterActor:magnification-filter
17900 * will be used when increasing the size of the content.
17905 clutter_actor_set_content_scaling_filters (ClutterActor *self,
17906 ClutterScalingFilter min_filter,
17907 ClutterScalingFilter mag_filter)
17909 ClutterActorPrivate *priv;
17913 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17916 obj = G_OBJECT (self);
17918 g_object_freeze_notify (obj);
17922 if (priv->min_filter != min_filter)
17924 priv->min_filter = min_filter;
17927 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17930 if (priv->mag_filter != mag_filter)
17932 priv->mag_filter = mag_filter;
17935 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17939 clutter_actor_queue_redraw (self);
17941 g_object_thaw_notify (obj);
17945 * clutter_actor_get_content_scaling_filters:
17946 * @self: a #ClutterActor
17947 * @min_filter: (out) (allow-none): return location for the minification
17949 * @mag_filter: (out) (allow-none): return location for the magnification
17952 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
17957 clutter_actor_get_content_scaling_filters (ClutterActor *self,
17958 ClutterScalingFilter *min_filter,
17959 ClutterScalingFilter *mag_filter)
17961 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17963 if (min_filter != NULL)
17964 *min_filter = self->priv->min_filter;
17966 if (mag_filter != NULL)
17967 *mag_filter = self->priv->mag_filter;