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,
798 static guint actor_signals[LAST_SIGNAL] = { 0, };
800 static void clutter_container_iface_init (ClutterContainerIface *iface);
801 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
802 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
803 static void atk_implementor_iface_init (AtkImplementorIface *iface);
805 /* These setters are all static for now, maybe they should be in the
806 * public API, but they are perhaps obscure enough to leave only as
809 static void clutter_actor_set_min_width (ClutterActor *self,
811 static void clutter_actor_set_min_height (ClutterActor *self,
813 static void clutter_actor_set_natural_width (ClutterActor *self,
814 gfloat natural_width);
815 static void clutter_actor_set_natural_height (ClutterActor *self,
816 gfloat natural_height);
817 static void clutter_actor_set_min_width_set (ClutterActor *self,
818 gboolean use_min_width);
819 static void clutter_actor_set_min_height_set (ClutterActor *self,
820 gboolean use_min_height);
821 static void clutter_actor_set_natural_width_set (ClutterActor *self,
822 gboolean use_natural_width);
823 static void clutter_actor_set_natural_height_set (ClutterActor *self,
824 gboolean use_natural_height);
825 static void clutter_actor_update_map_state (ClutterActor *self,
826 MapStateChange change);
827 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
829 /* Helper routines for managing anchor coords */
830 static void clutter_anchor_coord_get_units (ClutterActor *self,
831 const AnchorCoord *coord,
835 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
840 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
841 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
842 ClutterGravity gravity);
844 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
846 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
848 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
849 ClutterActor *ancestor,
852 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
854 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
856 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
857 const ClutterColor *color);
859 static void on_layout_manager_changed (ClutterLayoutManager *manager,
862 /* Helper macro which translates by the anchor coord, applies the
863 given transformation and then translates back */
864 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
865 gfloat _tx, _ty, _tz; \
866 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
867 cogl_matrix_translate ((m), _tx, _ty, _tz); \
869 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
871 static GQuark quark_shader_data = 0;
872 static GQuark quark_actor_layout_info = 0;
873 static GQuark quark_actor_transform_info = 0;
874 static GQuark quark_actor_animation_info = 0;
876 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
878 G_TYPE_INITIALLY_UNOWNED,
879 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
880 clutter_container_iface_init)
881 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
882 clutter_scriptable_iface_init)
883 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
884 clutter_animatable_iface_init)
885 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
886 atk_implementor_iface_init));
889 * clutter_actor_get_debug_name:
890 * @actor: a #ClutterActor
892 * Retrieves a printable name of @actor for debugging messages
894 * Return value: a string with a printable name
897 _clutter_actor_get_debug_name (ClutterActor *actor)
899 return actor->priv->name != NULL ? actor->priv->name
900 : G_OBJECT_TYPE_NAME (actor);
903 #ifdef CLUTTER_ENABLE_DEBUG
904 /* XXX - this is for debugging only, remove once working (or leave
905 * in only in some debug mode). Should leave it for a little while
906 * until we're confident in the new map/realize/visible handling.
909 clutter_actor_verify_map_state (ClutterActor *self)
911 ClutterActorPrivate *priv = self->priv;
913 if (CLUTTER_ACTOR_IS_REALIZED (self))
915 /* all bets are off during reparent when we're potentially realized,
916 * but should not be according to invariants
918 if (!CLUTTER_ACTOR_IN_REPARENT (self))
920 if (priv->parent == NULL)
922 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
926 g_warning ("Realized non-toplevel actor '%s' should "
928 _clutter_actor_get_debug_name (self));
930 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
932 g_warning ("Realized actor %s has an unrealized parent %s",
933 _clutter_actor_get_debug_name (self),
934 _clutter_actor_get_debug_name (priv->parent));
939 if (CLUTTER_ACTOR_IS_MAPPED (self))
941 if (!CLUTTER_ACTOR_IS_REALIZED (self))
942 g_warning ("Actor '%s' is mapped but not realized",
943 _clutter_actor_get_debug_name (self));
945 /* remaining bets are off during reparent when we're potentially
946 * mapped, but should not be according to invariants
948 if (!CLUTTER_ACTOR_IN_REPARENT (self))
950 if (priv->parent == NULL)
952 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
954 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
955 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
957 g_warning ("Toplevel actor '%s' is mapped "
959 _clutter_actor_get_debug_name (self));
964 g_warning ("Mapped actor '%s' should have a parent",
965 _clutter_actor_get_debug_name (self));
970 ClutterActor *iter = self;
972 /* check for the enable_paint_unmapped flag on the actor
973 * and parents; if the flag is enabled at any point of this
974 * branch of the scene graph then all the later checks
979 if (iter->priv->enable_paint_unmapped)
982 iter = iter->priv->parent;
985 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
987 g_warning ("Actor '%s' should not be mapped if parent '%s'"
989 _clutter_actor_get_debug_name (self),
990 _clutter_actor_get_debug_name (priv->parent));
993 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
995 g_warning ("Actor '%s' should not be mapped if parent '%s'"
997 _clutter_actor_get_debug_name (self),
998 _clutter_actor_get_debug_name (priv->parent));
1001 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1003 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1004 g_warning ("Actor '%s' is mapped but its non-toplevel "
1005 "parent '%s' is not mapped",
1006 _clutter_actor_get_debug_name (self),
1007 _clutter_actor_get_debug_name (priv->parent));
1014 #endif /* CLUTTER_ENABLE_DEBUG */
1017 clutter_actor_set_mapped (ClutterActor *self,
1020 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1025 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1026 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1030 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1031 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1035 /* this function updates the mapped and realized states according to
1036 * invariants, in the appropriate order.
1039 clutter_actor_update_map_state (ClutterActor *self,
1040 MapStateChange change)
1042 gboolean was_mapped;
1044 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1046 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1048 /* the mapped flag on top-level actors must be set by the
1049 * per-backend implementation because it might be asynchronous.
1051 * That is, the MAPPED flag on toplevels currently tracks the X
1052 * server mapped-ness of the window, while the expected behavior
1053 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1054 * This creates some weird complexity by breaking the invariant
1055 * that if we're visible and all ancestors shown then we are
1056 * also mapped - instead, we are mapped if all ancestors
1057 * _possibly excepting_ the stage are mapped. The stage
1058 * will map/unmap for example when it is minimized or
1059 * moved to another workspace.
1061 * So, the only invariant on the stage is that if visible it
1062 * should be realized, and that it has to be visible to be
1065 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1066 clutter_actor_realize (self);
1070 case MAP_STATE_CHECK:
1073 case MAP_STATE_MAKE_MAPPED:
1074 g_assert (!was_mapped);
1075 clutter_actor_set_mapped (self, TRUE);
1078 case MAP_STATE_MAKE_UNMAPPED:
1079 g_assert (was_mapped);
1080 clutter_actor_set_mapped (self, FALSE);
1083 case MAP_STATE_MAKE_UNREALIZED:
1084 /* we only use MAKE_UNREALIZED in unparent,
1085 * and unparenting a stage isn't possible.
1086 * If someone wants to just unrealize a stage
1087 * then clutter_actor_unrealize() doesn't
1088 * go through this codepath.
1090 g_warning ("Trying to force unrealize stage is not allowed");
1094 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1095 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1096 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1098 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1099 "it is somehow still mapped",
1100 _clutter_actor_get_debug_name (self));
1105 ClutterActorPrivate *priv = self->priv;
1106 ClutterActor *parent = priv->parent;
1107 gboolean should_be_mapped;
1108 gboolean may_be_realized;
1109 gboolean must_be_realized;
1111 should_be_mapped = FALSE;
1112 may_be_realized = TRUE;
1113 must_be_realized = FALSE;
1115 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1117 may_be_realized = FALSE;
1121 /* Maintain invariant that if parent is mapped, and we are
1122 * visible, then we are mapped ... unless parent is a
1123 * stage, in which case we map regardless of parent's map
1124 * state but do require stage to be visible and realized.
1126 * If parent is realized, that does not force us to be
1127 * realized; but if parent is unrealized, that does force
1128 * us to be unrealized.
1130 * The reason we don't force children to realize with
1131 * parents is _clutter_actor_rerealize(); if we require that
1132 * a realized parent means children are realized, then to
1133 * unrealize an actor we would have to unrealize its
1134 * parents, which would end up meaning unrealizing and
1135 * hiding the entire stage. So we allow unrealizing a
1136 * child (as long as that child is not mapped) while that
1137 * child still has a realized parent.
1139 * Also, if we unrealize from leaf nodes to root, and
1140 * realize from root to leaf, the invariants are never
1141 * violated if we allow children to be unrealized
1142 * while parents are realized.
1144 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1145 * to force us to unmap, even though parent is still
1146 * mapped. This is because we're unmapping from leaf nodes
1149 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1150 change != MAP_STATE_MAKE_UNMAPPED)
1152 gboolean parent_is_visible_realized_toplevel;
1154 parent_is_visible_realized_toplevel =
1155 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1156 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1157 CLUTTER_ACTOR_IS_REALIZED (parent));
1159 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1160 parent_is_visible_realized_toplevel)
1162 must_be_realized = TRUE;
1163 should_be_mapped = TRUE;
1167 /* if the actor has been set to be painted even if unmapped
1168 * then we should map it and check for realization as well;
1169 * this is an override for the branch of the scene graph
1170 * which begins with this node
1172 if (priv->enable_paint_unmapped)
1174 if (priv->parent == NULL)
1175 g_warning ("Attempting to map an unparented actor '%s'",
1176 _clutter_actor_get_debug_name (self));
1178 should_be_mapped = TRUE;
1179 must_be_realized = TRUE;
1182 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1183 may_be_realized = FALSE;
1186 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1189 g_warning ("Attempting to map a child that does not "
1190 "meet the necessary invariants: the actor '%s' "
1192 _clutter_actor_get_debug_name (self));
1194 g_warning ("Attempting to map a child that does not "
1195 "meet the necessary invariants: the actor '%s' "
1196 "is parented to an unmapped actor '%s'",
1197 _clutter_actor_get_debug_name (self),
1198 _clutter_actor_get_debug_name (priv->parent));
1201 /* If in reparent, we temporarily suspend unmap and unrealize.
1203 * We want to go in the order "realize, map" and "unmap, unrealize"
1207 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1208 clutter_actor_set_mapped (self, FALSE);
1211 if (must_be_realized)
1212 clutter_actor_realize (self);
1214 /* if we must be realized then we may be, presumably */
1215 g_assert (!(must_be_realized && !may_be_realized));
1218 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1219 clutter_actor_unrealize_not_hiding (self);
1222 if (should_be_mapped)
1224 if (!must_be_realized)
1225 g_warning ("Somehow we think actor '%s' should be mapped but "
1226 "not realized, which isn't allowed",
1227 _clutter_actor_get_debug_name (self));
1229 /* realization is allowed to fail (though I don't know what
1230 * an app is supposed to do about that - shouldn't it just
1231 * be a g_error? anyway, we have to avoid mapping if this
1234 if (CLUTTER_ACTOR_IS_REALIZED (self))
1235 clutter_actor_set_mapped (self, TRUE);
1239 #ifdef CLUTTER_ENABLE_DEBUG
1240 /* check all invariants were kept */
1241 clutter_actor_verify_map_state (self);
1246 clutter_actor_real_map (ClutterActor *self)
1248 ClutterActorPrivate *priv = self->priv;
1249 ClutterActor *stage, *iter;
1251 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1253 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1254 _clutter_actor_get_debug_name (self));
1256 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1258 stage = _clutter_actor_get_stage_internal (self);
1259 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1261 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1263 _clutter_actor_get_debug_name (self));
1265 /* notify on parent mapped before potentially mapping
1266 * children, so apps see a top-down notification.
1268 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1270 for (iter = self->priv->first_child;
1272 iter = iter->priv->next_sibling)
1274 clutter_actor_map (iter);
1279 * clutter_actor_map:
1280 * @self: A #ClutterActor
1282 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1283 * and realizes its children if they are visible. Does nothing if the
1284 * actor is not visible.
1286 * Calling this function is strongly disencouraged: the default
1287 * implementation of #ClutterActorClass.map() will map all the children
1288 * of an actor when mapping its parent.
1290 * When overriding map, it is mandatory to chain up to the parent
1296 clutter_actor_map (ClutterActor *self)
1298 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1300 if (CLUTTER_ACTOR_IS_MAPPED (self))
1303 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1306 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1310 clutter_actor_real_unmap (ClutterActor *self)
1312 ClutterActorPrivate *priv = self->priv;
1315 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1317 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1318 _clutter_actor_get_debug_name (self));
1320 for (iter = self->priv->first_child;
1322 iter = iter->priv->next_sibling)
1324 clutter_actor_unmap (iter);
1327 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1329 /* clear the contents of the last paint volume, so that hiding + moving +
1330 * showing will not result in the wrong area being repainted
1332 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1333 priv->last_paint_volume_valid = TRUE;
1335 /* notify on parent mapped after potentially unmapping
1336 * children, so apps see a bottom-up notification.
1338 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1340 /* relinquish keyboard focus if we were unmapped while owning it */
1341 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1343 ClutterStage *stage;
1345 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1348 _clutter_stage_release_pick_id (stage, priv->pick_id);
1352 if (stage != NULL &&
1353 clutter_stage_get_key_focus (stage) == self)
1355 clutter_stage_set_key_focus (stage, NULL);
1361 * clutter_actor_unmap:
1362 * @self: A #ClutterActor
1364 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1365 * unmaps its children if they were mapped.
1367 * Calling this function is not encouraged: the default #ClutterActor
1368 * implementation of #ClutterActorClass.unmap() will also unmap any
1369 * eventual children by default when their parent is unmapped.
1371 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1372 * chain up to the parent implementation.
1374 * <note>It is important to note that the implementation of the
1375 * #ClutterActorClass.unmap() virtual function may be called after
1376 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1377 * implementation, but it is guaranteed to be called before the
1378 * #GObjectClass.finalize() implementation.</note>
1383 clutter_actor_unmap (ClutterActor *self)
1385 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1387 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1390 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1394 clutter_actor_real_show (ClutterActor *self)
1396 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1398 ClutterActorPrivate *priv = self->priv;
1400 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1402 /* we notify on the "visible" flag in the clutter_actor_show()
1403 * wrapper so the entire show signal emission completes first
1406 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1408 /* we queue a relayout unless the actor is inside a
1409 * container that explicitly told us not to
1411 if (priv->parent != NULL &&
1412 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1414 /* While an actor is hidden the parent may not have
1415 * allocated/requested so we need to start from scratch
1416 * and avoid the short-circuiting in
1417 * clutter_actor_queue_relayout().
1419 priv->needs_width_request = FALSE;
1420 priv->needs_height_request = FALSE;
1421 priv->needs_allocation = FALSE;
1422 clutter_actor_queue_relayout (self);
1428 set_show_on_set_parent (ClutterActor *self,
1431 ClutterActorPrivate *priv = self->priv;
1433 set_show = !!set_show;
1435 if (priv->show_on_set_parent == set_show)
1438 if (priv->parent == NULL)
1440 priv->show_on_set_parent = set_show;
1441 g_object_notify_by_pspec (G_OBJECT (self),
1442 obj_props[PROP_SHOW_ON_SET_PARENT]);
1447 * clutter_actor_show:
1448 * @self: A #ClutterActor
1450 * Flags an actor to be displayed. An actor that isn't shown will not
1451 * be rendered on the stage.
1453 * Actors are visible by default.
1455 * If this function is called on an actor without a parent, the
1456 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1460 clutter_actor_show (ClutterActor *self)
1462 ClutterActorPrivate *priv;
1464 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1466 /* simple optimization */
1467 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1469 /* we still need to set the :show-on-set-parent property, in
1470 * case show() is called on an unparented actor
1472 set_show_on_set_parent (self, TRUE);
1476 #ifdef CLUTTER_ENABLE_DEBUG
1477 clutter_actor_verify_map_state (self);
1482 g_object_freeze_notify (G_OBJECT (self));
1484 set_show_on_set_parent (self, TRUE);
1486 g_signal_emit (self, actor_signals[SHOW], 0);
1487 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1489 if (priv->parent != NULL)
1490 clutter_actor_queue_redraw (priv->parent);
1492 g_object_thaw_notify (G_OBJECT (self));
1496 * clutter_actor_show_all:
1497 * @self: a #ClutterActor
1499 * Calls clutter_actor_show() on all children of an actor (if any).
1503 * Deprecated: 1.10: Actors are visible by default
1506 clutter_actor_show_all (ClutterActor *self)
1508 ClutterActorClass *klass;
1510 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1512 klass = CLUTTER_ACTOR_GET_CLASS (self);
1513 if (klass->show_all)
1514 klass->show_all (self);
1518 clutter_actor_real_hide (ClutterActor *self)
1520 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1522 ClutterActorPrivate *priv = self->priv;
1524 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1526 /* we notify on the "visible" flag in the clutter_actor_hide()
1527 * wrapper so the entire hide signal emission completes first
1530 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1532 /* we queue a relayout unless the actor is inside a
1533 * container that explicitly told us not to
1535 if (priv->parent != NULL &&
1536 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1537 clutter_actor_queue_relayout (priv->parent);
1542 * clutter_actor_hide:
1543 * @self: A #ClutterActor
1545 * Flags an actor to be hidden. A hidden actor will not be
1546 * rendered on the stage.
1548 * Actors are visible by default.
1550 * If this function is called on an actor without a parent, the
1551 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1555 clutter_actor_hide (ClutterActor *self)
1557 ClutterActorPrivate *priv;
1559 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1561 /* simple optimization */
1562 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1564 /* we still need to set the :show-on-set-parent property, in
1565 * case hide() is called on an unparented actor
1567 set_show_on_set_parent (self, FALSE);
1571 #ifdef CLUTTER_ENABLE_DEBUG
1572 clutter_actor_verify_map_state (self);
1577 g_object_freeze_notify (G_OBJECT (self));
1579 set_show_on_set_parent (self, FALSE);
1581 g_signal_emit (self, actor_signals[HIDE], 0);
1582 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1584 if (priv->parent != NULL)
1585 clutter_actor_queue_redraw (priv->parent);
1587 g_object_thaw_notify (G_OBJECT (self));
1591 * clutter_actor_hide_all:
1592 * @self: a #ClutterActor
1594 * Calls clutter_actor_hide() on all child actors (if any).
1598 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1599 * prevent its children from being painted as well.
1602 clutter_actor_hide_all (ClutterActor *self)
1604 ClutterActorClass *klass;
1606 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1608 klass = CLUTTER_ACTOR_GET_CLASS (self);
1609 if (klass->hide_all)
1610 klass->hide_all (self);
1614 * clutter_actor_realize:
1615 * @self: A #ClutterActor
1617 * Realization informs the actor that it is attached to a stage. It
1618 * can use this to allocate resources if it wanted to delay allocation
1619 * until it would be rendered. However it is perfectly acceptable for
1620 * an actor to create resources before being realized because Clutter
1621 * only ever has a single rendering context so that actor is free to
1622 * be moved from one stage to another.
1624 * This function does nothing if the actor is already realized.
1626 * Because a realized actor must have realized parent actors, calling
1627 * clutter_actor_realize() will also realize all parents of the actor.
1629 * This function does not realize child actors, except in the special
1630 * case that realizing the stage, when the stage is visible, will
1631 * suddenly map (and thus realize) the children of the stage.
1634 clutter_actor_realize (ClutterActor *self)
1636 ClutterActorPrivate *priv;
1638 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1642 #ifdef CLUTTER_ENABLE_DEBUG
1643 clutter_actor_verify_map_state (self);
1646 if (CLUTTER_ACTOR_IS_REALIZED (self))
1649 /* To be realized, our parent actors must be realized first.
1650 * This will only succeed if we're inside a toplevel.
1652 if (priv->parent != NULL)
1653 clutter_actor_realize (priv->parent);
1655 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1657 /* toplevels can be realized at any time */
1661 /* "Fail" the realization if parent is missing or unrealized;
1662 * this should really be a g_warning() not some kind of runtime
1663 * failure; how can an app possibly recover? Instead it's a bug
1664 * in the app and the app should get an explanatory warning so
1665 * someone can fix it. But for now it's too hard to fix this
1666 * because e.g. ClutterTexture needs reworking.
1668 if (priv->parent == NULL ||
1669 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1673 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1675 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1676 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1678 g_signal_emit (self, actor_signals[REALIZE], 0);
1680 /* Stage actor is allowed to unset the realized flag again in its
1681 * default signal handler, though that is a pathological situation.
1684 /* If realization "failed" we'll have to update child state. */
1685 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1689 clutter_actor_real_unrealize (ClutterActor *self)
1691 /* we must be unmapped (implying our children are also unmapped) */
1692 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1696 * clutter_actor_unrealize:
1697 * @self: A #ClutterActor
1699 * Unrealization informs the actor that it may be being destroyed or
1700 * moved to another stage. The actor may want to destroy any
1701 * underlying graphics resources at this point. However it is
1702 * perfectly acceptable for it to retain the resources until the actor
1703 * is destroyed because Clutter only ever uses a single rendering
1704 * context and all of the graphics resources are valid on any stage.
1706 * Because mapped actors must be realized, actors may not be
1707 * unrealized if they are mapped. This function hides the actor to be
1708 * sure it isn't mapped, an application-visible side effect that you
1709 * may not be expecting.
1711 * This function should not be called by application code.
1714 clutter_actor_unrealize (ClutterActor *self)
1716 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1717 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1719 /* This function should not really be in the public API, because
1720 * there isn't a good reason to call it. ClutterActor will already
1721 * unrealize things for you when it's important to do so.
1723 * If you were using clutter_actor_unrealize() in a dispose
1724 * implementation, then don't, just chain up to ClutterActor's
1727 * If you were using clutter_actor_unrealize() to implement
1728 * unrealizing children of your container, then don't, ClutterActor
1729 * will already take care of that.
1731 * If you were using clutter_actor_unrealize() to re-realize to
1732 * create your resources in a different way, then use
1733 * _clutter_actor_rerealize() (inside Clutter) or just call your
1734 * code that recreates your resources directly (outside Clutter).
1737 #ifdef CLUTTER_ENABLE_DEBUG
1738 clutter_actor_verify_map_state (self);
1741 clutter_actor_hide (self);
1743 clutter_actor_unrealize_not_hiding (self);
1746 static ClutterActorTraverseVisitFlags
1747 unrealize_actor_before_children_cb (ClutterActor *self,
1751 /* If an actor is already unrealized we know its children have also
1752 * already been unrealized... */
1753 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1754 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1756 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1758 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1761 static ClutterActorTraverseVisitFlags
1762 unrealize_actor_after_children_cb (ClutterActor *self,
1766 /* We want to unset the realized flag only _after_
1767 * child actors are unrealized, to maintain invariants.
1769 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1770 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1771 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1775 * clutter_actor_unrealize_not_hiding:
1776 * @self: A #ClutterActor
1778 * Unrealization informs the actor that it may be being destroyed or
1779 * moved to another stage. The actor may want to destroy any
1780 * underlying graphics resources at this point. However it is
1781 * perfectly acceptable for it to retain the resources until the actor
1782 * is destroyed because Clutter only ever uses a single rendering
1783 * context and all of the graphics resources are valid on any stage.
1785 * Because mapped actors must be realized, actors may not be
1786 * unrealized if they are mapped. You must hide the actor or one of
1787 * its parents before attempting to unrealize.
1789 * This function is separate from clutter_actor_unrealize() because it
1790 * does not automatically hide the actor.
1791 * Actors need not be hidden to be unrealized, they just need to
1792 * be unmapped. In fact we don't want to mess up the application's
1793 * setting of the "visible" flag, so hiding is very undesirable.
1795 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1796 * backward compatibility.
1799 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1801 _clutter_actor_traverse (self,
1802 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1803 unrealize_actor_before_children_cb,
1804 unrealize_actor_after_children_cb,
1809 * _clutter_actor_rerealize:
1810 * @self: A #ClutterActor
1811 * @callback: Function to call while unrealized
1812 * @data: data for callback
1814 * If an actor is already unrealized, this just calls the callback.
1816 * If it is realized, it unrealizes temporarily, calls the callback,
1817 * and then re-realizes the actor.
1819 * As a side effect, leaves all children of the actor unrealized if
1820 * the actor was realized but not showing. This is because when we
1821 * unrealize the actor temporarily we must unrealize its children
1822 * (e.g. children of a stage can't be realized if stage window is
1823 * gone). And we aren't clever enough to save the realization state of
1824 * all children. In most cases this should not matter, because
1825 * the children will automatically realize when they next become mapped.
1828 _clutter_actor_rerealize (ClutterActor *self,
1829 ClutterCallback callback,
1832 gboolean was_mapped;
1833 gboolean was_showing;
1834 gboolean was_realized;
1836 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1838 #ifdef CLUTTER_ENABLE_DEBUG
1839 clutter_actor_verify_map_state (self);
1842 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1843 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1844 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1846 /* Must be unmapped to unrealize. Note we only have to hide this
1847 * actor if it was mapped (if all parents were showing). If actor
1848 * is merely visible (but not mapped), then that's fine, we can
1852 clutter_actor_hide (self);
1854 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1856 /* unrealize self and all children */
1857 clutter_actor_unrealize_not_hiding (self);
1859 if (callback != NULL)
1861 (* callback) (self, data);
1865 clutter_actor_show (self); /* will realize only if mapping implies it */
1866 else if (was_realized)
1867 clutter_actor_realize (self); /* realize self and all parents */
1871 clutter_actor_real_pick (ClutterActor *self,
1872 const ClutterColor *color)
1874 /* the default implementation is just to paint a rectangle
1875 * with the same size of the actor using the passed color
1877 if (clutter_actor_should_pick_paint (self))
1879 ClutterActorBox box = { 0, };
1880 float width, height;
1882 clutter_actor_get_allocation_box (self, &box);
1884 width = box.x2 - box.x1;
1885 height = box.y2 - box.y1;
1887 cogl_set_source_color4ub (color->red,
1892 cogl_rectangle (0, 0, width, height);
1895 /* XXX - this thoroughly sucks, but we need to maintain compatibility
1896 * with existing container classes that override the pick() virtual
1897 * and chain up to the default implementation - otherwise we'll end up
1898 * painting our children twice.
1900 * this has to go away for 2.0; hopefully along the pick() itself.
1902 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1906 for (iter = self->priv->first_child;
1908 iter = iter->priv->next_sibling)
1909 clutter_actor_paint (iter);
1914 * clutter_actor_should_pick_paint:
1915 * @self: A #ClutterActor
1917 * Should be called inside the implementation of the
1918 * #ClutterActor::pick virtual function in order to check whether
1919 * the actor should paint itself in pick mode or not.
1921 * This function should never be called directly by applications.
1923 * Return value: %TRUE if the actor should paint its silhouette,
1927 clutter_actor_should_pick_paint (ClutterActor *self)
1929 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1931 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1932 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1933 CLUTTER_ACTOR_IS_REACTIVE (self)))
1940 clutter_actor_real_get_preferred_width (ClutterActor *self,
1942 gfloat *min_width_p,
1943 gfloat *natural_width_p)
1945 ClutterActorPrivate *priv = self->priv;
1947 if (priv->n_children != 0 &&
1948 priv->layout_manager != NULL)
1950 ClutterContainer *container = CLUTTER_CONTAINER (self);
1952 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1953 "for the preferred width",
1954 G_OBJECT_TYPE_NAME (priv->layout_manager),
1955 priv->layout_manager);
1957 clutter_layout_manager_get_preferred_width (priv->layout_manager,
1966 /* Default implementation is always 0x0, usually an actor
1967 * using this default is relying on someone to set the
1970 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1975 if (natural_width_p)
1976 *natural_width_p = 0;
1980 clutter_actor_real_get_preferred_height (ClutterActor *self,
1982 gfloat *min_height_p,
1983 gfloat *natural_height_p)
1985 ClutterActorPrivate *priv = self->priv;
1987 if (priv->n_children != 0 &&
1988 priv->layout_manager != NULL)
1990 ClutterContainer *container = CLUTTER_CONTAINER (self);
1992 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1993 "for the preferred height",
1994 G_OBJECT_TYPE_NAME (priv->layout_manager),
1995 priv->layout_manager);
1997 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2005 /* Default implementation is always 0x0, usually an actor
2006 * using this default is relying on someone to set the
2009 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2014 if (natural_height_p)
2015 *natural_height_p = 0;
2019 clutter_actor_store_old_geometry (ClutterActor *self,
2020 ClutterActorBox *box)
2022 *box = self->priv->allocation;
2026 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2027 const ClutterActorBox *old)
2029 ClutterActorPrivate *priv = self->priv;
2030 GObject *obj = G_OBJECT (self);
2032 g_object_freeze_notify (obj);
2034 /* to avoid excessive requisition or allocation cycles we
2035 * use the cached values.
2037 * - if we don't have an allocation we assume that we need
2039 * - if we don't have a width or a height request we notify
2041 * - if we have a valid allocation then we check the old
2042 * bounding box with the current allocation and we notify
2045 if (priv->needs_allocation)
2047 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2048 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2049 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2050 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2052 else if (priv->needs_width_request || priv->needs_height_request)
2054 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2055 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2060 gfloat width, height;
2062 x = priv->allocation.x1;
2063 y = priv->allocation.y1;
2064 width = priv->allocation.x2 - priv->allocation.x1;
2065 height = priv->allocation.y2 - priv->allocation.y1;
2068 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2071 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2073 if (width != (old->x2 - old->x1))
2074 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2076 if (height != (old->y2 - old->y1))
2077 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2080 g_object_thaw_notify (obj);
2084 * clutter_actor_set_allocation_internal:
2085 * @self: a #ClutterActor
2086 * @box: a #ClutterActorBox
2087 * @flags: allocation flags
2089 * Stores the allocation of @self.
2091 * This function only performs basic storage and property notification.
2093 * This function should be called by clutter_actor_set_allocation()
2094 * and by the default implementation of #ClutterActorClass.allocate().
2096 * Return value: %TRUE if the allocation of the #ClutterActor has been
2097 * changed, and %FALSE otherwise
2099 static inline gboolean
2100 clutter_actor_set_allocation_internal (ClutterActor *self,
2101 const ClutterActorBox *box,
2102 ClutterAllocationFlags flags)
2104 ClutterActorPrivate *priv = self->priv;
2106 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2107 gboolean flags_changed;
2109 ClutterActorBox old_alloc = { 0, };
2111 obj = G_OBJECT (self);
2113 g_object_freeze_notify (obj);
2115 clutter_actor_store_old_geometry (self, &old_alloc);
2117 x1_changed = priv->allocation.x1 != box->x1;
2118 y1_changed = priv->allocation.y1 != box->y1;
2119 x2_changed = priv->allocation.x2 != box->x2;
2120 y2_changed = priv->allocation.y2 != box->y2;
2122 flags_changed = priv->allocation_flags != flags;
2124 priv->allocation = *box;
2125 priv->allocation_flags = flags;
2127 /* allocation is authoritative */
2128 priv->needs_width_request = FALSE;
2129 priv->needs_height_request = FALSE;
2130 priv->needs_allocation = FALSE;
2132 if (x1_changed || y1_changed ||
2133 x2_changed || y2_changed ||
2136 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2137 _clutter_actor_get_debug_name (self));
2139 priv->transform_valid = FALSE;
2141 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2143 /* if the allocation changes, so does the content box */
2144 if (priv->content != NULL)
2145 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2152 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2154 g_object_thaw_notify (obj);
2159 static void clutter_actor_real_allocate (ClutterActor *self,
2160 const ClutterActorBox *box,
2161 ClutterAllocationFlags flags);
2164 clutter_actor_maybe_layout_children (ClutterActor *self,
2165 const ClutterActorBox *allocation,
2166 ClutterAllocationFlags flags)
2168 ClutterActorPrivate *priv = self->priv;
2170 /* this is going to be a bit hard to follow, so let's put an explanation
2173 * we want ClutterActor to have a default layout manager if the actor was
2174 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2176 * we also want any subclass of ClutterActor that does not override the
2177 * ::allocate() virtual function to delegate to a layout manager.
2179 * finally, we want to allow people subclassing ClutterActor and overriding
2180 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2182 * on the other hand, we want existing actor subclasses overriding the
2183 * ::allocate() virtual function and chaining up to the parent's
2184 * implementation to continue working without allocating their children
2185 * twice, or without entering an allocation loop.
2187 * for the first two points, we check if the class of the actor is
2188 * overridding the ::allocate() virtual function; if it isn't, then we
2189 * follow through with checking whether we have children and a layout
2190 * manager, and eventually calling clutter_layout_manager_allocate().
2192 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2193 * allocation flags that we got passed, and if it is present, we continue
2194 * with the check above.
2196 * if neither of these two checks yields a positive result, we just
2197 * assume that the ::allocate() virtual function that resulted in this
2198 * function being called will also allocate the children of the actor.
2201 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2204 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2210 if (priv->n_children != 0 &&
2211 priv->layout_manager != NULL)
2213 ClutterContainer *container = CLUTTER_CONTAINER (self);
2214 ClutterAllocationFlags children_flags;
2215 ClutterActorBox children_box;
2217 /* normalize the box passed to the layout manager */
2218 children_box.x1 = children_box.y1 = 0.f;
2219 children_box.x2 = (allocation->x2 - allocation->x1);
2220 children_box.y2 = (allocation->y2 - allocation->y1);
2222 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2223 * the actor's children, since it refers only to the current
2224 * actor's allocation.
2226 children_flags = flags;
2227 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2229 CLUTTER_NOTE (LAYOUT,
2230 "Allocating %d children of %s "
2231 "at { %.2f, %.2f - %.2f x %.2f } "
2234 _clutter_actor_get_debug_name (self),
2237 (allocation->x2 - allocation->x1),
2238 (allocation->y2 - allocation->y1),
2239 G_OBJECT_TYPE_NAME (priv->layout_manager));
2241 clutter_layout_manager_allocate (priv->layout_manager,
2249 clutter_actor_real_allocate (ClutterActor *self,
2250 const ClutterActorBox *box,
2251 ClutterAllocationFlags flags)
2253 ClutterActorPrivate *priv = self->priv;
2256 g_object_freeze_notify (G_OBJECT (self));
2258 changed = clutter_actor_set_allocation_internal (self, box, flags);
2260 /* we allocate our children before we notify changes in our geometry,
2261 * so that people connecting to properties will be able to get valid
2262 * data out of the sub-tree of the scene graph that has this actor at
2265 clutter_actor_maybe_layout_children (self, box, flags);
2269 ClutterActorBox signal_box = priv->allocation;
2270 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2272 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2277 g_object_thaw_notify (G_OBJECT (self));
2281 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2282 ClutterActor *origin)
2284 /* no point in queuing a redraw on a destroyed actor */
2285 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2288 /* NB: We can't bail out early here if the actor is hidden in case
2289 * the actor bas been cloned. In this case the clone will need to
2290 * receive the signal so it can queue its own redraw.
2293 /* calls klass->queue_redraw in default handler */
2294 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2298 clutter_actor_real_queue_redraw (ClutterActor *self,
2299 ClutterActor *origin)
2301 ClutterActor *parent;
2303 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2304 _clutter_actor_get_debug_name (self),
2305 origin != NULL ? _clutter_actor_get_debug_name (origin)
2308 /* no point in queuing a redraw on a destroyed actor */
2309 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2312 /* If the queue redraw is coming from a child then the actor has
2313 become dirty and any queued effect is no longer valid */
2316 self->priv->is_dirty = TRUE;
2317 self->priv->effect_to_redraw = NULL;
2320 /* If the actor isn't visible, we still had to emit the signal
2321 * to allow for a ClutterClone, but the appearance of the parent
2322 * won't change so we don't have to propagate up the hierarchy.
2324 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2327 /* Although we could determine here that a full stage redraw
2328 * has already been queued and immediately bail out, we actually
2329 * guarantee that we will propagate a queue-redraw signal to our
2330 * parent at least once so that it's possible to implement a
2331 * container that tracks which of its children have queued a
2334 if (self->priv->propagated_one_redraw)
2336 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2337 if (stage != NULL &&
2338 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2342 self->priv->propagated_one_redraw = TRUE;
2344 /* notify parents, if they are all visible eventually we'll
2345 * queue redraw on the stage, which queues the redraw idle.
2347 parent = clutter_actor_get_parent (self);
2350 /* this will go up recursively */
2351 _clutter_actor_signal_queue_redraw (parent, origin);
2356 clutter_actor_real_queue_relayout (ClutterActor *self)
2358 ClutterActorPrivate *priv = self->priv;
2360 /* no point in queueing a redraw on a destroyed actor */
2361 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2364 priv->needs_width_request = TRUE;
2365 priv->needs_height_request = TRUE;
2366 priv->needs_allocation = TRUE;
2368 /* reset the cached size requests */
2369 memset (priv->width_requests, 0,
2370 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2371 memset (priv->height_requests, 0,
2372 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2374 /* We need to go all the way up the hierarchy */
2375 if (priv->parent != NULL)
2376 _clutter_actor_queue_only_relayout (priv->parent);
2380 * clutter_actor_apply_relative_transform_to_point:
2381 * @self: A #ClutterActor
2382 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2383 * default #ClutterStage
2384 * @point: A point as #ClutterVertex
2385 * @vertex: (out caller-allocates): The translated #ClutterVertex
2387 * Transforms @point in coordinates relative to the actor into
2388 * ancestor-relative coordinates using the relevant transform
2389 * stack (i.e. scale, rotation, etc).
2391 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2392 * this case, the coordinates returned will be the coordinates on
2393 * the stage before the projection is applied. This is different from
2394 * the behaviour of clutter_actor_apply_transform_to_point().
2399 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2400 ClutterActor *ancestor,
2401 const ClutterVertex *point,
2402 ClutterVertex *vertex)
2407 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2408 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2409 g_return_if_fail (point != NULL);
2410 g_return_if_fail (vertex != NULL);
2415 if (ancestor == NULL)
2416 ancestor = _clutter_actor_get_stage_internal (self);
2418 if (ancestor == NULL)
2424 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2425 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2429 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2430 const ClutterVertex *vertices_in,
2431 ClutterVertex *vertices_out,
2434 ClutterActor *stage;
2435 CoglMatrix modelview;
2436 CoglMatrix projection;
2439 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2441 stage = _clutter_actor_get_stage_internal (self);
2443 /* We really can't do anything meaningful in this case so don't try
2444 * to do any transform */
2448 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2449 * that gets us to stage coordinates, we want to go all the way to eye
2451 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2453 /* Fetch the projection and viewport */
2454 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2455 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2461 _clutter_util_fully_transform_vertices (&modelview,
2472 * clutter_actor_apply_transform_to_point:
2473 * @self: A #ClutterActor
2474 * @point: A point as #ClutterVertex
2475 * @vertex: (out caller-allocates): The translated #ClutterVertex
2477 * Transforms @point in coordinates relative to the actor
2478 * into screen-relative coordinates with the current actor
2479 * transformation (i.e. scale, rotation, etc)
2484 clutter_actor_apply_transform_to_point (ClutterActor *self,
2485 const ClutterVertex *point,
2486 ClutterVertex *vertex)
2488 g_return_if_fail (point != NULL);
2489 g_return_if_fail (vertex != NULL);
2490 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2494 * _clutter_actor_get_relative_transformation_matrix:
2495 * @self: The actor whose coordinate space you want to transform from.
2496 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2497 * or %NULL if you want to transform all the way to eye coordinates.
2498 * @matrix: A #CoglMatrix to store the transformation
2500 * This gets a transformation @matrix that will transform coordinates from the
2501 * coordinate space of @self into the coordinate space of @ancestor.
2503 * For example if you need a matrix that can transform the local actor
2504 * coordinates of @self into stage coordinates you would pass the actor's stage
2505 * pointer as the @ancestor.
2507 * If you pass %NULL then the transformation will take you all the way through
2508 * to eye coordinates. This can be useful if you want to extract the entire
2509 * modelview transform that Clutter applies before applying the projection
2510 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2511 * using cogl_set_modelview_matrix() for example then you would want a matrix
2512 * that transforms into eye coordinates.
2514 * <note><para>This function explicitly initializes the given @matrix. If you just
2515 * want clutter to multiply a relative transformation with an existing matrix
2516 * you can use clutter_actor_apply_relative_transformation_matrix()
2517 * instead.</para></note>
2520 /* XXX: We should consider caching the stage relative modelview along with
2521 * the actor itself */
2523 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2524 ClutterActor *ancestor,
2527 cogl_matrix_init_identity (matrix);
2529 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2532 /* Project the given @box into stage window coordinates, writing the
2533 * transformed vertices to @verts[]. */
2535 _clutter_actor_transform_and_project_box (ClutterActor *self,
2536 const ClutterActorBox *box,
2537 ClutterVertex verts[])
2539 ClutterVertex box_vertices[4];
2541 box_vertices[0].x = box->x1;
2542 box_vertices[0].y = box->y1;
2543 box_vertices[0].z = 0;
2544 box_vertices[1].x = box->x2;
2545 box_vertices[1].y = box->y1;
2546 box_vertices[1].z = 0;
2547 box_vertices[2].x = box->x1;
2548 box_vertices[2].y = box->y2;
2549 box_vertices[2].z = 0;
2550 box_vertices[3].x = box->x2;
2551 box_vertices[3].y = box->y2;
2552 box_vertices[3].z = 0;
2555 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2559 * clutter_actor_get_allocation_vertices:
2560 * @self: A #ClutterActor
2561 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2562 * against, or %NULL to use the #ClutterStage
2563 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2564 * location for an array of 4 #ClutterVertex in which to store the result
2566 * Calculates the transformed coordinates of the four corners of the
2567 * actor in the plane of @ancestor. The returned vertices relate to
2568 * the #ClutterActorBox coordinates as follows:
2570 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2571 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2572 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2573 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2576 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2577 * this case, the coordinates returned will be the coordinates on
2578 * the stage before the projection is applied. This is different from
2579 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2584 clutter_actor_get_allocation_vertices (ClutterActor *self,
2585 ClutterActor *ancestor,
2586 ClutterVertex verts[])
2588 ClutterActorPrivate *priv;
2589 ClutterActorBox box;
2590 ClutterVertex vertices[4];
2591 CoglMatrix modelview;
2593 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2594 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2596 if (ancestor == NULL)
2597 ancestor = _clutter_actor_get_stage_internal (self);
2599 /* Fallback to a NOP transform if the actor isn't parented under a
2601 if (ancestor == NULL)
2606 /* if the actor needs to be allocated we force a relayout, so that
2607 * we will have valid values to use in the transformations */
2608 if (priv->needs_allocation)
2610 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2612 _clutter_stage_maybe_relayout (stage);
2615 box.x1 = box.y1 = 0;
2616 /* The result isn't really meaningful in this case but at
2617 * least try to do something *vaguely* reasonable... */
2618 clutter_actor_get_size (self, &box.x2, &box.y2);
2622 clutter_actor_get_allocation_box (self, &box);
2624 vertices[0].x = box.x1;
2625 vertices[0].y = box.y1;
2627 vertices[1].x = box.x2;
2628 vertices[1].y = box.y1;
2630 vertices[2].x = box.x1;
2631 vertices[2].y = box.y2;
2633 vertices[3].x = box.x2;
2634 vertices[3].y = box.y2;
2637 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2640 cogl_matrix_transform_points (&modelview,
2642 sizeof (ClutterVertex),
2644 sizeof (ClutterVertex),
2650 * clutter_actor_get_abs_allocation_vertices:
2651 * @self: A #ClutterActor
2652 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2653 * of 4 #ClutterVertex where to store the result.
2655 * Calculates the transformed screen coordinates of the four corners of
2656 * the actor; the returned vertices relate to the #ClutterActorBox
2657 * coordinates as follows:
2659 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2660 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2661 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2662 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2668 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2669 ClutterVertex verts[])
2671 ClutterActorPrivate *priv;
2672 ClutterActorBox actor_space_allocation;
2674 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2678 /* if the actor needs to be allocated we force a relayout, so that
2679 * the actor allocation box will be valid for
2680 * _clutter_actor_transform_and_project_box()
2682 if (priv->needs_allocation)
2684 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2685 /* There's nothing meaningful we can do now */
2689 _clutter_stage_maybe_relayout (stage);
2692 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2693 * own coordinate space... */
2694 actor_space_allocation.x1 = 0;
2695 actor_space_allocation.y1 = 0;
2696 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2697 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2698 _clutter_actor_transform_and_project_box (self,
2699 &actor_space_allocation,
2704 clutter_actor_real_apply_transform (ClutterActor *self,
2707 ClutterActorPrivate *priv = self->priv;
2709 if (!priv->transform_valid)
2711 CoglMatrix *transform = &priv->transform;
2712 const ClutterTransformInfo *info;
2714 info = _clutter_actor_get_transform_info_or_defaults (self);
2716 cogl_matrix_init_identity (transform);
2718 cogl_matrix_translate (transform,
2719 priv->allocation.x1,
2720 priv->allocation.y1,
2724 cogl_matrix_translate (transform, 0, 0, info->depth);
2727 * because the rotation involves translations, we must scale
2728 * before applying the rotations (if we apply the scale after
2729 * the rotations, the translations included in the rotation are
2730 * not scaled and so the entire object will move on the screen
2731 * as a result of rotating it).
2733 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2735 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2736 &info->scale_center,
2737 cogl_matrix_scale (transform,
2744 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2746 cogl_matrix_rotate (transform,
2751 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2753 cogl_matrix_rotate (transform,
2758 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2760 cogl_matrix_rotate (transform,
2764 if (!clutter_anchor_coord_is_zero (&info->anchor))
2768 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2769 cogl_matrix_translate (transform, -x, -y, -z);
2772 priv->transform_valid = TRUE;
2775 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2778 /* Applies the transforms associated with this actor to the given
2781 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2784 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2788 * clutter_actor_apply_relative_transformation_matrix:
2789 * @self: The actor whose coordinate space you want to transform from.
2790 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2791 * or %NULL if you want to transform all the way to eye coordinates.
2792 * @matrix: A #CoglMatrix to apply the transformation too.
2794 * This multiplies a transform with @matrix that will transform coordinates
2795 * from the coordinate space of @self into the coordinate space of @ancestor.
2797 * For example if you need a matrix that can transform the local actor
2798 * coordinates of @self into stage coordinates you would pass the actor's stage
2799 * pointer as the @ancestor.
2801 * If you pass %NULL then the transformation will take you all the way through
2802 * to eye coordinates. This can be useful if you want to extract the entire
2803 * modelview transform that Clutter applies before applying the projection
2804 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2805 * using cogl_set_modelview_matrix() for example then you would want a matrix
2806 * that transforms into eye coordinates.
2808 * <note>This function doesn't initialize the given @matrix, it simply
2809 * multiplies the requested transformation matrix with the existing contents of
2810 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2811 * before calling this function, or you can use
2812 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2815 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2816 ClutterActor *ancestor,
2819 ClutterActor *parent;
2821 /* Note we terminate before ever calling stage->apply_transform()
2822 * since that would conceptually be relative to the underlying
2823 * window OpenGL coordinates so we'd need a special @ancestor
2824 * value to represent the fake parent of the stage. */
2825 if (self == ancestor)
2828 parent = clutter_actor_get_parent (self);
2831 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2834 _clutter_actor_apply_modelview_transform (self, matrix);
2838 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2839 ClutterPaintVolume *pv,
2841 const CoglColor *color)
2843 static CoglPipeline *outline = NULL;
2844 CoglPrimitive *prim;
2845 ClutterVertex line_ends[12 * 2];
2848 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2849 /* XXX: at some point we'll query this from the stage but we can't
2850 * do that until the osx backend uses Cogl natively. */
2851 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2853 if (outline == NULL)
2854 outline = cogl_pipeline_new (ctx);
2856 _clutter_paint_volume_complete (pv);
2858 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2861 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2862 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2863 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2864 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2869 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2870 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2871 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2872 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2874 /* Lines connecting front face to back face */
2875 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2876 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2877 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2878 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2881 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2883 (CoglVertexP3 *)line_ends);
2885 cogl_pipeline_set_color (outline, color);
2886 cogl_framebuffer_draw_primitive (fb, outline, prim);
2887 cogl_object_unref (prim);
2891 PangoLayout *layout;
2892 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2893 pango_layout_set_text (layout, label, -1);
2894 cogl_pango_render_layout (layout,
2899 g_object_unref (layout);
2904 _clutter_actor_draw_paint_volume (ClutterActor *self)
2906 ClutterPaintVolume *pv;
2909 pv = _clutter_actor_get_paint_volume_mutable (self);
2912 gfloat width, height;
2913 ClutterPaintVolume fake_pv;
2915 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2916 _clutter_paint_volume_init_static (&fake_pv, stage);
2918 clutter_actor_get_size (self, &width, &height);
2919 clutter_paint_volume_set_width (&fake_pv, width);
2920 clutter_paint_volume_set_height (&fake_pv, height);
2922 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2923 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2924 _clutter_actor_get_debug_name (self),
2927 clutter_paint_volume_free (&fake_pv);
2931 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2932 _clutter_actor_draw_paint_volume_full (self, pv,
2933 _clutter_actor_get_debug_name (self),
2939 _clutter_actor_paint_cull_result (ClutterActor *self,
2941 ClutterCullResult result)
2943 ClutterPaintVolume *pv;
2948 if (result == CLUTTER_CULL_RESULT_IN)
2949 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2950 else if (result == CLUTTER_CULL_RESULT_OUT)
2951 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2953 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2956 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2958 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2959 _clutter_actor_draw_paint_volume_full (self, pv,
2960 _clutter_actor_get_debug_name (self),
2964 PangoLayout *layout;
2966 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2967 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2968 cogl_set_source_color (&color);
2970 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2971 pango_layout_set_text (layout, label, -1);
2972 cogl_pango_render_layout (layout,
2978 g_object_unref (layout);
2982 static int clone_paint_level = 0;
2985 _clutter_actor_push_clone_paint (void)
2987 clone_paint_level++;
2991 _clutter_actor_pop_clone_paint (void)
2993 clone_paint_level--;
2997 in_clone_paint (void)
2999 return clone_paint_level > 0;
3002 /* Returns TRUE if the actor can be ignored */
3003 /* FIXME: we should return a ClutterCullResult, and
3004 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3005 * means there's no point in trying to cull descendants of the current
3008 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3010 ClutterActorPrivate *priv = self->priv;
3011 ClutterActor *stage;
3012 const ClutterPlane *stage_clip;
3014 if (!priv->last_paint_volume_valid)
3016 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3017 "->last_paint_volume_valid == FALSE",
3018 _clutter_actor_get_debug_name (self));
3022 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3025 stage = _clutter_actor_get_stage_internal (self);
3026 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3027 if (G_UNLIKELY (!stage_clip))
3029 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3030 "No stage clip set",
3031 _clutter_actor_get_debug_name (self));
3035 if (cogl_get_draw_framebuffer () !=
3036 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3038 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3039 "Current framebuffer doesn't correspond to stage",
3040 _clutter_actor_get_debug_name (self));
3045 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3050 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3052 ClutterActorPrivate *priv = self->priv;
3053 const ClutterPaintVolume *pv;
3055 if (priv->last_paint_volume_valid)
3057 clutter_paint_volume_free (&priv->last_paint_volume);
3058 priv->last_paint_volume_valid = FALSE;
3061 pv = clutter_actor_get_paint_volume (self);
3064 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3065 "Actor failed to report a paint volume",
3066 _clutter_actor_get_debug_name (self));
3070 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3072 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3073 NULL); /* eye coordinates */
3075 priv->last_paint_volume_valid = TRUE;
3078 static inline gboolean
3079 actor_has_shader_data (ClutterActor *self)
3081 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3085 _clutter_actor_get_pick_id (ClutterActor *self)
3087 if (self->priv->pick_id < 0)
3090 return self->priv->pick_id;
3093 /* This is the same as clutter_actor_add_effect except that it doesn't
3094 queue a redraw and it doesn't notify on the effect property */
3096 _clutter_actor_add_effect_internal (ClutterActor *self,
3097 ClutterEffect *effect)
3099 ClutterActorPrivate *priv = self->priv;
3101 if (priv->effects == NULL)
3103 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3104 priv->effects->actor = self;
3107 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3110 /* This is the same as clutter_actor_remove_effect except that it doesn't
3111 queue a redraw and it doesn't notify on the effect property */
3113 _clutter_actor_remove_effect_internal (ClutterActor *self,
3114 ClutterEffect *effect)
3116 ClutterActorPrivate *priv = self->priv;
3118 if (priv->effects == NULL)
3121 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3125 needs_flatten_effect (ClutterActor *self)
3127 ClutterActorPrivate *priv = self->priv;
3129 if (G_UNLIKELY (clutter_paint_debug_flags &
3130 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3133 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3135 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3137 if (clutter_actor_get_paint_opacity (self) < 255 &&
3138 clutter_actor_has_overlaps (self))
3146 add_or_remove_flatten_effect (ClutterActor *self)
3148 ClutterActorPrivate *priv = self->priv;
3150 /* Add or remove the flatten effect depending on the
3151 offscreen-redirect property. */
3152 if (needs_flatten_effect (self))
3154 if (priv->flatten_effect == NULL)
3156 ClutterActorMeta *actor_meta;
3159 priv->flatten_effect = _clutter_flatten_effect_new ();
3160 /* Keep a reference to the effect so that we can queue
3162 g_object_ref_sink (priv->flatten_effect);
3164 /* Set the priority of the effect to high so that it will
3165 always be applied to the actor first. It uses an internal
3166 priority so that it won't be visible to applications */
3167 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3168 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3169 _clutter_actor_meta_set_priority (actor_meta, priority);
3171 /* This will add the effect without queueing a redraw */
3172 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3177 if (priv->flatten_effect != NULL)
3179 /* Destroy the effect so that it will lose its fbo cache of
3181 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3182 g_object_unref (priv->flatten_effect);
3183 priv->flatten_effect = NULL;
3189 clutter_actor_real_paint (ClutterActor *actor)
3191 ClutterActorPrivate *priv = actor->priv;
3194 for (iter = priv->first_child;
3196 iter = iter->priv->next_sibling)
3198 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3199 _clutter_actor_get_debug_name (iter),
3200 _clutter_actor_get_debug_name (actor),
3201 iter->priv->allocation.x1,
3202 iter->priv->allocation.y1,
3203 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3204 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3206 clutter_actor_paint (iter);
3211 clutter_actor_paint_node (ClutterActor *actor,
3212 ClutterPaintNode *root)
3214 ClutterActorPrivate *priv = actor->priv;
3219 if (priv->bg_color_set &&
3220 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3222 ClutterPaintNode *node;
3223 ClutterColor bg_color;
3224 ClutterActorBox box;
3228 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3229 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3231 bg_color = priv->bg_color;
3232 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3233 * priv->bg_color.alpha
3236 node = clutter_color_node_new (&bg_color);
3237 clutter_paint_node_set_name (node, "backgroundColor");
3238 clutter_paint_node_add_rectangle (node, &box);
3239 clutter_paint_node_add_child (root, node);
3240 clutter_paint_node_unref (node);
3243 if (priv->content != NULL)
3244 _clutter_content_paint_content (priv->content, actor, root);
3246 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3247 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3249 if (clutter_paint_node_get_n_children (root) == 0)
3252 #ifdef CLUTTER_ENABLE_DEBUG
3253 if (CLUTTER_HAS_DEBUG (PAINT))
3255 /* dump the tree only if we have one */
3256 _clutter_paint_node_dump_tree (root);
3258 #endif /* CLUTTER_ENABLE_DEBUG */
3260 _clutter_paint_node_paint (root);
3263 /* XXX: Uncomment this when we disable emitting the paint signal */
3264 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3271 * clutter_actor_paint:
3272 * @self: A #ClutterActor
3274 * Renders the actor to display.
3276 * This function should not be called directly by applications.
3277 * Call clutter_actor_queue_redraw() to queue paints, instead.
3279 * This function is context-aware, and will either cause a
3280 * regular paint or a pick paint.
3282 * This function will emit the #ClutterActor::paint signal or
3283 * the #ClutterActor::pick signal, depending on the context.
3285 * This function does not paint the actor if the actor is set to 0,
3286 * unless it is performing a pick paint.
3289 clutter_actor_paint (ClutterActor *self)
3291 ClutterActorPrivate *priv;
3292 ClutterPickMode pick_mode;
3293 gboolean clip_set = FALSE;
3294 gboolean shader_applied = FALSE;
3296 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3297 "Actor real-paint counter",
3298 "Increments each time any actor is painted",
3299 0 /* no application private data */);
3300 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3301 "Actor pick-paint counter",
3302 "Increments each time any actor is painted "
3304 0 /* no application private data */);
3306 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3308 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3313 pick_mode = _clutter_context_get_pick_mode ();
3315 if (pick_mode == CLUTTER_PICK_NONE)
3316 priv->propagated_one_redraw = FALSE;
3318 /* It's an important optimization that we consider painting of
3319 * actors with 0 opacity to be a NOP... */
3320 if (pick_mode == CLUTTER_PICK_NONE &&
3321 /* ignore top-levels, since they might be transparent */
3322 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3323 /* Use the override opacity if its been set */
3324 ((priv->opacity_override >= 0) ?
3325 priv->opacity_override : priv->opacity) == 0)
3328 /* if we aren't paintable (not in a toplevel with all
3329 * parents paintable) then do nothing.
3331 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3334 /* mark that we are in the paint process */
3335 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3339 if (priv->enable_model_view_transform)
3343 /* XXX: It could be better to cache the modelview with the actor
3344 * instead of progressively building up the transformations on
3345 * the matrix stack every time we paint. */
3346 cogl_get_modelview_matrix (&matrix);
3347 _clutter_actor_apply_modelview_transform (self, &matrix);
3349 #ifdef CLUTTER_ENABLE_DEBUG
3350 /* Catch when out-of-band transforms have been made by actors not as part
3351 * of an apply_transform vfunc... */
3352 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3354 CoglMatrix expected_matrix;
3356 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3359 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3361 GString *buf = g_string_sized_new (1024);
3362 ClutterActor *parent;
3365 while (parent != NULL)
3367 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3369 if (parent->priv->parent != NULL)
3370 g_string_append (buf, "->");
3372 parent = parent->priv->parent;
3375 g_warning ("Unexpected transform found when painting actor "
3376 "\"%s\". This will be caused by one of the actor's "
3377 "ancestors (%s) using the Cogl API directly to transform "
3378 "children instead of using ::apply_transform().",
3379 _clutter_actor_get_debug_name (self),
3382 g_string_free (buf, TRUE);
3385 #endif /* CLUTTER_ENABLE_DEBUG */
3387 cogl_set_modelview_matrix (&matrix);
3392 cogl_clip_push_rectangle (priv->clip.x,
3394 priv->clip.x + priv->clip.width,
3395 priv->clip.y + priv->clip.height);
3398 else if (priv->clip_to_allocation)
3400 gfloat width, height;
3402 width = priv->allocation.x2 - priv->allocation.x1;
3403 height = priv->allocation.y2 - priv->allocation.y1;
3405 cogl_clip_push_rectangle (0, 0, width, height);
3409 if (pick_mode == CLUTTER_PICK_NONE)
3411 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3413 /* We check whether we need to add the flatten effect before
3414 each paint so that we can avoid having a mechanism for
3415 applications to notify when the value of the
3416 has_overlaps virtual changes. */
3417 add_or_remove_flatten_effect (self);
3420 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3422 /* We save the current paint volume so that the next time the
3423 * actor queues a redraw we can constrain the redraw to just
3424 * cover the union of the new bounding box and the old.
3426 * We also fetch the current paint volume to perform culling so
3427 * we can avoid painting actors outside the current clip region.
3429 * If we are painting inside a clone, we should neither update
3430 * the paint volume or use it to cull painting, since the paint
3431 * box represents the location of the source actor on the
3434 * XXX: We are starting to do a lot of vertex transforms on
3435 * the CPU in a typical paint, so at some point we should
3436 * audit these and consider caching some things.
3438 * NB: We don't perform culling while picking at this point because
3439 * clutter-stage.c doesn't setup the clipping planes appropriately.
3441 * NB: We don't want to update the last-paint-volume during picking
3442 * because the last-paint-volume is used to determine the old screen
3443 * space location of an actor that has moved so we can know the
3444 * minimal region to redraw to clear an old view of the actor. If we
3445 * update this during picking then by the time we come around to
3446 * paint then the last-paint-volume would likely represent the new
3447 * actor position not the old.
3449 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3452 /* annoyingly gcc warns if uninitialized even though
3453 * the initialization is redundant :-( */
3454 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3456 if (G_LIKELY ((clutter_paint_debug_flags &
3457 (CLUTTER_DEBUG_DISABLE_CULLING |
3458 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3459 (CLUTTER_DEBUG_DISABLE_CULLING |
3460 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3461 _clutter_actor_update_last_paint_volume (self);
3463 success = cull_actor (self, &result);
3465 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3466 _clutter_actor_paint_cull_result (self, success, result);
3467 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3471 if (priv->effects == NULL)
3473 if (pick_mode == CLUTTER_PICK_NONE &&
3474 actor_has_shader_data (self))
3476 _clutter_actor_shader_pre_paint (self, FALSE);
3477 shader_applied = TRUE;
3480 priv->next_effect_to_paint = NULL;
3483 priv->next_effect_to_paint =
3484 _clutter_meta_group_peek_metas (priv->effects);
3486 clutter_actor_continue_paint (self);
3489 _clutter_actor_shader_post_paint (self);
3491 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3492 pick_mode == CLUTTER_PICK_NONE))
3493 _clutter_actor_draw_paint_volume (self);
3496 /* If we make it here then the actor has run through a complete
3497 paint run including all the effects so it's no longer dirty */
3498 if (pick_mode == CLUTTER_PICK_NONE)
3499 priv->is_dirty = FALSE;
3506 /* paint sequence complete */
3507 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3511 * clutter_actor_continue_paint:
3512 * @self: A #ClutterActor
3514 * Run the next stage of the paint sequence. This function should only
3515 * be called within the implementation of the ‘run’ virtual of a
3516 * #ClutterEffect. It will cause the run method of the next effect to
3517 * be applied, or it will paint the actual actor if the current effect
3518 * is the last effect in the chain.
3523 clutter_actor_continue_paint (ClutterActor *self)
3525 ClutterActorPrivate *priv;
3527 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3528 /* This should only be called from with in the ‘run’ implementation
3529 of a ClutterEffect */
3530 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3534 /* Skip any effects that are disabled */
3535 while (priv->next_effect_to_paint &&
3536 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3537 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3539 /* If this has come from the last effect then we'll just paint the
3541 if (priv->next_effect_to_paint == NULL)
3543 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3545 ClutterPaintNode *dummy;
3547 /* XXX - this will go away in 2.0, when we can get rid of this
3548 * stuff and switch to a pure retained render tree of PaintNodes
3549 * for the entire frame, starting from the Stage; the paint()
3550 * virtual function can then be called directly.
3552 dummy = _clutter_dummy_node_new (self);
3553 clutter_paint_node_set_name (dummy, "Root");
3555 /* XXX - for 1.12, we use the return value of paint_node() to
3556 * decide whether we should emit the ::paint signal.
3558 clutter_actor_paint_node (self, dummy);
3559 clutter_paint_node_unref (dummy);
3561 g_signal_emit (self, actor_signals[PAINT], 0);
3565 ClutterColor col = { 0, };
3567 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3569 /* Actor will then paint silhouette of itself in supplied
3570 * color. See clutter_stage_get_actor_at_pos() for where
3571 * picking is enabled.
3573 g_signal_emit (self, actor_signals[PICK], 0, &col);
3578 ClutterEffect *old_current_effect;
3579 ClutterEffectPaintFlags run_flags = 0;
3581 /* Cache the current effect so that we can put it back before
3583 old_current_effect = priv->current_effect;
3585 priv->current_effect = priv->next_effect_to_paint->data;
3586 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3588 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3592 /* If there's an effect queued with this redraw then all
3593 effects up to that one will be considered dirty. It
3594 is expected the queued effect will paint the cached
3595 image and not call clutter_actor_continue_paint again
3596 (although it should work ok if it does) */
3597 if (priv->effect_to_redraw == NULL ||
3598 priv->current_effect != priv->effect_to_redraw)
3599 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3602 _clutter_effect_paint (priv->current_effect, run_flags);
3606 /* We can't determine when an actor has been modified since
3607 its last pick so lets just assume it has always been
3609 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3611 _clutter_effect_pick (priv->current_effect, run_flags);
3614 priv->current_effect = old_current_effect;
3618 static ClutterActorTraverseVisitFlags
3619 invalidate_queue_redraw_entry (ClutterActor *self,
3623 ClutterActorPrivate *priv = self->priv;
3625 if (priv->queue_redraw_entry != NULL)
3627 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3628 priv->queue_redraw_entry = NULL;
3631 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3635 remove_child (ClutterActor *self,
3636 ClutterActor *child)
3638 ClutterActor *prev_sibling, *next_sibling;
3640 prev_sibling = child->priv->prev_sibling;
3641 next_sibling = child->priv->next_sibling;
3643 if (prev_sibling != NULL)
3644 prev_sibling->priv->next_sibling = next_sibling;
3646 if (next_sibling != NULL)
3647 next_sibling->priv->prev_sibling = prev_sibling;
3649 if (self->priv->first_child == child)
3650 self->priv->first_child = next_sibling;
3652 if (self->priv->last_child == child)
3653 self->priv->last_child = prev_sibling;
3655 child->priv->parent = NULL;
3656 child->priv->prev_sibling = NULL;
3657 child->priv->next_sibling = NULL;
3661 REMOVE_CHILD_DESTROY_META = 1 << 0,
3662 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3663 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3664 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3665 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3666 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3668 /* default flags for public API */
3669 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3670 REMOVE_CHILD_EMIT_PARENT_SET |
3671 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3672 REMOVE_CHILD_CHECK_STATE |
3673 REMOVE_CHILD_FLUSH_QUEUE |
3674 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3676 /* flags for legacy/deprecated API */
3677 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3678 REMOVE_CHILD_FLUSH_QUEUE |
3679 REMOVE_CHILD_EMIT_PARENT_SET |
3680 REMOVE_CHILD_NOTIFY_FIRST_LAST
3681 } ClutterActorRemoveChildFlags;
3684 * clutter_actor_remove_child_internal:
3685 * @self: a #ClutterActor
3686 * @child: the child of @self that has to be removed
3687 * @flags: control the removal operations
3689 * Removes @child from the list of children of @self.
3692 clutter_actor_remove_child_internal (ClutterActor *self,
3693 ClutterActor *child,
3694 ClutterActorRemoveChildFlags flags)
3696 ClutterActor *old_first, *old_last;
3697 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3698 gboolean flush_queue;
3699 gboolean notify_first_last;
3700 gboolean was_mapped;
3702 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3703 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3704 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3705 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3706 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3707 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3709 g_object_freeze_notify (G_OBJECT (self));
3712 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3716 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3718 /* we need to unrealize *before* we set parent_actor to NULL,
3719 * because in an unrealize method actors are dissociating from the
3720 * stage, which means they need to be able to
3721 * clutter_actor_get_stage().
3723 * yhis should unmap and unrealize, unless we're reparenting.
3725 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3732 /* We take this opportunity to invalidate any queue redraw entry
3733 * associated with the actor and descendants since we won't be able to
3734 * determine the appropriate stage after this.
3736 * we do this after we updated the mapped state because actors might
3737 * end up queueing redraws inside their mapped/unmapped virtual
3738 * functions, and if we invalidate the redraw entry we could end up
3739 * with an inconsistent state and weird memory corruption. see
3742 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3743 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3745 _clutter_actor_traverse (child,
3747 invalidate_queue_redraw_entry,
3752 old_first = self->priv->first_child;
3753 old_last = self->priv->last_child;
3755 remove_child (self, child);
3757 self->priv->n_children -= 1;
3759 self->priv->age += 1;
3761 /* clutter_actor_reparent() will emit ::parent-set for us */
3762 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3763 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3765 /* if the child was mapped then we need to relayout ourselves to account
3766 * for the removed child
3769 clutter_actor_queue_relayout (self);
3771 /* we need to emit the signal before dropping the reference */
3772 if (emit_actor_removed)
3773 g_signal_emit_by_name (self, "actor-removed", child);
3775 if (notify_first_last)
3777 if (old_first != self->priv->first_child)
3778 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3780 if (old_last != self->priv->last_child)
3781 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3784 g_object_thaw_notify (G_OBJECT (self));
3786 /* remove the reference we acquired in clutter_actor_add_child() */
3787 g_object_unref (child);
3790 static const ClutterTransformInfo default_transform_info = {
3791 0.0, { 0, }, /* rotation-x */
3792 0.0, { 0, }, /* rotation-y */
3793 0.0, { 0, }, /* rotation-z */
3795 1.0, 1.0, { 0, }, /* scale */
3797 { 0, }, /* anchor */
3803 * _clutter_actor_get_transform_info_or_defaults:
3804 * @self: a #ClutterActor
3806 * Retrieves the ClutterTransformInfo structure associated to an actor.
3808 * If the actor does not have a ClutterTransformInfo structure associated
3809 * to it, then the default structure will be returned.
3811 * This function should only be used for getters.
3813 * Return value: a const pointer to the ClutterTransformInfo structure
3815 const ClutterTransformInfo *
3816 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3818 ClutterTransformInfo *info;
3820 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3824 return &default_transform_info;
3828 clutter_transform_info_free (gpointer data)
3831 g_slice_free (ClutterTransformInfo, data);
3835 * _clutter_actor_get_transform_info:
3836 * @self: a #ClutterActor
3838 * Retrieves a pointer to the ClutterTransformInfo structure.
3840 * If the actor does not have a ClutterTransformInfo associated to it, one
3841 * will be created and initialized to the default values.
3843 * This function should be used for setters.
3845 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3848 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3851 ClutterTransformInfo *
3852 _clutter_actor_get_transform_info (ClutterActor *self)
3854 ClutterTransformInfo *info;
3856 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3859 info = g_slice_new (ClutterTransformInfo);
3861 *info = default_transform_info;
3863 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3865 clutter_transform_info_free);
3872 * clutter_actor_set_rotation_angle_internal:
3873 * @self: a #ClutterActor
3874 * @axis: the axis of the angle to change
3875 * @angle: the angle of rotation
3877 * Sets the rotation angle on the given axis without affecting the
3878 * rotation center point.
3881 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3882 ClutterRotateAxis axis,
3885 GObject *obj = G_OBJECT (self);
3886 ClutterTransformInfo *info;
3888 info = _clutter_actor_get_transform_info (self);
3890 g_object_freeze_notify (obj);
3894 case CLUTTER_X_AXIS:
3895 info->rx_angle = angle;
3896 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3899 case CLUTTER_Y_AXIS:
3900 info->ry_angle = angle;
3901 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3904 case CLUTTER_Z_AXIS:
3905 info->rz_angle = angle;
3906 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3910 self->priv->transform_valid = FALSE;
3912 g_object_thaw_notify (obj);
3914 clutter_actor_queue_redraw (self);
3918 clutter_actor_set_rotation_angle (ClutterActor *self,
3919 ClutterRotateAxis axis,
3922 ClutterTransformInfo *info;
3924 info = _clutter_actor_get_transform_info (self);
3926 if (clutter_actor_get_easing_duration (self) != 0)
3928 ClutterTransition *transition;
3929 GParamSpec *pspec = NULL;
3930 double *cur_angle_p = NULL;
3934 case CLUTTER_X_AXIS:
3935 cur_angle_p = &info->rx_angle;
3936 pspec = obj_props[PROP_ROTATION_ANGLE_X];
3939 case CLUTTER_Y_AXIS:
3940 cur_angle_p = &info->ry_angle;
3941 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3944 case CLUTTER_Z_AXIS:
3945 cur_angle_p = &info->rz_angle;
3946 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3950 g_assert (pspec != NULL);
3951 g_assert (cur_angle_p != NULL);
3953 transition = _clutter_actor_get_transition (self, pspec);
3954 if (transition == NULL)
3956 transition = _clutter_actor_create_transition (self, pspec,
3959 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3962 _clutter_actor_update_transition (self, pspec, angle);
3964 self->priv->transform_valid = FALSE;
3965 clutter_actor_queue_redraw (self);
3968 clutter_actor_set_rotation_angle_internal (self, axis, angle);
3972 * clutter_actor_set_rotation_center_internal:
3973 * @self: a #ClutterActor
3974 * @axis: the axis of the center to change
3975 * @center: the coordinates of the rotation center
3977 * Sets the rotation center on the given axis without affecting the
3981 clutter_actor_set_rotation_center_internal (ClutterActor *self,
3982 ClutterRotateAxis axis,
3983 const ClutterVertex *center)
3985 GObject *obj = G_OBJECT (self);
3986 ClutterTransformInfo *info;
3987 ClutterVertex v = { 0, 0, 0 };
3989 info = _clutter_actor_get_transform_info (self);
3994 g_object_freeze_notify (obj);
3998 case CLUTTER_X_AXIS:
3999 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4000 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4003 case CLUTTER_Y_AXIS:
4004 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4005 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4008 case CLUTTER_Z_AXIS:
4009 /* if the previously set rotation center was fractional, then
4010 * setting explicit coordinates will have to notify the
4011 * :rotation-center-z-gravity property as well
4013 if (info->rz_center.is_fractional)
4014 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4016 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4017 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4021 self->priv->transform_valid = FALSE;
4023 g_object_thaw_notify (obj);
4025 clutter_actor_queue_redraw (self);
4029 clutter_actor_animate_scale_factor (ClutterActor *self,
4034 ClutterTransition *transition;
4036 transition = _clutter_actor_get_transition (self, pspec);
4037 if (transition == NULL)
4039 transition = _clutter_actor_create_transition (self, pspec,
4042 clutter_timeline_start (CLUTTER_TIMELINE (transition));
4045 _clutter_actor_update_transition (self, pspec, new_factor);
4048 self->priv->transform_valid = FALSE;
4049 clutter_actor_queue_redraw (self);
4053 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4057 GObject *obj = G_OBJECT (self);
4058 ClutterTransformInfo *info;
4060 info = _clutter_actor_get_transform_info (self);
4062 if (pspec == obj_props[PROP_SCALE_X])
4063 info->scale_x = factor;
4065 info->scale_y = factor;
4067 self->priv->transform_valid = FALSE;
4068 clutter_actor_queue_redraw (self);
4069 g_object_notify_by_pspec (obj, pspec);
4073 clutter_actor_set_scale_factor (ClutterActor *self,
4074 ClutterRotateAxis axis,
4077 GObject *obj = G_OBJECT (self);
4078 ClutterTransformInfo *info;
4081 info = _clutter_actor_get_transform_info (self);
4083 g_object_freeze_notify (obj);
4087 case CLUTTER_X_AXIS:
4088 pspec = obj_props[PROP_SCALE_X];
4090 if (clutter_actor_get_easing_duration (self) != 0)
4091 clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4093 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4096 case CLUTTER_Y_AXIS:
4097 pspec = obj_props[PROP_SCALE_Y];
4099 if (clutter_actor_get_easing_duration (self) != 0)
4100 clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4102 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4106 g_assert_not_reached ();
4109 g_object_thaw_notify (obj);
4113 clutter_actor_set_scale_center (ClutterActor *self,
4114 ClutterRotateAxis axis,
4117 GObject *obj = G_OBJECT (self);
4118 ClutterTransformInfo *info;
4119 gfloat center_x, center_y;
4121 info = _clutter_actor_get_transform_info (self);
4123 g_object_freeze_notify (obj);
4125 /* get the current scale center coordinates */
4126 clutter_anchor_coord_get_units (self, &info->scale_center,
4131 /* we need to notify this too, because setting explicit coordinates will
4132 * change the gravity as a side effect
4134 if (info->scale_center.is_fractional)
4135 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4139 case CLUTTER_X_AXIS:
4140 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4141 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4144 case CLUTTER_Y_AXIS:
4145 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4146 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4150 g_assert_not_reached ();
4153 self->priv->transform_valid = FALSE;
4155 clutter_actor_queue_redraw (self);
4157 g_object_thaw_notify (obj);
4161 clutter_actor_set_scale_gravity (ClutterActor *self,
4162 ClutterGravity gravity)
4164 ClutterTransformInfo *info;
4167 info = _clutter_actor_get_transform_info (self);
4168 obj = G_OBJECT (self);
4170 if (gravity == CLUTTER_GRAVITY_NONE)
4171 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4173 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4175 self->priv->transform_valid = FALSE;
4177 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4178 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4179 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4181 clutter_actor_queue_redraw (self);
4185 clutter_actor_set_anchor_coord (ClutterActor *self,
4186 ClutterRotateAxis axis,
4189 GObject *obj = G_OBJECT (self);
4190 ClutterTransformInfo *info;
4191 gfloat anchor_x, anchor_y;
4193 info = _clutter_actor_get_transform_info (self);
4195 g_object_freeze_notify (obj);
4197 clutter_anchor_coord_get_units (self, &info->anchor,
4202 if (info->anchor.is_fractional)
4203 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4207 case CLUTTER_X_AXIS:
4208 clutter_anchor_coord_set_units (&info->anchor,
4212 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4215 case CLUTTER_Y_AXIS:
4216 clutter_anchor_coord_set_units (&info->anchor,
4220 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4224 g_assert_not_reached ();
4227 self->priv->transform_valid = FALSE;
4229 clutter_actor_queue_redraw (self);
4231 g_object_thaw_notify (obj);
4235 clutter_actor_set_property (GObject *object,
4237 const GValue *value,
4240 ClutterActor *actor = CLUTTER_ACTOR (object);
4241 ClutterActorPrivate *priv = actor->priv;
4246 clutter_actor_set_x (actor, g_value_get_float (value));
4250 clutter_actor_set_y (actor, g_value_get_float (value));
4254 clutter_actor_set_width (actor, g_value_get_float (value));
4258 clutter_actor_set_height (actor, g_value_get_float (value));
4262 clutter_actor_set_x (actor, g_value_get_float (value));
4266 clutter_actor_set_y (actor, g_value_get_float (value));
4269 case PROP_FIXED_POSITION_SET:
4270 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4273 case PROP_MIN_WIDTH:
4274 clutter_actor_set_min_width (actor, g_value_get_float (value));
4277 case PROP_MIN_HEIGHT:
4278 clutter_actor_set_min_height (actor, g_value_get_float (value));
4281 case PROP_NATURAL_WIDTH:
4282 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4285 case PROP_NATURAL_HEIGHT:
4286 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4289 case PROP_MIN_WIDTH_SET:
4290 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4293 case PROP_MIN_HEIGHT_SET:
4294 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4297 case PROP_NATURAL_WIDTH_SET:
4298 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4301 case PROP_NATURAL_HEIGHT_SET:
4302 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4305 case PROP_REQUEST_MODE:
4306 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4310 clutter_actor_set_depth (actor, g_value_get_float (value));
4314 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4317 case PROP_OFFSCREEN_REDIRECT:
4318 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4322 clutter_actor_set_name (actor, g_value_get_string (value));
4326 if (g_value_get_boolean (value) == TRUE)
4327 clutter_actor_show (actor);
4329 clutter_actor_hide (actor);
4333 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4334 g_value_get_double (value));
4338 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4339 g_value_get_double (value));
4342 case PROP_SCALE_CENTER_X:
4343 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4344 g_value_get_float (value));
4347 case PROP_SCALE_CENTER_Y:
4348 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4349 g_value_get_float (value));
4352 case PROP_SCALE_GRAVITY:
4353 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4358 const ClutterGeometry *geom = g_value_get_boxed (value);
4360 clutter_actor_set_clip (actor,
4362 geom->width, geom->height);
4366 case PROP_CLIP_TO_ALLOCATION:
4367 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4371 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4374 case PROP_ROTATION_ANGLE_X:
4375 clutter_actor_set_rotation_angle (actor,
4377 g_value_get_double (value));
4380 case PROP_ROTATION_ANGLE_Y:
4381 clutter_actor_set_rotation_angle (actor,
4383 g_value_get_double (value));
4386 case PROP_ROTATION_ANGLE_Z:
4387 clutter_actor_set_rotation_angle (actor,
4389 g_value_get_double (value));
4392 case PROP_ROTATION_CENTER_X:
4393 clutter_actor_set_rotation_center_internal (actor,
4395 g_value_get_boxed (value));
4398 case PROP_ROTATION_CENTER_Y:
4399 clutter_actor_set_rotation_center_internal (actor,
4401 g_value_get_boxed (value));
4404 case PROP_ROTATION_CENTER_Z:
4405 clutter_actor_set_rotation_center_internal (actor,
4407 g_value_get_boxed (value));
4410 case PROP_ROTATION_CENTER_Z_GRAVITY:
4412 const ClutterTransformInfo *info;
4414 info = _clutter_actor_get_transform_info_or_defaults (actor);
4415 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4416 g_value_get_enum (value));
4421 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4422 g_value_get_float (value));
4426 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4427 g_value_get_float (value));
4430 case PROP_ANCHOR_GRAVITY:
4431 clutter_actor_set_anchor_point_from_gravity (actor,
4432 g_value_get_enum (value));
4435 case PROP_SHOW_ON_SET_PARENT:
4436 priv->show_on_set_parent = g_value_get_boolean (value);
4439 case PROP_TEXT_DIRECTION:
4440 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4444 clutter_actor_add_action (actor, g_value_get_object (value));
4447 case PROP_CONSTRAINTS:
4448 clutter_actor_add_constraint (actor, g_value_get_object (value));
4452 clutter_actor_add_effect (actor, g_value_get_object (value));
4455 case PROP_LAYOUT_MANAGER:
4456 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4460 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4464 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4467 case PROP_MARGIN_TOP:
4468 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4471 case PROP_MARGIN_BOTTOM:
4472 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4475 case PROP_MARGIN_LEFT:
4476 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4479 case PROP_MARGIN_RIGHT:
4480 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4483 case PROP_BACKGROUND_COLOR:
4484 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4488 clutter_actor_set_content (actor, g_value_get_object (value));
4491 case PROP_CONTENT_GRAVITY:
4492 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4495 case PROP_MINIFICATION_FILTER:
4496 clutter_actor_set_content_scaling_filters (actor,
4497 g_value_get_enum (value),
4498 actor->priv->mag_filter);
4501 case PROP_MAGNIFICATION_FILTER:
4502 clutter_actor_set_content_scaling_filters (actor,
4503 actor->priv->min_filter,
4504 g_value_get_enum (value));
4508 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4514 clutter_actor_get_property (GObject *object,
4519 ClutterActor *actor = CLUTTER_ACTOR (object);
4520 ClutterActorPrivate *priv = actor->priv;
4525 g_value_set_float (value, clutter_actor_get_x (actor));
4529 g_value_set_float (value, clutter_actor_get_y (actor));
4533 g_value_set_float (value, clutter_actor_get_width (actor));
4537 g_value_set_float (value, clutter_actor_get_height (actor));
4542 const ClutterLayoutInfo *info;
4544 info = _clutter_actor_get_layout_info_or_defaults (actor);
4545 g_value_set_float (value, info->fixed_x);
4551 const ClutterLayoutInfo *info;
4553 info = _clutter_actor_get_layout_info_or_defaults (actor);
4554 g_value_set_float (value, info->fixed_y);
4558 case PROP_FIXED_POSITION_SET:
4559 g_value_set_boolean (value, priv->position_set);
4562 case PROP_MIN_WIDTH:
4564 const ClutterLayoutInfo *info;
4566 info = _clutter_actor_get_layout_info_or_defaults (actor);
4567 g_value_set_float (value, info->min_width);
4571 case PROP_MIN_HEIGHT:
4573 const ClutterLayoutInfo *info;
4575 info = _clutter_actor_get_layout_info_or_defaults (actor);
4576 g_value_set_float (value, info->min_height);
4580 case PROP_NATURAL_WIDTH:
4582 const ClutterLayoutInfo *info;
4584 info = _clutter_actor_get_layout_info_or_defaults (actor);
4585 g_value_set_float (value, info->natural_width);
4589 case PROP_NATURAL_HEIGHT:
4591 const ClutterLayoutInfo *info;
4593 info = _clutter_actor_get_layout_info_or_defaults (actor);
4594 g_value_set_float (value, info->natural_height);
4598 case PROP_MIN_WIDTH_SET:
4599 g_value_set_boolean (value, priv->min_width_set);
4602 case PROP_MIN_HEIGHT_SET:
4603 g_value_set_boolean (value, priv->min_height_set);
4606 case PROP_NATURAL_WIDTH_SET:
4607 g_value_set_boolean (value, priv->natural_width_set);
4610 case PROP_NATURAL_HEIGHT_SET:
4611 g_value_set_boolean (value, priv->natural_height_set);
4614 case PROP_REQUEST_MODE:
4615 g_value_set_enum (value, priv->request_mode);
4618 case PROP_ALLOCATION:
4619 g_value_set_boxed (value, &priv->allocation);
4623 g_value_set_float (value, clutter_actor_get_depth (actor));
4627 g_value_set_uint (value, priv->opacity);
4630 case PROP_OFFSCREEN_REDIRECT:
4631 g_value_set_enum (value, priv->offscreen_redirect);
4635 g_value_set_string (value, priv->name);
4639 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4643 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4647 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4651 g_value_set_boolean (value, priv->has_clip);
4656 ClutterGeometry clip;
4658 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4659 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4660 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4661 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4663 g_value_set_boxed (value, &clip);
4667 case PROP_CLIP_TO_ALLOCATION:
4668 g_value_set_boolean (value, priv->clip_to_allocation);
4673 const ClutterTransformInfo *info;
4675 info = _clutter_actor_get_transform_info_or_defaults (actor);
4676 g_value_set_double (value, info->scale_x);
4682 const ClutterTransformInfo *info;
4684 info = _clutter_actor_get_transform_info_or_defaults (actor);
4685 g_value_set_double (value, info->scale_y);
4689 case PROP_SCALE_CENTER_X:
4693 clutter_actor_get_scale_center (actor, ¢er, NULL);
4695 g_value_set_float (value, center);
4699 case PROP_SCALE_CENTER_Y:
4703 clutter_actor_get_scale_center (actor, NULL, ¢er);
4705 g_value_set_float (value, center);
4709 case PROP_SCALE_GRAVITY:
4710 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4714 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4717 case PROP_ROTATION_ANGLE_X:
4719 const ClutterTransformInfo *info;
4721 info = _clutter_actor_get_transform_info_or_defaults (actor);
4722 g_value_set_double (value, info->rx_angle);
4726 case PROP_ROTATION_ANGLE_Y:
4728 const ClutterTransformInfo *info;
4730 info = _clutter_actor_get_transform_info_or_defaults (actor);
4731 g_value_set_double (value, info->ry_angle);
4735 case PROP_ROTATION_ANGLE_Z:
4737 const ClutterTransformInfo *info;
4739 info = _clutter_actor_get_transform_info_or_defaults (actor);
4740 g_value_set_double (value, info->rz_angle);
4744 case PROP_ROTATION_CENTER_X:
4746 ClutterVertex center;
4748 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4753 g_value_set_boxed (value, ¢er);
4757 case PROP_ROTATION_CENTER_Y:
4759 ClutterVertex center;
4761 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4766 g_value_set_boxed (value, ¢er);
4770 case PROP_ROTATION_CENTER_Z:
4772 ClutterVertex center;
4774 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4779 g_value_set_boxed (value, ¢er);
4783 case PROP_ROTATION_CENTER_Z_GRAVITY:
4784 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4789 const ClutterTransformInfo *info;
4792 info = _clutter_actor_get_transform_info_or_defaults (actor);
4793 clutter_anchor_coord_get_units (actor, &info->anchor,
4797 g_value_set_float (value, anchor_x);
4803 const ClutterTransformInfo *info;
4806 info = _clutter_actor_get_transform_info_or_defaults (actor);
4807 clutter_anchor_coord_get_units (actor, &info->anchor,
4811 g_value_set_float (value, anchor_y);
4815 case PROP_ANCHOR_GRAVITY:
4816 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4819 case PROP_SHOW_ON_SET_PARENT:
4820 g_value_set_boolean (value, priv->show_on_set_parent);
4823 case PROP_TEXT_DIRECTION:
4824 g_value_set_enum (value, priv->text_direction);
4827 case PROP_HAS_POINTER:
4828 g_value_set_boolean (value, priv->has_pointer);
4831 case PROP_LAYOUT_MANAGER:
4832 g_value_set_object (value, priv->layout_manager);
4837 const ClutterLayoutInfo *info;
4839 info = _clutter_actor_get_layout_info_or_defaults (actor);
4840 g_value_set_enum (value, info->x_align);
4846 const ClutterLayoutInfo *info;
4848 info = _clutter_actor_get_layout_info_or_defaults (actor);
4849 g_value_set_enum (value, info->y_align);
4853 case PROP_MARGIN_TOP:
4855 const ClutterLayoutInfo *info;
4857 info = _clutter_actor_get_layout_info_or_defaults (actor);
4858 g_value_set_float (value, info->margin.top);
4862 case PROP_MARGIN_BOTTOM:
4864 const ClutterLayoutInfo *info;
4866 info = _clutter_actor_get_layout_info_or_defaults (actor);
4867 g_value_set_float (value, info->margin.bottom);
4871 case PROP_MARGIN_LEFT:
4873 const ClutterLayoutInfo *info;
4875 info = _clutter_actor_get_layout_info_or_defaults (actor);
4876 g_value_set_float (value, info->margin.left);
4880 case PROP_MARGIN_RIGHT:
4882 const ClutterLayoutInfo *info;
4884 info = _clutter_actor_get_layout_info_or_defaults (actor);
4885 g_value_set_float (value, info->margin.right);
4889 case PROP_BACKGROUND_COLOR_SET:
4890 g_value_set_boolean (value, priv->bg_color_set);
4893 case PROP_BACKGROUND_COLOR:
4894 g_value_set_boxed (value, &priv->bg_color);
4897 case PROP_FIRST_CHILD:
4898 g_value_set_object (value, priv->first_child);
4901 case PROP_LAST_CHILD:
4902 g_value_set_object (value, priv->last_child);
4906 g_value_set_object (value, priv->content);
4909 case PROP_CONTENT_GRAVITY:
4910 g_value_set_enum (value, priv->content_gravity);
4913 case PROP_CONTENT_BOX:
4915 ClutterActorBox box = { 0, };
4917 clutter_actor_get_content_box (actor, &box);
4918 g_value_set_boxed (value, &box);
4922 case PROP_MINIFICATION_FILTER:
4923 g_value_set_enum (value, priv->min_filter);
4926 case PROP_MAGNIFICATION_FILTER:
4927 g_value_set_enum (value, priv->mag_filter);
4931 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4937 clutter_actor_dispose (GObject *object)
4939 ClutterActor *self = CLUTTER_ACTOR (object);
4940 ClutterActorPrivate *priv = self->priv;
4942 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4944 g_type_name (G_OBJECT_TYPE (self)),
4947 g_signal_emit (self, actor_signals[DESTROY], 0);
4949 /* avoid recursing when called from clutter_actor_destroy() */
4950 if (priv->parent != NULL)
4952 ClutterActor *parent = priv->parent;
4954 /* go through the Container implementation unless this
4955 * is an internal child and has been marked as such.
4957 * removing the actor from its parent will reset the
4958 * realized and mapped states.
4960 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4961 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4963 clutter_actor_remove_child_internal (parent, self,
4964 REMOVE_CHILD_LEGACY_FLAGS);
4967 /* parent must be gone at this point */
4968 g_assert (priv->parent == NULL);
4970 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4972 /* can't be mapped or realized with no parent */
4973 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4974 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4977 g_clear_object (&priv->pango_context);
4978 g_clear_object (&priv->actions);
4979 g_clear_object (&priv->constraints);
4980 g_clear_object (&priv->effects);
4981 g_clear_object (&priv->flatten_effect);
4983 if (priv->layout_manager != NULL)
4985 clutter_layout_manager_set_container (priv->layout_manager, NULL);
4986 g_clear_object (&priv->layout_manager);
4989 if (priv->content != NULL)
4991 _clutter_content_detached (priv->content, self);
4992 g_clear_object (&priv->content);
4995 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4999 clutter_actor_finalize (GObject *object)
5001 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5003 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5004 priv->name != NULL ? priv->name : "<none>",
5006 g_type_name (G_OBJECT_TYPE (object)));
5008 _clutter_context_release_id (priv->id);
5010 g_free (priv->name);
5012 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5017 * clutter_actor_get_accessible:
5018 * @self: a #ClutterActor
5020 * Returns the accessible object that describes the actor to an
5021 * assistive technology.
5023 * If no class-specific #AtkObject implementation is available for the
5024 * actor instance in question, it will inherit an #AtkObject
5025 * implementation from the first ancestor class for which such an
5026 * implementation is defined.
5028 * The documentation of the <ulink
5029 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5030 * library contains more information about accessible objects and
5033 * Returns: (transfer none): the #AtkObject associated with @actor
5036 clutter_actor_get_accessible (ClutterActor *self)
5038 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5040 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5044 clutter_actor_real_get_accessible (ClutterActor *actor)
5046 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5050 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5052 AtkObject *accessible;
5054 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5055 if (accessible != NULL)
5056 g_object_ref (accessible);
5062 atk_implementor_iface_init (AtkImplementorIface *iface)
5064 iface->ref_accessible = _clutter_actor_ref_accessible;
5068 clutter_actor_update_default_paint_volume (ClutterActor *self,
5069 ClutterPaintVolume *volume)
5071 ClutterActorPrivate *priv = self->priv;
5072 gboolean res = FALSE;
5074 /* we start from the allocation */
5075 clutter_paint_volume_set_width (volume,
5076 priv->allocation.x2 - priv->allocation.x1);
5077 clutter_paint_volume_set_height (volume,
5078 priv->allocation.y2 - priv->allocation.y1);
5080 /* if the actor has a clip set then we have a pretty definite
5081 * size for the paint volume: the actor cannot possibly paint
5082 * outside the clip region.
5084 if (priv->clip_to_allocation)
5086 /* the allocation has already been set, so we just flip the
5093 ClutterActor *child;
5095 if (priv->has_clip &&
5096 priv->clip.width >= 0 &&
5097 priv->clip.height >= 0)
5099 ClutterVertex origin;
5101 origin.x = priv->clip.x;
5102 origin.y = priv->clip.y;
5105 clutter_paint_volume_set_origin (volume, &origin);
5106 clutter_paint_volume_set_width (volume, priv->clip.width);
5107 clutter_paint_volume_set_height (volume, priv->clip.height);
5112 /* if we don't have children we just bail out here... */
5113 if (priv->n_children == 0)
5116 /* ...but if we have children then we ask for their paint volume in
5117 * our coordinates. if any of our children replies that it doesn't
5118 * have a paint volume, we bail out
5120 for (child = priv->first_child;
5122 child = child->priv->next_sibling)
5124 const ClutterPaintVolume *child_volume;
5126 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5127 if (child_volume == NULL)
5133 clutter_paint_volume_union (volume, child_volume);
5143 clutter_actor_real_get_paint_volume (ClutterActor *self,
5144 ClutterPaintVolume *volume)
5146 ClutterActorClass *klass;
5149 klass = CLUTTER_ACTOR_GET_CLASS (self);
5151 /* XXX - this thoroughly sucks, but we don't want to penalize users
5152 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5153 * redraw. This should go away in 2.0.
5155 if (klass->paint == clutter_actor_real_paint &&
5156 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5162 /* this is the default return value: we cannot know if a class
5163 * is going to paint outside its allocation, so we take the
5164 * conservative approach.
5169 if (clutter_actor_update_default_paint_volume (self, volume))
5176 * clutter_actor_get_default_paint_volume:
5177 * @self: a #ClutterActor
5179 * Retrieves the default paint volume for @self.
5181 * This function provides the same #ClutterPaintVolume that would be
5182 * computed by the default implementation inside #ClutterActor of the
5183 * #ClutterActorClass.get_paint_volume() virtual function.
5185 * This function should only be used by #ClutterActor subclasses that
5186 * cannot chain up to the parent implementation when computing their
5189 * Return value: (transfer none): a pointer to the default
5190 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5191 * the actor could not compute a valid paint volume. The returned value
5192 * is not guaranteed to be stable across multiple frames, so if you
5193 * want to retain it, you will need to copy it using
5194 * clutter_paint_volume_copy().
5198 const ClutterPaintVolume *
5199 clutter_actor_get_default_paint_volume (ClutterActor *self)
5201 ClutterPaintVolume volume;
5202 ClutterPaintVolume *res;
5204 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5207 _clutter_paint_volume_init_static (&volume, self);
5208 if (clutter_actor_update_default_paint_volume (self, &volume))
5210 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5214 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5215 _clutter_paint_volume_copy_static (&volume, res);
5219 clutter_paint_volume_free (&volume);
5225 clutter_actor_real_has_overlaps (ClutterActor *self)
5227 /* By default we'll assume that all actors need an offscreen redirect to get
5228 * the correct opacity. Actors such as ClutterTexture that would never need
5229 * an offscreen redirect can override this to return FALSE. */
5234 clutter_actor_real_destroy (ClutterActor *actor)
5236 ClutterActorIter iter;
5238 clutter_actor_iter_init (&iter, actor);
5239 while (clutter_actor_iter_next (&iter, NULL))
5240 clutter_actor_iter_destroy (&iter);
5244 clutter_actor_constructor (GType gtype,
5246 GObjectConstructParam *props)
5248 GObjectClass *gobject_class;
5252 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5253 retval = gobject_class->constructor (gtype, n_props, props);
5254 self = CLUTTER_ACTOR (retval);
5256 if (self->priv->layout_manager == NULL)
5258 ClutterLayoutManager *default_layout;
5260 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5262 default_layout = clutter_fixed_layout_new ();
5263 clutter_actor_set_layout_manager (self, default_layout);
5270 clutter_actor_class_init (ClutterActorClass *klass)
5272 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5274 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5275 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5276 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5277 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5279 object_class->constructor = clutter_actor_constructor;
5280 object_class->set_property = clutter_actor_set_property;
5281 object_class->get_property = clutter_actor_get_property;
5282 object_class->dispose = clutter_actor_dispose;
5283 object_class->finalize = clutter_actor_finalize;
5285 klass->show = clutter_actor_real_show;
5286 klass->show_all = clutter_actor_show;
5287 klass->hide = clutter_actor_real_hide;
5288 klass->hide_all = clutter_actor_hide;
5289 klass->map = clutter_actor_real_map;
5290 klass->unmap = clutter_actor_real_unmap;
5291 klass->unrealize = clutter_actor_real_unrealize;
5292 klass->pick = clutter_actor_real_pick;
5293 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5294 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5295 klass->allocate = clutter_actor_real_allocate;
5296 klass->queue_redraw = clutter_actor_real_queue_redraw;
5297 klass->queue_relayout = clutter_actor_real_queue_relayout;
5298 klass->apply_transform = clutter_actor_real_apply_transform;
5299 klass->get_accessible = clutter_actor_real_get_accessible;
5300 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5301 klass->has_overlaps = clutter_actor_real_has_overlaps;
5302 klass->paint = clutter_actor_real_paint;
5303 klass->destroy = clutter_actor_real_destroy;
5305 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5310 * X coordinate of the actor in pixels. If written, forces a fixed
5311 * position for the actor. If read, returns the fixed position if any,
5312 * otherwise the allocation if available, otherwise 0.
5314 * The #ClutterActor:x property is animatable.
5317 g_param_spec_float ("x",
5319 P_("X coordinate of the actor"),
5320 -G_MAXFLOAT, G_MAXFLOAT,
5323 G_PARAM_STATIC_STRINGS |
5324 CLUTTER_PARAM_ANIMATABLE);
5329 * Y coordinate of the actor in pixels. If written, forces a fixed
5330 * position for the actor. If read, returns the fixed position if
5331 * any, otherwise the allocation if available, otherwise 0.
5333 * The #ClutterActor:y property is animatable.
5336 g_param_spec_float ("y",
5338 P_("Y coordinate of the actor"),
5339 -G_MAXFLOAT, G_MAXFLOAT,
5342 G_PARAM_STATIC_STRINGS |
5343 CLUTTER_PARAM_ANIMATABLE);
5346 * ClutterActor:width:
5348 * Width of the actor (in pixels). If written, forces the minimum and
5349 * natural size request of the actor to the given width. If read, returns
5350 * the allocated width if available, otherwise the width request.
5352 * The #ClutterActor:width property is animatable.
5354 obj_props[PROP_WIDTH] =
5355 g_param_spec_float ("width",
5357 P_("Width of the actor"),
5361 G_PARAM_STATIC_STRINGS |
5362 CLUTTER_PARAM_ANIMATABLE);
5365 * ClutterActor:height:
5367 * Height of the actor (in pixels). If written, forces the minimum and
5368 * natural size request of the actor to the given height. If read, returns
5369 * the allocated height if available, otherwise the height request.
5371 * The #ClutterActor:height property is animatable.
5373 obj_props[PROP_HEIGHT] =
5374 g_param_spec_float ("height",
5376 P_("Height of the actor"),
5380 G_PARAM_STATIC_STRINGS |
5381 CLUTTER_PARAM_ANIMATABLE);
5384 * ClutterActor:fixed-x:
5386 * The fixed X position of the actor in pixels.
5388 * Writing this property sets #ClutterActor:fixed-position-set
5389 * property as well, as a side effect
5393 obj_props[PROP_FIXED_X] =
5394 g_param_spec_float ("fixed-x",
5396 P_("Forced X position of the actor"),
5397 -G_MAXFLOAT, G_MAXFLOAT,
5399 CLUTTER_PARAM_READWRITE);
5402 * ClutterActor:fixed-y:
5404 * The fixed Y position of the actor in pixels.
5406 * Writing this property sets the #ClutterActor:fixed-position-set
5407 * property as well, as a side effect
5411 obj_props[PROP_FIXED_Y] =
5412 g_param_spec_float ("fixed-y",
5414 P_("Forced Y position of the actor"),
5415 -G_MAXFLOAT, G_MAXFLOAT,
5417 CLUTTER_PARAM_READWRITE);
5420 * ClutterActor:fixed-position-set:
5422 * This flag controls whether the #ClutterActor:fixed-x and
5423 * #ClutterActor:fixed-y properties are used
5427 obj_props[PROP_FIXED_POSITION_SET] =
5428 g_param_spec_boolean ("fixed-position-set",
5429 P_("Fixed position set"),
5430 P_("Whether to use fixed positioning for the actor"),
5432 CLUTTER_PARAM_READWRITE);
5435 * ClutterActor:min-width:
5437 * A forced minimum width request for the actor, in pixels
5439 * Writing this property sets the #ClutterActor:min-width-set property
5440 * as well, as a side effect.
5442 *This property overrides the usual width request of the actor.
5446 obj_props[PROP_MIN_WIDTH] =
5447 g_param_spec_float ("min-width",
5449 P_("Forced minimum width request for the actor"),
5452 CLUTTER_PARAM_READWRITE);
5455 * ClutterActor:min-height:
5457 * A forced minimum height request for the actor, in pixels
5459 * Writing this property sets the #ClutterActor:min-height-set property
5460 * as well, as a side effect. This property overrides the usual height
5461 * request of the actor.
5465 obj_props[PROP_MIN_HEIGHT] =
5466 g_param_spec_float ("min-height",
5468 P_("Forced minimum height request for the actor"),
5471 CLUTTER_PARAM_READWRITE);
5474 * ClutterActor:natural-width:
5476 * A forced natural width request for the actor, in pixels
5478 * Writing this property sets the #ClutterActor:natural-width-set
5479 * property as well, as a side effect. This property overrides the
5480 * usual width request of the actor
5484 obj_props[PROP_NATURAL_WIDTH] =
5485 g_param_spec_float ("natural-width",
5486 P_("Natural Width"),
5487 P_("Forced natural width request for the actor"),
5490 CLUTTER_PARAM_READWRITE);
5493 * ClutterActor:natural-height:
5495 * A forced natural height request for the actor, in pixels
5497 * Writing this property sets the #ClutterActor:natural-height-set
5498 * property as well, as a side effect. This property overrides the
5499 * usual height request of the actor
5503 obj_props[PROP_NATURAL_HEIGHT] =
5504 g_param_spec_float ("natural-height",
5505 P_("Natural Height"),
5506 P_("Forced natural height request for the actor"),
5509 CLUTTER_PARAM_READWRITE);
5512 * ClutterActor:min-width-set:
5514 * This flag controls whether the #ClutterActor:min-width property
5519 obj_props[PROP_MIN_WIDTH_SET] =
5520 g_param_spec_boolean ("min-width-set",
5521 P_("Minimum width set"),
5522 P_("Whether to use the min-width property"),
5524 CLUTTER_PARAM_READWRITE);
5527 * ClutterActor:min-height-set:
5529 * This flag controls whether the #ClutterActor:min-height property
5534 obj_props[PROP_MIN_HEIGHT_SET] =
5535 g_param_spec_boolean ("min-height-set",
5536 P_("Minimum height set"),
5537 P_("Whether to use the min-height property"),
5539 CLUTTER_PARAM_READWRITE);
5542 * ClutterActor:natural-width-set:
5544 * This flag controls whether the #ClutterActor:natural-width property
5549 obj_props[PROP_NATURAL_WIDTH_SET] =
5550 g_param_spec_boolean ("natural-width-set",
5551 P_("Natural width set"),
5552 P_("Whether to use the natural-width property"),
5554 CLUTTER_PARAM_READWRITE);
5557 * ClutterActor:natural-height-set:
5559 * This flag controls whether the #ClutterActor:natural-height property
5564 obj_props[PROP_NATURAL_HEIGHT_SET] =
5565 g_param_spec_boolean ("natural-height-set",
5566 P_("Natural height set"),
5567 P_("Whether to use the natural-height property"),
5569 CLUTTER_PARAM_READWRITE);
5572 * ClutterActor:allocation:
5574 * The allocation for the actor, in pixels
5576 * This is property is read-only, but you might monitor it to know when an
5577 * actor moves or resizes
5581 obj_props[PROP_ALLOCATION] =
5582 g_param_spec_boxed ("allocation",
5584 P_("The actor's allocation"),
5585 CLUTTER_TYPE_ACTOR_BOX,
5586 CLUTTER_PARAM_READABLE);
5589 * ClutterActor:request-mode:
5591 * Request mode for the #ClutterActor. The request mode determines the
5592 * type of geometry management used by the actor, either height for width
5593 * (the default) or width for height.
5595 * For actors implementing height for width, the parent container should get
5596 * the preferred width first, and then the preferred height for that width.
5598 * For actors implementing width for height, the parent container should get
5599 * the preferred height first, and then the preferred width for that height.
5604 * ClutterRequestMode mode;
5605 * gfloat natural_width, min_width;
5606 * gfloat natural_height, min_height;
5608 * mode = clutter_actor_get_request_mode (child);
5609 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5611 * clutter_actor_get_preferred_width (child, -1,
5613 * &natural_width);
5614 * clutter_actor_get_preferred_height (child, natural_width,
5616 * &natural_height);
5620 * clutter_actor_get_preferred_height (child, -1,
5622 * &natural_height);
5623 * clutter_actor_get_preferred_width (child, natural_height,
5625 * &natural_width);
5629 * will retrieve the minimum and natural width and height depending on the
5630 * preferred request mode of the #ClutterActor "child".
5632 * The clutter_actor_get_preferred_size() function will implement this
5637 obj_props[PROP_REQUEST_MODE] =
5638 g_param_spec_enum ("request-mode",
5640 P_("The actor's request mode"),
5641 CLUTTER_TYPE_REQUEST_MODE,
5642 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5643 CLUTTER_PARAM_READWRITE);
5646 * ClutterActor:depth:
5648 * The position of the actor on the Z axis.
5650 * The #ClutterActor:depth property is relative to the parent's
5653 * The #ClutterActor:depth property is animatable.
5657 obj_props[PROP_DEPTH] =
5658 g_param_spec_float ("depth",
5660 P_("Position on the Z axis"),
5661 -G_MAXFLOAT, G_MAXFLOAT,
5664 G_PARAM_STATIC_STRINGS |
5665 CLUTTER_PARAM_ANIMATABLE);
5668 * ClutterActor:opacity:
5670 * Opacity of an actor, between 0 (fully transparent) and
5671 * 255 (fully opaque)
5673 * The #ClutterActor:opacity property is animatable.
5675 obj_props[PROP_OPACITY] =
5676 g_param_spec_uint ("opacity",
5678 P_("Opacity of an actor"),
5682 G_PARAM_STATIC_STRINGS |
5683 CLUTTER_PARAM_ANIMATABLE);
5686 * ClutterActor:offscreen-redirect:
5688 * Determines the conditions in which the actor will be redirected
5689 * to an offscreen framebuffer while being painted. For example this
5690 * can be used to cache an actor in a framebuffer or for improved
5691 * handling of transparent actors. See
5692 * clutter_actor_set_offscreen_redirect() for details.
5696 obj_props[PROP_OFFSCREEN_REDIRECT] =
5697 g_param_spec_flags ("offscreen-redirect",
5698 P_("Offscreen redirect"),
5699 P_("Flags controlling when to flatten the actor into a single image"),
5700 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5702 CLUTTER_PARAM_READWRITE);
5705 * ClutterActor:visible:
5707 * Whether the actor is set to be visible or not
5709 * See also #ClutterActor:mapped
5711 obj_props[PROP_VISIBLE] =
5712 g_param_spec_boolean ("visible",
5714 P_("Whether the actor is visible or not"),
5716 CLUTTER_PARAM_READWRITE);
5719 * ClutterActor:mapped:
5721 * Whether the actor is mapped (will be painted when the stage
5722 * to which it belongs is mapped)
5726 obj_props[PROP_MAPPED] =
5727 g_param_spec_boolean ("mapped",
5729 P_("Whether the actor will be painted"),
5731 CLUTTER_PARAM_READABLE);
5734 * ClutterActor:realized:
5736 * Whether the actor has been realized
5740 obj_props[PROP_REALIZED] =
5741 g_param_spec_boolean ("realized",
5743 P_("Whether the actor has been realized"),
5745 CLUTTER_PARAM_READABLE);
5748 * ClutterActor:reactive:
5750 * Whether the actor is reactive to events or not
5752 * Only reactive actors will emit event-related signals
5756 obj_props[PROP_REACTIVE] =
5757 g_param_spec_boolean ("reactive",
5759 P_("Whether the actor is reactive to events"),
5761 CLUTTER_PARAM_READWRITE);
5764 * ClutterActor:has-clip:
5766 * Whether the actor has the #ClutterActor:clip property set or not
5768 obj_props[PROP_HAS_CLIP] =
5769 g_param_spec_boolean ("has-clip",
5771 P_("Whether the actor has a clip set"),
5773 CLUTTER_PARAM_READABLE);
5776 * ClutterActor:clip:
5778 * The clip region for the actor, in actor-relative coordinates
5780 * Every part of the actor outside the clip region will not be
5783 obj_props[PROP_CLIP] =
5784 g_param_spec_boxed ("clip",
5786 P_("The clip region for the actor"),
5787 CLUTTER_TYPE_GEOMETRY,
5788 CLUTTER_PARAM_READWRITE);
5791 * ClutterActor:name:
5793 * The name of the actor
5797 obj_props[PROP_NAME] =
5798 g_param_spec_string ("name",
5800 P_("Name of the actor"),
5802 CLUTTER_PARAM_READWRITE);
5805 * ClutterActor:scale-x:
5807 * The horizontal scale of the actor.
5809 * The #ClutterActor:scale-x property is animatable.
5813 obj_props[PROP_SCALE_X] =
5814 g_param_spec_double ("scale-x",
5816 P_("Scale factor on the X axis"),
5820 G_PARAM_STATIC_STRINGS |
5821 CLUTTER_PARAM_ANIMATABLE);
5824 * ClutterActor:scale-y:
5826 * The vertical scale of the actor.
5828 * The #ClutterActor:scale-y property is animatable.
5832 obj_props[PROP_SCALE_Y] =
5833 g_param_spec_double ("scale-y",
5835 P_("Scale factor on the Y axis"),
5839 G_PARAM_STATIC_STRINGS |
5840 CLUTTER_PARAM_ANIMATABLE);
5843 * ClutterActor:scale-center-x:
5845 * The horizontal center point for scaling
5849 obj_props[PROP_SCALE_CENTER_X] =
5850 g_param_spec_float ("scale-center-x",
5851 P_("Scale Center X"),
5852 P_("Horizontal scale center"),
5853 -G_MAXFLOAT, G_MAXFLOAT,
5855 CLUTTER_PARAM_READWRITE);
5858 * ClutterActor:scale-center-y:
5860 * The vertical center point for scaling
5864 obj_props[PROP_SCALE_CENTER_Y] =
5865 g_param_spec_float ("scale-center-y",
5866 P_("Scale Center Y"),
5867 P_("Vertical scale center"),
5868 -G_MAXFLOAT, G_MAXFLOAT,
5870 CLUTTER_PARAM_READWRITE);
5873 * ClutterActor:scale-gravity:
5875 * The center point for scaling expressed as a #ClutterGravity
5879 obj_props[PROP_SCALE_GRAVITY] =
5880 g_param_spec_enum ("scale-gravity",
5881 P_("Scale Gravity"),
5882 P_("The center of scaling"),
5883 CLUTTER_TYPE_GRAVITY,
5884 CLUTTER_GRAVITY_NONE,
5885 CLUTTER_PARAM_READWRITE);
5888 * ClutterActor:rotation-angle-x:
5890 * The rotation angle on the X axis.
5892 * The #ClutterActor:rotation-angle-x property is animatable.
5896 obj_props[PROP_ROTATION_ANGLE_X] =
5897 g_param_spec_double ("rotation-angle-x",
5898 P_("Rotation Angle X"),
5899 P_("The rotation angle on the X axis"),
5900 -G_MAXDOUBLE, G_MAXDOUBLE,
5903 G_PARAM_STATIC_STRINGS |
5904 CLUTTER_PARAM_ANIMATABLE);
5907 * ClutterActor:rotation-angle-y:
5909 * The rotation angle on the Y axis
5911 * The #ClutterActor:rotation-angle-y property is animatable.
5915 obj_props[PROP_ROTATION_ANGLE_Y] =
5916 g_param_spec_double ("rotation-angle-y",
5917 P_("Rotation Angle Y"),
5918 P_("The rotation angle on the Y axis"),
5919 -G_MAXDOUBLE, G_MAXDOUBLE,
5922 G_PARAM_STATIC_STRINGS |
5923 CLUTTER_PARAM_ANIMATABLE);
5926 * ClutterActor:rotation-angle-z:
5928 * The rotation angle on the Z axis
5930 * The #ClutterActor:rotation-angle-z property is animatable.
5934 obj_props[PROP_ROTATION_ANGLE_Z] =
5935 g_param_spec_double ("rotation-angle-z",
5936 P_("Rotation Angle Z"),
5937 P_("The rotation angle on the Z axis"),
5938 -G_MAXDOUBLE, G_MAXDOUBLE,
5941 G_PARAM_STATIC_STRINGS |
5942 CLUTTER_PARAM_ANIMATABLE);
5945 * ClutterActor:rotation-center-x:
5947 * The rotation center on the X axis.
5951 obj_props[PROP_ROTATION_CENTER_X] =
5952 g_param_spec_boxed ("rotation-center-x",
5953 P_("Rotation Center X"),
5954 P_("The rotation center on the X axis"),
5955 CLUTTER_TYPE_VERTEX,
5956 CLUTTER_PARAM_READWRITE);
5959 * ClutterActor:rotation-center-y:
5961 * The rotation center on the Y axis.
5965 obj_props[PROP_ROTATION_CENTER_Y] =
5966 g_param_spec_boxed ("rotation-center-y",
5967 P_("Rotation Center Y"),
5968 P_("The rotation center on the Y axis"),
5969 CLUTTER_TYPE_VERTEX,
5970 CLUTTER_PARAM_READWRITE);
5973 * ClutterActor:rotation-center-z:
5975 * The rotation center on the Z axis.
5979 obj_props[PROP_ROTATION_CENTER_Z] =
5980 g_param_spec_boxed ("rotation-center-z",
5981 P_("Rotation Center Z"),
5982 P_("The rotation center on the Z axis"),
5983 CLUTTER_TYPE_VERTEX,
5984 CLUTTER_PARAM_READWRITE);
5987 * ClutterActor:rotation-center-z-gravity:
5989 * The rotation center on the Z axis expressed as a #ClutterGravity.
5993 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5994 g_param_spec_enum ("rotation-center-z-gravity",
5995 P_("Rotation Center Z Gravity"),
5996 P_("Center point for rotation around the Z axis"),
5997 CLUTTER_TYPE_GRAVITY,
5998 CLUTTER_GRAVITY_NONE,
5999 CLUTTER_PARAM_READWRITE);
6002 * ClutterActor:anchor-x:
6004 * The X coordinate of an actor's anchor point, relative to
6005 * the actor coordinate space, in pixels
6009 obj_props[PROP_ANCHOR_X] =
6010 g_param_spec_float ("anchor-x",
6012 P_("X coordinate of the anchor point"),
6013 -G_MAXFLOAT, G_MAXFLOAT,
6015 CLUTTER_PARAM_READWRITE);
6018 * ClutterActor:anchor-y:
6020 * The Y coordinate of an actor's anchor point, relative to
6021 * the actor coordinate space, in pixels
6025 obj_props[PROP_ANCHOR_Y] =
6026 g_param_spec_float ("anchor-y",
6028 P_("Y coordinate of the anchor point"),
6029 -G_MAXFLOAT, G_MAXFLOAT,
6031 CLUTTER_PARAM_READWRITE);
6034 * ClutterActor:anchor-gravity:
6036 * The anchor point expressed as a #ClutterGravity
6040 obj_props[PROP_ANCHOR_GRAVITY] =
6041 g_param_spec_enum ("anchor-gravity",
6042 P_("Anchor Gravity"),
6043 P_("The anchor point as a ClutterGravity"),
6044 CLUTTER_TYPE_GRAVITY,
6045 CLUTTER_GRAVITY_NONE,
6046 CLUTTER_PARAM_READWRITE);
6049 * ClutterActor:show-on-set-parent:
6051 * If %TRUE, the actor is automatically shown when parented.
6053 * Calling clutter_actor_hide() on an actor which has not been
6054 * parented will set this property to %FALSE as a side effect.
6058 obj_props[PROP_SHOW_ON_SET_PARENT] =
6059 g_param_spec_boolean ("show-on-set-parent",
6060 P_("Show on set parent"),
6061 P_("Whether the actor is shown when parented"),
6063 CLUTTER_PARAM_READWRITE);
6066 * ClutterActor:clip-to-allocation:
6068 * Whether the clip region should track the allocated area
6071 * This property is ignored if a clip area has been explicitly
6072 * set using clutter_actor_set_clip().
6076 obj_props[PROP_CLIP_TO_ALLOCATION] =
6077 g_param_spec_boolean ("clip-to-allocation",
6078 P_("Clip to Allocation"),
6079 P_("Sets the clip region to track the actor's allocation"),
6081 CLUTTER_PARAM_READWRITE);
6084 * ClutterActor:text-direction:
6086 * The direction of the text inside a #ClutterActor.
6090 obj_props[PROP_TEXT_DIRECTION] =
6091 g_param_spec_enum ("text-direction",
6092 P_("Text Direction"),
6093 P_("Direction of the text"),
6094 CLUTTER_TYPE_TEXT_DIRECTION,
6095 CLUTTER_TEXT_DIRECTION_LTR,
6096 CLUTTER_PARAM_READWRITE);
6099 * ClutterActor:has-pointer:
6101 * Whether the actor contains the pointer of a #ClutterInputDevice
6106 obj_props[PROP_HAS_POINTER] =
6107 g_param_spec_boolean ("has-pointer",
6109 P_("Whether the actor contains the pointer of an input device"),
6111 CLUTTER_PARAM_READABLE);
6114 * ClutterActor:actions:
6116 * Adds a #ClutterAction to the actor
6120 obj_props[PROP_ACTIONS] =
6121 g_param_spec_object ("actions",
6123 P_("Adds an action to the actor"),
6124 CLUTTER_TYPE_ACTION,
6125 CLUTTER_PARAM_WRITABLE);
6128 * ClutterActor:constraints:
6130 * Adds a #ClutterConstraint to the actor
6134 obj_props[PROP_CONSTRAINTS] =
6135 g_param_spec_object ("constraints",
6137 P_("Adds a constraint to the actor"),
6138 CLUTTER_TYPE_CONSTRAINT,
6139 CLUTTER_PARAM_WRITABLE);
6142 * ClutterActor:effect:
6144 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6148 obj_props[PROP_EFFECT] =
6149 g_param_spec_object ("effect",
6151 P_("Add an effect to be applied on the actor"),
6152 CLUTTER_TYPE_EFFECT,
6153 CLUTTER_PARAM_WRITABLE);
6156 * ClutterActor:layout-manager:
6158 * A delegate object for controlling the layout of the children of
6163 obj_props[PROP_LAYOUT_MANAGER] =
6164 g_param_spec_object ("layout-manager",
6165 P_("Layout Manager"),
6166 P_("The object controlling the layout of an actor's children"),
6167 CLUTTER_TYPE_LAYOUT_MANAGER,
6168 CLUTTER_PARAM_READWRITE);
6172 * ClutterActor:x-align:
6174 * The alignment of an actor on the X axis, if the actor has been given
6175 * extra space for its allocation.
6179 obj_props[PROP_X_ALIGN] =
6180 g_param_spec_enum ("x-align",
6182 P_("The alignment of the actor on the X axis within its allocation"),
6183 CLUTTER_TYPE_ACTOR_ALIGN,
6184 CLUTTER_ACTOR_ALIGN_FILL,
6185 CLUTTER_PARAM_READWRITE);
6188 * ClutterActor:y-align:
6190 * The alignment of an actor on the Y axis, if the actor has been given
6191 * extra space for its allocation.
6195 obj_props[PROP_Y_ALIGN] =
6196 g_param_spec_enum ("y-align",
6198 P_("The alignment of the actor on the Y axis within its allocation"),
6199 CLUTTER_TYPE_ACTOR_ALIGN,
6200 CLUTTER_ACTOR_ALIGN_FILL,
6201 CLUTTER_PARAM_READWRITE);
6204 * ClutterActor:margin-top:
6206 * The margin (in pixels) from the top of the actor.
6208 * This property adds a margin to the actor's preferred size; the margin
6209 * will be automatically taken into account when allocating the actor.
6213 obj_props[PROP_MARGIN_TOP] =
6214 g_param_spec_float ("margin-top",
6216 P_("Extra space at the top"),
6219 CLUTTER_PARAM_READWRITE);
6222 * ClutterActor:margin-bottom:
6224 * The margin (in pixels) from the bottom of the actor.
6226 * This property adds a margin to the actor's preferred size; the margin
6227 * will be automatically taken into account when allocating the actor.
6231 obj_props[PROP_MARGIN_BOTTOM] =
6232 g_param_spec_float ("margin-bottom",
6233 P_("Margin Bottom"),
6234 P_("Extra space at the bottom"),
6237 CLUTTER_PARAM_READWRITE);
6240 * ClutterActor:margin-left:
6242 * The margin (in pixels) from the left of the actor.
6244 * This property adds a margin to the actor's preferred size; the margin
6245 * will be automatically taken into account when allocating the actor.
6249 obj_props[PROP_MARGIN_LEFT] =
6250 g_param_spec_float ("margin-left",
6252 P_("Extra space at the left"),
6255 CLUTTER_PARAM_READWRITE);
6258 * ClutterActor:margin-right:
6260 * The margin (in pixels) from the right of the actor.
6262 * This property adds a margin to the actor's preferred size; the margin
6263 * will be automatically taken into account when allocating the actor.
6267 obj_props[PROP_MARGIN_RIGHT] =
6268 g_param_spec_float ("margin-right",
6270 P_("Extra space at the right"),
6273 CLUTTER_PARAM_READWRITE);
6276 * ClutterActor:background-color-set:
6278 * Whether the #ClutterActor:background-color property has been set.
6282 obj_props[PROP_BACKGROUND_COLOR_SET] =
6283 g_param_spec_boolean ("background-color-set",
6284 P_("Background Color Set"),
6285 P_("Whether the background color is set"),
6287 CLUTTER_PARAM_READABLE);
6290 * ClutterActor:background-color:
6292 * Paints a solid fill of the actor's allocation using the specified
6295 * The #ClutterActor:background-color property is animatable.
6299 obj_props[PROP_BACKGROUND_COLOR] =
6300 clutter_param_spec_color ("background-color",
6301 P_("Background color"),
6302 P_("The actor's background color"),
6303 CLUTTER_COLOR_Transparent,
6305 G_PARAM_STATIC_STRINGS |
6306 CLUTTER_PARAM_ANIMATABLE);
6309 * ClutterActor:first-child:
6311 * The actor's first child.
6315 obj_props[PROP_FIRST_CHILD] =
6316 g_param_spec_object ("first-child",
6318 P_("The actor's first child"),
6320 CLUTTER_PARAM_READABLE);
6323 * ClutterActor:last-child:
6325 * The actor's last child.
6329 obj_props[PROP_LAST_CHILD] =
6330 g_param_spec_object ("last-child",
6332 P_("The actor's last child"),
6334 CLUTTER_PARAM_READABLE);
6337 * ClutterActor:content:
6339 * The #ClutterContent implementation that controls the content
6344 obj_props[PROP_CONTENT] =
6345 g_param_spec_object ("content",
6347 P_("Delegate object for painting the actor's content"),
6348 CLUTTER_TYPE_CONTENT,
6349 CLUTTER_PARAM_READWRITE);
6352 * ClutterActor:content-gravity:
6354 * The alignment that should be honoured by the #ClutterContent
6355 * set with the #ClutterActor:content property.
6357 * Changing the value of this property will change the bounding box of
6358 * the content; you can use the #ClutterActor:content-box property to
6359 * get the position and size of the content within the actor's
6362 * This property is meaningful only for #ClutterContent implementations
6363 * that have a preferred size, and if the preferred size is smaller than
6364 * the actor's allocation.
6368 obj_props[PROP_CONTENT_GRAVITY] =
6369 g_param_spec_enum ("content-gravity",
6370 P_("Content Gravity"),
6371 P_("Alignment of the actor's content"),
6372 CLUTTER_TYPE_CONTENT_GRAVITY,
6373 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6374 CLUTTER_PARAM_READWRITE);
6377 * ClutterActor:content-box:
6379 * The bounding box for the #ClutterContent used by the actor.
6381 * The value of this property is controlled by the #ClutterActor:allocation
6382 * and #ClutterActor:content-gravity properties of #ClutterActor.
6384 * The bounding box for the content is guaranteed to never exceed the
6385 * allocation's of the actor.
6389 obj_props[PROP_CONTENT_BOX] =
6390 g_param_spec_boxed ("content-box",
6392 P_("The bounding box of the actor's content"),
6393 CLUTTER_TYPE_ACTOR_BOX,
6394 CLUTTER_PARAM_READABLE);
6396 obj_props[PROP_MINIFICATION_FILTER] =
6397 g_param_spec_enum ("minification-filter",
6398 P_("Minification Filter"),
6399 P_("The filter used when reducing the size of the content"),
6400 CLUTTER_TYPE_SCALING_FILTER,
6401 CLUTTER_SCALING_FILTER_LINEAR,
6402 CLUTTER_PARAM_READWRITE);
6404 obj_props[PROP_MAGNIFICATION_FILTER] =
6405 g_param_spec_enum ("magnification-filter",
6406 P_("Magnification Filter"),
6407 P_("The filter used when increasing the size of the content"),
6408 CLUTTER_TYPE_SCALING_FILTER,
6409 CLUTTER_SCALING_FILTER_LINEAR,
6410 CLUTTER_PARAM_READWRITE);
6412 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6415 * ClutterActor::destroy:
6416 * @actor: the #ClutterActor which emitted the signal
6418 * The ::destroy signal notifies that all references held on the
6419 * actor which emitted it should be released.
6421 * The ::destroy signal should be used by all holders of a reference
6424 * This signal might result in the finalization of the #ClutterActor
6425 * if all references are released.
6427 * Composite actors and actors implementing the #ClutterContainer
6428 * interface should override the default implementation of the
6429 * class handler of this signal and call clutter_actor_destroy() on
6430 * their children. When overriding the default class handler, it is
6431 * required to chain up to the parent's implementation.
6435 actor_signals[DESTROY] =
6436 g_signal_new (I_("destroy"),
6437 G_TYPE_FROM_CLASS (object_class),
6438 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6439 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6441 _clutter_marshal_VOID__VOID,
6444 * ClutterActor::show:
6445 * @actor: the object which received the signal
6447 * The ::show signal is emitted when an actor is visible and
6448 * rendered on the stage.
6452 actor_signals[SHOW] =
6453 g_signal_new (I_("show"),
6454 G_TYPE_FROM_CLASS (object_class),
6456 G_STRUCT_OFFSET (ClutterActorClass, show),
6458 _clutter_marshal_VOID__VOID,
6461 * ClutterActor::hide:
6462 * @actor: the object which received the signal
6464 * The ::hide signal is emitted when an actor is no longer rendered
6469 actor_signals[HIDE] =
6470 g_signal_new (I_("hide"),
6471 G_TYPE_FROM_CLASS (object_class),
6473 G_STRUCT_OFFSET (ClutterActorClass, hide),
6475 _clutter_marshal_VOID__VOID,
6478 * ClutterActor::parent-set:
6479 * @actor: the object which received the signal
6480 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6482 * This signal is emitted when the parent of the actor changes.
6486 actor_signals[PARENT_SET] =
6487 g_signal_new (I_("parent-set"),
6488 G_TYPE_FROM_CLASS (object_class),
6490 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6492 _clutter_marshal_VOID__OBJECT,
6494 CLUTTER_TYPE_ACTOR);
6497 * ClutterActor::queue-redraw:
6498 * @actor: the actor we're bubbling the redraw request through
6499 * @origin: the actor which initiated the redraw request
6501 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6502 * is called on @origin.
6504 * The default implementation for #ClutterActor chains up to the
6505 * parent actor and queues a redraw on the parent, thus "bubbling"
6506 * the redraw queue up through the actor graph. The default
6507 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6508 * in a main loop idle handler.
6510 * Note that the @origin actor may be the stage, or a container; it
6511 * does not have to be a leaf node in the actor graph.
6513 * Toolkits embedding a #ClutterStage which require a redraw and
6514 * relayout cycle can stop the emission of this signal using the
6515 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6520 * on_redraw_complete (gpointer data)
6522 * ClutterStage *stage = data;
6524 * /* execute the Clutter drawing pipeline */
6525 * clutter_stage_ensure_redraw (stage);
6529 * on_stage_queue_redraw (ClutterStage *stage)
6531 * /* this prevents the default handler to run */
6532 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6534 * /* queue a redraw with the host toolkit and call
6535 * * a function when the redraw has been completed
6537 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6541 * <note><para>This signal is emitted before the Clutter paint
6542 * pipeline is executed. If you want to know when the pipeline has
6543 * been completed you should connect to the ::paint signal on the
6544 * Stage with g_signal_connect_after().</para></note>
6548 actor_signals[QUEUE_REDRAW] =
6549 g_signal_new (I_("queue-redraw"),
6550 G_TYPE_FROM_CLASS (object_class),
6553 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6555 _clutter_marshal_VOID__OBJECT,
6557 CLUTTER_TYPE_ACTOR);
6560 * ClutterActor::queue-relayout
6561 * @actor: the actor being queued for relayout
6563 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6564 * is called on an actor.
6566 * The default implementation for #ClutterActor chains up to the
6567 * parent actor and queues a relayout on the parent, thus "bubbling"
6568 * the relayout queue up through the actor graph.
6570 * The main purpose of this signal is to allow relayout to be propagated
6571 * properly in the procense of #ClutterClone actors. Applications will
6572 * not normally need to connect to this signal.
6576 actor_signals[QUEUE_RELAYOUT] =
6577 g_signal_new (I_("queue-relayout"),
6578 G_TYPE_FROM_CLASS (object_class),
6581 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6583 _clutter_marshal_VOID__VOID,
6587 * ClutterActor::event:
6588 * @actor: the actor which received the event
6589 * @event: a #ClutterEvent
6591 * The ::event signal is emitted each time an event is received
6592 * by the @actor. This signal will be emitted on every actor,
6593 * following the hierarchy chain, until it reaches the top-level
6594 * container (the #ClutterStage).
6596 * Return value: %TRUE if the event has been handled by the actor,
6597 * or %FALSE to continue the emission.
6601 actor_signals[EVENT] =
6602 g_signal_new (I_("event"),
6603 G_TYPE_FROM_CLASS (object_class),
6605 G_STRUCT_OFFSET (ClutterActorClass, event),
6606 _clutter_boolean_handled_accumulator, NULL,
6607 _clutter_marshal_BOOLEAN__BOXED,
6609 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6611 * ClutterActor::button-press-event:
6612 * @actor: the actor which received the event
6613 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6615 * The ::button-press-event signal is emitted each time a mouse button
6616 * is pressed on @actor.
6618 * Return value: %TRUE if the event has been handled by the actor,
6619 * or %FALSE to continue the emission.
6623 actor_signals[BUTTON_PRESS_EVENT] =
6624 g_signal_new (I_("button-press-event"),
6625 G_TYPE_FROM_CLASS (object_class),
6627 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6628 _clutter_boolean_handled_accumulator, NULL,
6629 _clutter_marshal_BOOLEAN__BOXED,
6631 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6633 * ClutterActor::button-release-event:
6634 * @actor: the actor which received the event
6635 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6637 * The ::button-release-event signal is emitted each time a mouse button
6638 * is released on @actor.
6640 * Return value: %TRUE if the event has been handled by the actor,
6641 * or %FALSE to continue the emission.
6645 actor_signals[BUTTON_RELEASE_EVENT] =
6646 g_signal_new (I_("button-release-event"),
6647 G_TYPE_FROM_CLASS (object_class),
6649 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6650 _clutter_boolean_handled_accumulator, NULL,
6651 _clutter_marshal_BOOLEAN__BOXED,
6653 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6655 * ClutterActor::scroll-event:
6656 * @actor: the actor which received the event
6657 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6659 * The ::scroll-event signal is emitted each time the mouse is
6660 * scrolled on @actor
6662 * Return value: %TRUE if the event has been handled by the actor,
6663 * or %FALSE to continue the emission.
6667 actor_signals[SCROLL_EVENT] =
6668 g_signal_new (I_("scroll-event"),
6669 G_TYPE_FROM_CLASS (object_class),
6671 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6672 _clutter_boolean_handled_accumulator, NULL,
6673 _clutter_marshal_BOOLEAN__BOXED,
6675 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6677 * ClutterActor::key-press-event:
6678 * @actor: the actor which received the event
6679 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6681 * The ::key-press-event signal is emitted each time a keyboard button
6682 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6684 * Return value: %TRUE if the event has been handled by the actor,
6685 * or %FALSE to continue the emission.
6689 actor_signals[KEY_PRESS_EVENT] =
6690 g_signal_new (I_("key-press-event"),
6691 G_TYPE_FROM_CLASS (object_class),
6693 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6694 _clutter_boolean_handled_accumulator, NULL,
6695 _clutter_marshal_BOOLEAN__BOXED,
6697 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6699 * ClutterActor::key-release-event:
6700 * @actor: the actor which received the event
6701 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6703 * The ::key-release-event signal is emitted each time a keyboard button
6704 * is released while @actor has key focus (see
6705 * clutter_stage_set_key_focus()).
6707 * Return value: %TRUE if the event has been handled by the actor,
6708 * or %FALSE to continue the emission.
6712 actor_signals[KEY_RELEASE_EVENT] =
6713 g_signal_new (I_("key-release-event"),
6714 G_TYPE_FROM_CLASS (object_class),
6716 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6717 _clutter_boolean_handled_accumulator, NULL,
6718 _clutter_marshal_BOOLEAN__BOXED,
6720 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6722 * ClutterActor::motion-event:
6723 * @actor: the actor which received the event
6724 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6726 * The ::motion-event signal is emitted each time the mouse pointer is
6727 * moved over @actor.
6729 * Return value: %TRUE if the event has been handled by the actor,
6730 * or %FALSE to continue the emission.
6734 actor_signals[MOTION_EVENT] =
6735 g_signal_new (I_("motion-event"),
6736 G_TYPE_FROM_CLASS (object_class),
6738 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6739 _clutter_boolean_handled_accumulator, NULL,
6740 _clutter_marshal_BOOLEAN__BOXED,
6742 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6745 * ClutterActor::key-focus-in:
6746 * @actor: the actor which now has key focus
6748 * The ::key-focus-in signal is emitted when @actor receives key focus.
6752 actor_signals[KEY_FOCUS_IN] =
6753 g_signal_new (I_("key-focus-in"),
6754 G_TYPE_FROM_CLASS (object_class),
6756 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6758 _clutter_marshal_VOID__VOID,
6762 * ClutterActor::key-focus-out:
6763 * @actor: the actor which now has key focus
6765 * The ::key-focus-out signal is emitted when @actor loses key focus.
6769 actor_signals[KEY_FOCUS_OUT] =
6770 g_signal_new (I_("key-focus-out"),
6771 G_TYPE_FROM_CLASS (object_class),
6773 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6775 _clutter_marshal_VOID__VOID,
6779 * ClutterActor::enter-event:
6780 * @actor: the actor which the pointer has entered.
6781 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6783 * The ::enter-event signal is emitted when the pointer enters the @actor
6785 * Return value: %TRUE if the event has been handled by the actor,
6786 * or %FALSE to continue the emission.
6790 actor_signals[ENTER_EVENT] =
6791 g_signal_new (I_("enter-event"),
6792 G_TYPE_FROM_CLASS (object_class),
6794 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6795 _clutter_boolean_handled_accumulator, NULL,
6796 _clutter_marshal_BOOLEAN__BOXED,
6798 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6801 * ClutterActor::leave-event:
6802 * @actor: the actor which the pointer has left
6803 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6805 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6807 * Return value: %TRUE if the event has been handled by the actor,
6808 * or %FALSE to continue the emission.
6812 actor_signals[LEAVE_EVENT] =
6813 g_signal_new (I_("leave-event"),
6814 G_TYPE_FROM_CLASS (object_class),
6816 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6817 _clutter_boolean_handled_accumulator, NULL,
6818 _clutter_marshal_BOOLEAN__BOXED,
6820 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6823 * ClutterActor::captured-event:
6824 * @actor: the actor which received the signal
6825 * @event: a #ClutterEvent
6827 * The ::captured-event signal is emitted when an event is captured
6828 * by Clutter. This signal will be emitted starting from the top-level
6829 * container (the #ClutterStage) to the actor which received the event
6830 * going down the hierarchy. This signal can be used to intercept every
6831 * event before the specialized events (like
6832 * ClutterActor::button-press-event or ::key-released-event) are
6835 * Return value: %TRUE if the event has been handled by the actor,
6836 * or %FALSE to continue the emission.
6840 actor_signals[CAPTURED_EVENT] =
6841 g_signal_new (I_("captured-event"),
6842 G_TYPE_FROM_CLASS (object_class),
6844 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6845 _clutter_boolean_handled_accumulator, NULL,
6846 _clutter_marshal_BOOLEAN__BOXED,
6848 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6851 * ClutterActor::paint:
6852 * @actor: the #ClutterActor that received the signal
6854 * The ::paint signal is emitted each time an actor is being painted.
6856 * Subclasses of #ClutterActor should override the class signal handler
6857 * and paint themselves in that function.
6859 * It is possible to connect a handler to the ::paint signal in order
6860 * to set up some custom aspect of a paint.
6864 actor_signals[PAINT] =
6865 g_signal_new (I_("paint"),
6866 G_TYPE_FROM_CLASS (object_class),
6869 G_STRUCT_OFFSET (ClutterActorClass, paint),
6871 _clutter_marshal_VOID__VOID,
6874 * ClutterActor::realize:
6875 * @actor: the #ClutterActor that received the signal
6877 * The ::realize signal is emitted each time an actor is being
6882 actor_signals[REALIZE] =
6883 g_signal_new (I_("realize"),
6884 G_TYPE_FROM_CLASS (object_class),
6886 G_STRUCT_OFFSET (ClutterActorClass, realize),
6888 _clutter_marshal_VOID__VOID,
6891 * ClutterActor::unrealize:
6892 * @actor: the #ClutterActor that received the signal
6894 * The ::unrealize signal is emitted each time an actor is being
6899 actor_signals[UNREALIZE] =
6900 g_signal_new (I_("unrealize"),
6901 G_TYPE_FROM_CLASS (object_class),
6903 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6905 _clutter_marshal_VOID__VOID,
6909 * ClutterActor::pick:
6910 * @actor: the #ClutterActor that received the signal
6911 * @color: the #ClutterColor to be used when picking
6913 * The ::pick signal is emitted each time an actor is being painted
6914 * in "pick mode". The pick mode is used to identify the actor during
6915 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6916 * The actor should paint its shape using the passed @pick_color.
6918 * Subclasses of #ClutterActor should override the class signal handler
6919 * and paint themselves in that function.
6921 * It is possible to connect a handler to the ::pick signal in order
6922 * to set up some custom aspect of a paint in pick mode.
6926 actor_signals[PICK] =
6927 g_signal_new (I_("pick"),
6928 G_TYPE_FROM_CLASS (object_class),
6930 G_STRUCT_OFFSET (ClutterActorClass, pick),
6932 _clutter_marshal_VOID__BOXED,
6934 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6937 * ClutterActor::allocation-changed:
6938 * @actor: the #ClutterActor that emitted the signal
6939 * @box: a #ClutterActorBox with the new allocation
6940 * @flags: #ClutterAllocationFlags for the allocation
6942 * The ::allocation-changed signal is emitted when the
6943 * #ClutterActor:allocation property changes. Usually, application
6944 * code should just use the notifications for the :allocation property
6945 * but if you want to track the allocation flags as well, for instance
6946 * to know whether the absolute origin of @actor changed, then you might
6947 * want use this signal instead.
6951 actor_signals[ALLOCATION_CHANGED] =
6952 g_signal_new (I_("allocation-changed"),
6953 G_TYPE_FROM_CLASS (object_class),
6957 _clutter_marshal_VOID__BOXED_FLAGS,
6959 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6960 CLUTTER_TYPE_ALLOCATION_FLAGS);
6964 clutter_actor_init (ClutterActor *self)
6966 ClutterActorPrivate *priv;
6968 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6970 priv->id = _clutter_context_acquire_id (self);
6973 priv->opacity = 0xff;
6974 priv->show_on_set_parent = TRUE;
6976 priv->needs_width_request = TRUE;
6977 priv->needs_height_request = TRUE;
6978 priv->needs_allocation = TRUE;
6980 priv->cached_width_age = 1;
6981 priv->cached_height_age = 1;
6983 priv->opacity_override = -1;
6984 priv->enable_model_view_transform = TRUE;
6986 /* Initialize an empty paint volume to start with */
6987 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6988 priv->last_paint_volume_valid = TRUE;
6990 priv->transform_valid = FALSE;
6992 /* the default is to stretch the content, to match the
6993 * current behaviour of basically all actors. also, it's
6994 * the easiest thing to compute.
6996 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6997 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
6998 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7002 * clutter_actor_new:
7004 * Creates a new #ClutterActor.
7006 * A newly created actor has a floating reference, which will be sunk
7007 * when it is added to another actor.
7009 * Return value: (transfer full): the newly created #ClutterActor
7014 clutter_actor_new (void)
7016 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7020 * clutter_actor_destroy:
7021 * @self: a #ClutterActor
7023 * Destroys an actor. When an actor is destroyed, it will break any
7024 * references it holds to other objects. If the actor is inside a
7025 * container, the actor will be removed.
7027 * When you destroy a container, its children will be destroyed as well.
7029 * Note: you cannot destroy the #ClutterStage returned by
7030 * clutter_stage_get_default().
7033 clutter_actor_destroy (ClutterActor *self)
7035 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7037 g_object_ref (self);
7039 /* avoid recursion while destroying */
7040 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7042 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7044 g_object_run_dispose (G_OBJECT (self));
7046 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7049 g_object_unref (self);
7053 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7054 ClutterPaintVolume *clip)
7056 ClutterActorPrivate *priv = self->priv;
7057 ClutterPaintVolume *pv;
7060 /* Remove queue entry early in the process, otherwise a new
7061 queue_redraw() during signal handling could put back this
7062 object in the stage redraw list (but the entry is freed as
7063 soon as we return from this function, causing a segfault
7066 priv->queue_redraw_entry = NULL;
7068 /* If we've been explicitly passed a clip volume then there's
7069 * nothing more to calculate, but otherwise the only thing we know
7070 * is that the change is constrained to the given actor.
7072 * The idea is that if we know the paint volume for where the actor
7073 * was last drawn (in eye coordinates) and we also have the paint
7074 * volume for where it will be drawn next (in actor coordinates)
7075 * then if we queue a redraw for both these volumes that will cover
7076 * everything that needs to be redrawn to clear the old view and
7077 * show the latest view of the actor.
7079 * Don't clip this redraw if we don't know what position we had for
7080 * the previous redraw since we don't know where to set the clip so
7081 * it will clear the actor as it is currently.
7085 _clutter_actor_set_queue_redraw_clip (self, clip);
7088 else if (G_LIKELY (priv->last_paint_volume_valid))
7090 pv = _clutter_actor_get_paint_volume_mutable (self);
7093 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7095 /* make sure we redraw the actors old position... */
7096 _clutter_actor_set_queue_redraw_clip (stage,
7097 &priv->last_paint_volume);
7098 _clutter_actor_signal_queue_redraw (stage, stage);
7099 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7101 /* XXX: Ideally the redraw signal would take a clip volume
7102 * argument, but that would be an ABI break. Until we can
7103 * break the ABI we pass the argument out-of-band
7106 /* setup the clip for the actors new position... */
7107 _clutter_actor_set_queue_redraw_clip (self, pv);
7116 _clutter_actor_signal_queue_redraw (self, self);
7118 /* Just in case anyone is manually firing redraw signals without
7119 * using the public queue_redraw() API we are careful to ensure that
7120 * our out-of-band clip member is cleared before returning...
7122 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7124 if (G_LIKELY (clipped))
7125 _clutter_actor_set_queue_redraw_clip (self, NULL);
7129 _clutter_actor_get_allocation_clip (ClutterActor *self,
7130 ClutterActorBox *clip)
7132 ClutterActorBox allocation;
7134 /* XXX: we don't care if we get an out of date allocation here
7135 * because clutter_actor_queue_redraw_with_clip knows to ignore
7136 * the clip if the actor's allocation is invalid.
7138 * This is noted because clutter_actor_get_allocation_box does some
7139 * unnecessary work to support buggy code with a comment suggesting
7140 * that it could be changed later which would be good for this use
7143 clutter_actor_get_allocation_box (self, &allocation);
7145 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7146 * actor's own coordinate space but the allocation is in parent
7150 clip->x2 = allocation.x2 - allocation.x1;
7151 clip->y2 = allocation.y2 - allocation.y1;
7155 _clutter_actor_queue_redraw_full (ClutterActor *self,
7156 ClutterRedrawFlags flags,
7157 ClutterPaintVolume *volume,
7158 ClutterEffect *effect)
7160 ClutterActorPrivate *priv = self->priv;
7161 ClutterPaintVolume allocation_pv;
7162 ClutterPaintVolume *pv;
7163 gboolean should_free_pv;
7164 ClutterActor *stage;
7166 /* Here's an outline of the actor queue redraw mechanism:
7168 * The process starts in one of the following two functions which
7169 * are wrappers for this function:
7170 * clutter_actor_queue_redraw
7171 * _clutter_actor_queue_redraw_with_clip
7173 * additionally, an effect can queue a redraw by wrapping this
7174 * function in clutter_effect_queue_rerun
7176 * This functions queues an entry in a list associated with the
7177 * stage which is a list of actors that queued a redraw while
7178 * updating the timelines, performing layouting and processing other
7179 * mainloop sources before the next paint starts.
7181 * We aim to minimize the processing done at this point because
7182 * there is a good chance other events will happen while updating
7183 * the scenegraph that would invalidate any expensive work we might
7184 * otherwise try to do here. For example we don't try and resolve
7185 * the screen space bounding box of an actor at this stage so as to
7186 * minimize how much of the screen redraw because it's possible
7187 * something else will happen which will force a full redraw anyway.
7189 * When all updates are complete and we come to paint the stage then
7190 * we iterate this list and actually emit the "queue-redraw" signals
7191 * for each of the listed actors which will bubble up to the stage
7192 * for each actor and at that point we will transform the actors
7193 * paint volume into screen coordinates to determine the clip region
7194 * for what needs to be redrawn in the next paint.
7196 * Besides minimizing redundant work another reason for this
7197 * deferred design is that it's more likely we will be able to
7198 * determine the paint volume of an actor once we've finished
7199 * updating the scenegraph because its allocation should be up to
7200 * date. NB: If we can't determine an actors paint volume then we
7201 * can't automatically queue a clipped redraw which can make a big
7202 * difference to performance.
7204 * So the control flow goes like this:
7205 * One of clutter_actor_queue_redraw,
7206 * _clutter_actor_queue_redraw_with_clip
7207 * or clutter_effect_queue_rerun
7209 * then control moves to:
7210 * _clutter_stage_queue_actor_redraw
7212 * later during _clutter_stage_do_update, once relayouting is done
7213 * and the scenegraph has been updated we will call:
7214 * _clutter_stage_finish_queue_redraws
7216 * _clutter_stage_finish_queue_redraws will call
7217 * _clutter_actor_finish_queue_redraw for each listed actor.
7218 * Note: actors *are* allowed to queue further redraws during this
7219 * process (considering clone actors or texture_new_from_actor which
7220 * respond to their source queueing a redraw by queuing a redraw
7221 * themselves). We repeat the process until the list is empty.
7223 * This will result in the "queue-redraw" signal being fired for
7224 * each actor which will pass control to the default signal handler:
7225 * clutter_actor_real_queue_redraw
7227 * This will bubble up to the stages handler:
7228 * clutter_stage_real_queue_redraw
7230 * clutter_stage_real_queue_redraw will transform the actors paint
7231 * volume into screen space and add it as a clip region for the next
7235 /* ignore queueing a redraw for actors being destroyed */
7236 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7239 stage = _clutter_actor_get_stage_internal (self);
7241 /* Ignore queueing a redraw for actors not descended from a stage */
7245 /* ignore queueing a redraw on stages that are being destroyed */
7246 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7249 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7251 ClutterActorBox allocation_clip;
7252 ClutterVertex origin;
7254 /* If the actor doesn't have a valid allocation then we will
7255 * queue a full stage redraw. */
7256 if (priv->needs_allocation)
7258 /* NB: NULL denotes an undefined clip which will result in a
7260 _clutter_actor_set_queue_redraw_clip (self, NULL);
7261 _clutter_actor_signal_queue_redraw (self, self);
7265 _clutter_paint_volume_init_static (&allocation_pv, self);
7266 pv = &allocation_pv;
7268 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7270 origin.x = allocation_clip.x1;
7271 origin.y = allocation_clip.y1;
7273 clutter_paint_volume_set_origin (pv, &origin);
7274 clutter_paint_volume_set_width (pv,
7275 allocation_clip.x2 - allocation_clip.x1);
7276 clutter_paint_volume_set_height (pv,
7277 allocation_clip.y2 -
7278 allocation_clip.y1);
7279 should_free_pv = TRUE;
7284 should_free_pv = FALSE;
7287 self->priv->queue_redraw_entry =
7288 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7289 priv->queue_redraw_entry,
7294 clutter_paint_volume_free (pv);
7296 /* If this is the first redraw queued then we can directly use the
7298 if (!priv->is_dirty)
7299 priv->effect_to_redraw = effect;
7300 /* Otherwise we need to merge it with the existing effect parameter */
7301 else if (effect != NULL)
7303 /* If there's already an effect then we need to use whichever is
7304 later in the chain of actors. Otherwise a full redraw has
7305 already been queued on the actor so we need to ignore the
7307 if (priv->effect_to_redraw != NULL)
7309 if (priv->effects == NULL)
7310 g_warning ("Redraw queued with an effect that is "
7311 "not applied to the actor");
7316 for (l = _clutter_meta_group_peek_metas (priv->effects);
7320 if (l->data == priv->effect_to_redraw ||
7322 priv->effect_to_redraw = l->data;
7329 /* If no effect is specified then we need to redraw the whole
7331 priv->effect_to_redraw = NULL;
7334 priv->is_dirty = TRUE;
7338 * clutter_actor_queue_redraw:
7339 * @self: A #ClutterActor
7341 * Queues up a redraw of an actor and any children. The redraw occurs
7342 * once the main loop becomes idle (after the current batch of events
7343 * has been processed, roughly).
7345 * Applications rarely need to call this, as redraws are handled
7346 * automatically by modification functions.
7348 * This function will not do anything if @self is not visible, or
7349 * if the actor is inside an invisible part of the scenegraph.
7351 * Also be aware that painting is a NOP for actors with an opacity of
7354 * When you are implementing a custom actor you must queue a redraw
7355 * whenever some private state changes that will affect painting or
7356 * picking of your actor.
7359 clutter_actor_queue_redraw (ClutterActor *self)
7361 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7363 _clutter_actor_queue_redraw_full (self,
7365 NULL, /* clip volume */
7370 * _clutter_actor_queue_redraw_with_clip:
7371 * @self: A #ClutterActor
7372 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7373 * this queue redraw.
7374 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7375 * redrawn or %NULL if you are just using a @flag to state your
7378 * Queues up a clipped redraw of an actor and any children. The redraw
7379 * occurs once the main loop becomes idle (after the current batch of
7380 * events has been processed, roughly).
7382 * If no flags are given the clip volume is defined by @volume
7383 * specified in actor coordinates and tells Clutter that only content
7384 * within this volume has been changed so Clutter can optionally
7385 * optimize the redraw.
7387 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7388 * should be %NULL and this tells Clutter to use the actor's current
7389 * allocation as a clip box. This flag can only be used for 2D actors,
7390 * because any actor with depth may be projected outside its
7393 * Applications rarely need to call this, as redraws are handled
7394 * automatically by modification functions.
7396 * This function will not do anything if @self is not visible, or if
7397 * the actor is inside an invisible part of the scenegraph.
7399 * Also be aware that painting is a NOP for actors with an opacity of
7402 * When you are implementing a custom actor you must queue a redraw
7403 * whenever some private state changes that will affect painting or
7404 * picking of your actor.
7407 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7408 ClutterRedrawFlags flags,
7409 ClutterPaintVolume *volume)
7411 _clutter_actor_queue_redraw_full (self,
7413 volume, /* clip volume */
7418 _clutter_actor_queue_only_relayout (ClutterActor *self)
7420 ClutterActorPrivate *priv = self->priv;
7422 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7425 if (priv->needs_width_request &&
7426 priv->needs_height_request &&
7427 priv->needs_allocation)
7428 return; /* save some cpu cycles */
7430 #if CLUTTER_ENABLE_DEBUG
7431 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7433 g_warning ("The actor '%s' is currently inside an allocation "
7434 "cycle; calling clutter_actor_queue_relayout() is "
7436 _clutter_actor_get_debug_name (self));
7438 #endif /* CLUTTER_ENABLE_DEBUG */
7440 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7444 * clutter_actor_queue_redraw_with_clip:
7445 * @self: a #ClutterActor
7446 * @clip: (allow-none): a rectangular clip region, or %NULL
7448 * Queues a redraw on @self limited to a specific, actor-relative
7451 * If @clip is %NULL this function is equivalent to
7452 * clutter_actor_queue_redraw().
7457 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7458 const cairo_rectangle_int_t *clip)
7460 ClutterPaintVolume volume;
7461 ClutterVertex origin;
7463 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7467 clutter_actor_queue_redraw (self);
7471 _clutter_paint_volume_init_static (&volume, self);
7477 clutter_paint_volume_set_origin (&volume, &origin);
7478 clutter_paint_volume_set_width (&volume, clip->width);
7479 clutter_paint_volume_set_height (&volume, clip->height);
7481 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7483 clutter_paint_volume_free (&volume);
7487 * clutter_actor_queue_relayout:
7488 * @self: A #ClutterActor
7490 * Indicates that the actor's size request or other layout-affecting
7491 * properties may have changed. This function is used inside #ClutterActor
7492 * subclass implementations, not by applications directly.
7494 * Queueing a new layout automatically queues a redraw as well.
7499 clutter_actor_queue_relayout (ClutterActor *self)
7501 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7503 _clutter_actor_queue_only_relayout (self);
7504 clutter_actor_queue_redraw (self);
7508 * clutter_actor_get_preferred_size:
7509 * @self: a #ClutterActor
7510 * @min_width_p: (out) (allow-none): return location for the minimum
7512 * @min_height_p: (out) (allow-none): return location for the minimum
7514 * @natural_width_p: (out) (allow-none): return location for the natural
7516 * @natural_height_p: (out) (allow-none): return location for the natural
7519 * Computes the preferred minimum and natural size of an actor, taking into
7520 * account the actor's geometry management (either height-for-width
7521 * or width-for-height).
7523 * The width and height used to compute the preferred height and preferred
7524 * width are the actor's natural ones.
7526 * If you need to control the height for the preferred width, or the width for
7527 * the preferred height, you should use clutter_actor_get_preferred_width()
7528 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7529 * geometry management using the #ClutterActor:request-mode property.
7534 clutter_actor_get_preferred_size (ClutterActor *self,
7535 gfloat *min_width_p,
7536 gfloat *min_height_p,
7537 gfloat *natural_width_p,
7538 gfloat *natural_height_p)
7540 ClutterActorPrivate *priv;
7541 gfloat min_width, min_height;
7542 gfloat natural_width, natural_height;
7544 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7548 min_width = min_height = 0;
7549 natural_width = natural_height = 0;
7551 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7553 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7554 clutter_actor_get_preferred_width (self, -1,
7557 clutter_actor_get_preferred_height (self, natural_width,
7563 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7564 clutter_actor_get_preferred_height (self, -1,
7567 clutter_actor_get_preferred_width (self, natural_height,
7573 *min_width_p = min_width;
7576 *min_height_p = min_height;
7578 if (natural_width_p)
7579 *natural_width_p = natural_width;
7581 if (natural_height_p)
7582 *natural_height_p = natural_height;
7587 * @align: a #ClutterActorAlign
7588 * @direction: a #ClutterTextDirection
7590 * Retrieves the correct alignment depending on the text direction
7592 * Return value: the effective alignment
7594 static ClutterActorAlign
7595 effective_align (ClutterActorAlign align,
7596 ClutterTextDirection direction)
7598 ClutterActorAlign res;
7602 case CLUTTER_ACTOR_ALIGN_START:
7603 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7604 ? CLUTTER_ACTOR_ALIGN_END
7605 : CLUTTER_ACTOR_ALIGN_START;
7608 case CLUTTER_ACTOR_ALIGN_END:
7609 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7610 ? CLUTTER_ACTOR_ALIGN_START
7611 : CLUTTER_ACTOR_ALIGN_END;
7623 adjust_for_margin (float margin_start,
7625 float *minimum_size,
7626 float *natural_size,
7627 float *allocated_start,
7628 float *allocated_end)
7630 *minimum_size -= (margin_start + margin_end);
7631 *natural_size -= (margin_start + margin_end);
7632 *allocated_start += margin_start;
7633 *allocated_end -= margin_end;
7637 adjust_for_alignment (ClutterActorAlign alignment,
7639 float *allocated_start,
7640 float *allocated_end)
7642 float allocated_size = *allocated_end - *allocated_start;
7646 case CLUTTER_ACTOR_ALIGN_FILL:
7650 case CLUTTER_ACTOR_ALIGN_START:
7652 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7655 case CLUTTER_ACTOR_ALIGN_END:
7656 if (allocated_size > natural_size)
7658 *allocated_start += (allocated_size - natural_size);
7659 *allocated_end = *allocated_start + natural_size;
7663 case CLUTTER_ACTOR_ALIGN_CENTER:
7664 if (allocated_size > natural_size)
7666 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7667 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7674 * clutter_actor_adjust_width:
7675 * @self: a #ClutterActor
7676 * @minimum_width: (inout): the actor's preferred minimum width, which
7677 * will be adjusted depending on the margin
7678 * @natural_width: (inout): the actor's preferred natural width, which
7679 * will be adjusted depending on the margin
7680 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7681 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7683 * Adjusts the preferred and allocated position and size of an actor,
7684 * depending on the margin and alignment properties.
7687 clutter_actor_adjust_width (ClutterActor *self,
7688 gfloat *minimum_width,
7689 gfloat *natural_width,
7690 gfloat *adjusted_x1,
7691 gfloat *adjusted_x2)
7693 ClutterTextDirection text_dir;
7694 const ClutterLayoutInfo *info;
7696 info = _clutter_actor_get_layout_info_or_defaults (self);
7697 text_dir = clutter_actor_get_text_direction (self);
7699 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7701 /* this will tweak natural_width to remove the margin, so that
7702 * adjust_for_alignment() will use the correct size
7704 adjust_for_margin (info->margin.left, info->margin.right,
7705 minimum_width, natural_width,
7706 adjusted_x1, adjusted_x2);
7708 adjust_for_alignment (effective_align (info->x_align, text_dir),
7710 adjusted_x1, adjusted_x2);
7714 * clutter_actor_adjust_height:
7715 * @self: a #ClutterActor
7716 * @minimum_height: (inout): the actor's preferred minimum height, which
7717 * will be adjusted depending on the margin
7718 * @natural_height: (inout): the actor's preferred natural height, which
7719 * will be adjusted depending on the margin
7720 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7721 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7723 * Adjusts the preferred and allocated position and size of an actor,
7724 * depending on the margin and alignment properties.
7727 clutter_actor_adjust_height (ClutterActor *self,
7728 gfloat *minimum_height,
7729 gfloat *natural_height,
7730 gfloat *adjusted_y1,
7731 gfloat *adjusted_y2)
7733 const ClutterLayoutInfo *info;
7735 info = _clutter_actor_get_layout_info_or_defaults (self);
7737 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7739 /* this will tweak natural_height to remove the margin, so that
7740 * adjust_for_alignment() will use the correct size
7742 adjust_for_margin (info->margin.top, info->margin.bottom,
7743 minimum_height, natural_height,
7747 /* we don't use effective_align() here, because text direction
7748 * only affects the horizontal axis
7750 adjust_for_alignment (info->y_align,
7757 /* looks for a cached size request for this for_size. If not
7758 * found, returns the oldest entry so it can be overwritten */
7760 _clutter_actor_get_cached_size_request (gfloat for_size,
7761 SizeRequest *cached_size_requests,
7762 SizeRequest **result)
7766 *result = &cached_size_requests[0];
7768 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7772 sr = &cached_size_requests[i];
7775 sr->for_size == for_size)
7777 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7781 else if (sr->age < (*result)->age)
7787 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7793 * clutter_actor_get_preferred_width:
7794 * @self: A #ClutterActor
7795 * @for_height: available height when computing the preferred width,
7796 * or a negative value to indicate that no height is defined
7797 * @min_width_p: (out) (allow-none): return location for minimum width,
7799 * @natural_width_p: (out) (allow-none): return location for the natural
7802 * Computes the requested minimum and natural widths for an actor,
7803 * optionally depending on the specified height, or if they are
7804 * already computed, returns the cached values.
7806 * An actor may not get its request - depending on the layout
7807 * manager that's in effect.
7809 * A request should not incorporate the actor's scale or anchor point;
7810 * those transformations do not affect layout, only rendering.
7815 clutter_actor_get_preferred_width (ClutterActor *self,
7817 gfloat *min_width_p,
7818 gfloat *natural_width_p)
7820 float request_min_width, request_natural_width;
7821 SizeRequest *cached_size_request;
7822 const ClutterLayoutInfo *info;
7823 ClutterActorPrivate *priv;
7824 gboolean found_in_cache;
7826 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7830 info = _clutter_actor_get_layout_info_or_defaults (self);
7832 /* we shortcircuit the case of a fixed size set using set_width() */
7833 if (priv->min_width_set && priv->natural_width_set)
7835 if (min_width_p != NULL)
7836 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7838 if (natural_width_p != NULL)
7839 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7844 /* the remaining cases are:
7846 * - either min_width or natural_width have been set
7847 * - neither min_width or natural_width have been set
7849 * in both cases, we go through the cache (and through the actor in case
7850 * of cache misses) and determine the authoritative value depending on
7854 if (!priv->needs_width_request)
7857 _clutter_actor_get_cached_size_request (for_height,
7858 priv->width_requests,
7859 &cached_size_request);
7863 /* if the actor needs a width request we use the first slot */
7864 found_in_cache = FALSE;
7865 cached_size_request = &priv->width_requests[0];
7868 if (!found_in_cache)
7870 gfloat minimum_width, natural_width;
7871 ClutterActorClass *klass;
7873 minimum_width = natural_width = 0;
7875 /* adjust for the margin */
7876 if (for_height >= 0)
7878 for_height -= (info->margin.top + info->margin.bottom);
7883 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7885 klass = CLUTTER_ACTOR_GET_CLASS (self);
7886 klass->get_preferred_width (self, for_height,
7890 /* adjust for the margin */
7891 minimum_width += (info->margin.left + info->margin.right);
7892 natural_width += (info->margin.left + info->margin.right);
7894 /* Due to accumulated float errors, it's better not to warn
7895 * on this, but just fix it.
7897 if (natural_width < minimum_width)
7898 natural_width = minimum_width;
7900 cached_size_request->min_size = minimum_width;
7901 cached_size_request->natural_size = natural_width;
7902 cached_size_request->for_size = for_height;
7903 cached_size_request->age = priv->cached_width_age;
7905 priv->cached_width_age += 1;
7906 priv->needs_width_request = FALSE;
7909 if (!priv->min_width_set)
7910 request_min_width = cached_size_request->min_size;
7912 request_min_width = info->min_width;
7914 if (!priv->natural_width_set)
7915 request_natural_width = cached_size_request->natural_size;
7917 request_natural_width = info->natural_width;
7920 *min_width_p = request_min_width;
7922 if (natural_width_p)
7923 *natural_width_p = request_natural_width;
7927 * clutter_actor_get_preferred_height:
7928 * @self: A #ClutterActor
7929 * @for_width: available width to assume in computing desired height,
7930 * or a negative value to indicate that no width is defined
7931 * @min_height_p: (out) (allow-none): return location for minimum height,
7933 * @natural_height_p: (out) (allow-none): return location for natural
7936 * Computes the requested minimum and natural heights for an actor,
7937 * or if they are already computed, returns the cached values.
7939 * An actor may not get its request - depending on the layout
7940 * manager that's in effect.
7942 * A request should not incorporate the actor's scale or anchor point;
7943 * those transformations do not affect layout, only rendering.
7948 clutter_actor_get_preferred_height (ClutterActor *self,
7950 gfloat *min_height_p,
7951 gfloat *natural_height_p)
7953 float request_min_height, request_natural_height;
7954 SizeRequest *cached_size_request;
7955 const ClutterLayoutInfo *info;
7956 ClutterActorPrivate *priv;
7957 gboolean found_in_cache;
7959 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7963 info = _clutter_actor_get_layout_info_or_defaults (self);
7965 /* we shortcircuit the case of a fixed size set using set_height() */
7966 if (priv->min_height_set && priv->natural_height_set)
7968 if (min_height_p != NULL)
7969 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7971 if (natural_height_p != NULL)
7972 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7977 /* the remaining cases are:
7979 * - either min_height or natural_height have been set
7980 * - neither min_height or natural_height have been set
7982 * in both cases, we go through the cache (and through the actor in case
7983 * of cache misses) and determine the authoritative value depending on
7987 if (!priv->needs_height_request)
7990 _clutter_actor_get_cached_size_request (for_width,
7991 priv->height_requests,
7992 &cached_size_request);
7996 found_in_cache = FALSE;
7997 cached_size_request = &priv->height_requests[0];
8000 if (!found_in_cache)
8002 gfloat minimum_height, natural_height;
8003 ClutterActorClass *klass;
8005 minimum_height = natural_height = 0;
8007 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8009 /* adjust for margin */
8012 for_width -= (info->margin.left + info->margin.right);
8017 klass = CLUTTER_ACTOR_GET_CLASS (self);
8018 klass->get_preferred_height (self, for_width,
8022 /* adjust for margin */
8023 minimum_height += (info->margin.top + info->margin.bottom);
8024 natural_height += (info->margin.top + info->margin.bottom);
8026 /* Due to accumulated float errors, it's better not to warn
8027 * on this, but just fix it.
8029 if (natural_height < minimum_height)
8030 natural_height = minimum_height;
8032 cached_size_request->min_size = minimum_height;
8033 cached_size_request->natural_size = natural_height;
8034 cached_size_request->for_size = for_width;
8035 cached_size_request->age = priv->cached_height_age;
8037 priv->cached_height_age += 1;
8038 priv->needs_height_request = FALSE;
8041 if (!priv->min_height_set)
8042 request_min_height = cached_size_request->min_size;
8044 request_min_height = info->min_height;
8046 if (!priv->natural_height_set)
8047 request_natural_height = cached_size_request->natural_size;
8049 request_natural_height = info->natural_height;
8052 *min_height_p = request_min_height;
8054 if (natural_height_p)
8055 *natural_height_p = request_natural_height;
8059 * clutter_actor_get_allocation_box:
8060 * @self: A #ClutterActor
8061 * @box: (out): the function fills this in with the actor's allocation
8063 * Gets the layout box an actor has been assigned. The allocation can
8064 * only be assumed valid inside a paint() method; anywhere else, it
8065 * may be out-of-date.
8067 * An allocation does not incorporate the actor's scale or anchor point;
8068 * those transformations do not affect layout, only rendering.
8070 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8071 * of functions inside the implementation of the get_preferred_width()
8072 * or get_preferred_height() virtual functions.</note>
8077 clutter_actor_get_allocation_box (ClutterActor *self,
8078 ClutterActorBox *box)
8080 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8082 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8083 * which limits calling get_allocation to inside paint() basically; or
8084 * we can 2) force a layout, which could be expensive if someone calls
8085 * get_allocation somewhere silly; or we can 3) just return the latest
8086 * value, allowing it to be out-of-date, and assume people know what
8089 * The least-surprises approach that keeps existing code working is
8090 * likely to be 2). People can end up doing some inefficient things,
8091 * though, and in general code that requires 2) is probably broken.
8094 /* this implements 2) */
8095 if (G_UNLIKELY (self->priv->needs_allocation))
8097 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8099 /* do not queue a relayout on an unparented actor */
8101 _clutter_stage_maybe_relayout (stage);
8104 /* commenting out the code above and just keeping this assigment
8107 *box = self->priv->allocation;
8111 * clutter_actor_get_allocation_geometry:
8112 * @self: A #ClutterActor
8113 * @geom: (out): allocation geometry in pixels
8115 * Gets the layout box an actor has been assigned. The allocation can
8116 * only be assumed valid inside a paint() method; anywhere else, it
8117 * may be out-of-date.
8119 * An allocation does not incorporate the actor's scale or anchor point;
8120 * those transformations do not affect layout, only rendering.
8122 * The returned rectangle is in pixels.
8127 clutter_actor_get_allocation_geometry (ClutterActor *self,
8128 ClutterGeometry *geom)
8130 ClutterActorBox box;
8132 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8133 g_return_if_fail (geom != NULL);
8135 clutter_actor_get_allocation_box (self, &box);
8137 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8138 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8139 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8140 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8144 clutter_actor_update_constraints (ClutterActor *self,
8145 ClutterActorBox *allocation)
8147 ClutterActorPrivate *priv = self->priv;
8148 const GList *constraints, *l;
8150 if (priv->constraints == NULL)
8153 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8154 for (l = constraints; l != NULL; l = l->next)
8156 ClutterConstraint *constraint = l->data;
8157 ClutterActorMeta *meta = l->data;
8159 if (clutter_actor_meta_get_enabled (meta))
8161 _clutter_constraint_update_allocation (constraint,
8165 CLUTTER_NOTE (LAYOUT,
8166 "Allocation of '%s' after constraint '%s': "
8167 "{ %.2f, %.2f, %.2f, %.2f }",
8168 _clutter_actor_get_debug_name (self),
8169 _clutter_actor_meta_get_debug_name (meta),
8179 * clutter_actor_adjust_allocation:
8180 * @self: a #ClutterActor
8181 * @allocation: (inout): the allocation to adjust
8183 * Adjusts the passed allocation box taking into account the actor's
8184 * layout information, like alignment, expansion, and margin.
8187 clutter_actor_adjust_allocation (ClutterActor *self,
8188 ClutterActorBox *allocation)
8190 ClutterActorBox adj_allocation;
8191 float alloc_width, alloc_height;
8192 float min_width, min_height;
8193 float nat_width, nat_height;
8194 ClutterRequestMode req_mode;
8196 adj_allocation = *allocation;
8198 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8200 /* we want to hit the cache, so we use the public API */
8201 req_mode = clutter_actor_get_request_mode (self);
8203 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8205 clutter_actor_get_preferred_width (self, -1,
8208 clutter_actor_get_preferred_height (self, alloc_width,
8212 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8214 clutter_actor_get_preferred_height (self, -1,
8217 clutter_actor_get_preferred_height (self, alloc_height,
8222 #ifdef CLUTTER_ENABLE_DEBUG
8223 /* warn about underallocations */
8224 if (_clutter_diagnostic_enabled () &&
8225 (floorf (min_width - alloc_width) > 0 ||
8226 floorf (min_height - alloc_height) > 0))
8228 ClutterActor *parent = clutter_actor_get_parent (self);
8230 /* the only actors that are allowed to be underallocated are the Stage,
8231 * as it doesn't have an implicit size, and Actors that specifically
8232 * told us that they want to opt-out from layout control mechanisms
8233 * through the NO_LAYOUT escape hatch.
8235 if (parent != NULL &&
8236 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8238 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8239 "of %.2f x %.2f from its parent actor '%s', but its "
8240 "requested minimum size is of %.2f x %.2f",
8241 _clutter_actor_get_debug_name (self),
8242 alloc_width, alloc_height,
8243 _clutter_actor_get_debug_name (parent),
8244 min_width, min_height);
8249 clutter_actor_adjust_width (self,
8253 &adj_allocation.x2);
8255 clutter_actor_adjust_height (self,
8259 &adj_allocation.y2);
8261 /* we maintain the invariant that an allocation cannot be adjusted
8262 * to be outside the parent-given box
8264 if (adj_allocation.x1 < allocation->x1 ||
8265 adj_allocation.y1 < allocation->y1 ||
8266 adj_allocation.x2 > allocation->x2 ||
8267 adj_allocation.y2 > allocation->y2)
8269 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8270 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8271 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8272 _clutter_actor_get_debug_name (self),
8273 adj_allocation.x1, adj_allocation.y1,
8274 adj_allocation.x2 - adj_allocation.x1,
8275 adj_allocation.y2 - adj_allocation.y1,
8276 allocation->x1, allocation->y1,
8277 allocation->x2 - allocation->x1,
8278 allocation->y2 - allocation->y1);
8282 *allocation = adj_allocation;
8286 * clutter_actor_allocate:
8287 * @self: A #ClutterActor
8288 * @box: new allocation of the actor, in parent-relative coordinates
8289 * @flags: flags that control the allocation
8291 * Called by the parent of an actor to assign the actor its size.
8292 * Should never be called by applications (except when implementing
8293 * a container or layout manager).
8295 * Actors can know from their allocation box whether they have moved
8296 * with respect to their parent actor. The @flags parameter describes
8297 * additional information about the allocation, for instance whether
8298 * the parent has moved with respect to the stage, for example because
8299 * a grandparent's origin has moved.
8304 clutter_actor_allocate (ClutterActor *self,
8305 const ClutterActorBox *box,
8306 ClutterAllocationFlags flags)
8308 ClutterActorPrivate *priv;
8309 ClutterActorClass *klass;
8310 ClutterActorBox old_allocation, real_allocation;
8311 gboolean origin_changed, child_moved, size_changed;
8312 gboolean stage_allocation_changed;
8314 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8315 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8317 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8318 "which isn't a descendent of the stage!\n",
8319 self, _clutter_actor_get_debug_name (self));
8325 old_allocation = priv->allocation;
8326 real_allocation = *box;
8328 /* constraints are allowed to modify the allocation only here; we do
8329 * this prior to all the other checks so that we can bail out if the
8330 * allocation did not change
8332 clutter_actor_update_constraints (self, &real_allocation);
8334 /* adjust the allocation depending on the align/margin properties */
8335 clutter_actor_adjust_allocation (self, &real_allocation);
8337 if (real_allocation.x2 < real_allocation.x1 ||
8338 real_allocation.y2 < real_allocation.y1)
8340 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8341 _clutter_actor_get_debug_name (self),
8342 real_allocation.x2 - real_allocation.x1,
8343 real_allocation.y2 - real_allocation.y1);
8346 /* we allow 0-sized actors, but not negative-sized ones */
8347 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8348 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8350 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8352 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8353 real_allocation.y1 != old_allocation.y1);
8355 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8356 real_allocation.y2 != old_allocation.y2);
8358 if (origin_changed || child_moved || size_changed)
8359 stage_allocation_changed = TRUE;
8361 stage_allocation_changed = FALSE;
8363 /* If we get an allocation "out of the blue"
8364 * (we did not queue relayout), then we want to
8365 * ignore it. But if we have needs_allocation set,
8366 * we want to guarantee that allocate() virtual
8367 * method is always called, i.e. that queue_relayout()
8368 * always results in an allocate() invocation on
8371 * The optimization here is to avoid re-allocating
8372 * actors that did not queue relayout and were
8375 if (!priv->needs_allocation && !stage_allocation_changed)
8377 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8381 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8382 * clutter_actor_allocate(), it indicates whether the parent has its
8383 * absolute origin moved; when passed in to ClutterActor::allocate()
8384 * virtual method though, it indicates whether the child has its
8385 * absolute origin moved. So we set it when child_moved is TRUE
8388 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8390 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8392 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8393 _clutter_actor_get_debug_name (self));
8395 klass = CLUTTER_ACTOR_GET_CLASS (self);
8396 klass->allocate (self, &real_allocation, flags);
8398 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8400 if (stage_allocation_changed)
8401 clutter_actor_queue_redraw (self);
8405 * clutter_actor_set_allocation:
8406 * @self: a #ClutterActor
8407 * @box: a #ClutterActorBox
8408 * @flags: allocation flags
8410 * Stores the allocation of @self as defined by @box.
8412 * This function can only be called from within the implementation of
8413 * the #ClutterActorClass.allocate() virtual function.
8415 * The allocation should have been adjusted to take into account constraints,
8416 * alignment, and margin properties. If you are implementing a #ClutterActor
8417 * subclass that provides its own layout management policy for its children
8418 * instead of using a #ClutterLayoutManager delegate, you should not call
8419 * this function on the children of @self; instead, you should call
8420 * clutter_actor_allocate(), which will adjust the allocation box for
8423 * This function should only be used by subclasses of #ClutterActor
8424 * that wish to store their allocation but cannot chain up to the
8425 * parent's implementation; the default implementation of the
8426 * #ClutterActorClass.allocate() virtual function will call this
8429 * It is important to note that, while chaining up was the recommended
8430 * behaviour for #ClutterActor subclasses prior to the introduction of
8431 * this function, it is recommended to call clutter_actor_set_allocation()
8434 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8435 * to handle the allocation of its children, this function will call
8436 * the clutter_layout_manager_allocate() function only if the
8437 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8438 * expected that the subclass will call clutter_layout_manager_allocate()
8439 * by itself. For instance, the following code:
8443 * my_actor_allocate (ClutterActor *actor,
8444 * const ClutterActorBox *allocation,
8445 * ClutterAllocationFlags flags)
8447 * ClutterActorBox new_alloc;
8448 * ClutterAllocationFlags new_flags;
8450 * adjust_allocation (allocation, &new_alloc);
8452 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8454 * /* this will use the layout manager set on the actor */
8455 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8459 * is equivalent to this:
8463 * my_actor_allocate (ClutterActor *actor,
8464 * const ClutterActorBox *allocation,
8465 * ClutterAllocationFlags flags)
8467 * ClutterLayoutManager *layout;
8468 * ClutterActorBox new_alloc;
8470 * adjust_allocation (allocation, &new_alloc);
8472 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8474 * layout = clutter_actor_get_layout_manager (actor);
8475 * clutter_layout_manager_allocate (layout,
8476 * CLUTTER_CONTAINER (actor),
8485 clutter_actor_set_allocation (ClutterActor *self,
8486 const ClutterActorBox *box,
8487 ClutterAllocationFlags flags)
8489 ClutterActorPrivate *priv;
8492 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8493 g_return_if_fail (box != NULL);
8495 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8497 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8498 "can only be called from within the implementation of "
8499 "the ClutterActor::allocate() virtual function.");
8505 g_object_freeze_notify (G_OBJECT (self));
8507 changed = clutter_actor_set_allocation_internal (self, box, flags);
8509 /* we allocate our children before we notify changes in our geometry,
8510 * so that people connecting to properties will be able to get valid
8511 * data out of the sub-tree of the scene graph that has this actor at
8514 clutter_actor_maybe_layout_children (self, box, flags);
8518 ClutterActorBox signal_box = priv->allocation;
8519 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8521 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8526 g_object_thaw_notify (G_OBJECT (self));
8530 * clutter_actor_set_geometry:
8531 * @self: A #ClutterActor
8532 * @geometry: A #ClutterGeometry
8534 * Sets the actor's fixed position and forces its minimum and natural
8535 * size, in pixels. This means the untransformed actor will have the
8536 * given geometry. This is the same as calling clutter_actor_set_position()
8537 * and clutter_actor_set_size().
8539 * Deprecated: 1.10: Use clutter_actor_set_position() and
8540 * clutter_actor_set_size() instead.
8543 clutter_actor_set_geometry (ClutterActor *self,
8544 const ClutterGeometry *geometry)
8546 g_object_freeze_notify (G_OBJECT (self));
8548 clutter_actor_set_position (self, geometry->x, geometry->y);
8549 clutter_actor_set_size (self, geometry->width, geometry->height);
8551 g_object_thaw_notify (G_OBJECT (self));
8555 * clutter_actor_get_geometry:
8556 * @self: A #ClutterActor
8557 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8559 * Gets the size and position of an actor relative to its parent
8560 * actor. This is the same as calling clutter_actor_get_position() and
8561 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8562 * requested size and position if the actor's allocation is invalid.
8564 * Deprecated: 1.10: Use clutter_actor_get_position() and
8565 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8569 clutter_actor_get_geometry (ClutterActor *self,
8570 ClutterGeometry *geometry)
8572 gfloat x, y, width, height;
8574 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8575 g_return_if_fail (geometry != NULL);
8577 clutter_actor_get_position (self, &x, &y);
8578 clutter_actor_get_size (self, &width, &height);
8580 geometry->x = (int) x;
8581 geometry->y = (int) y;
8582 geometry->width = (int) width;
8583 geometry->height = (int) height;
8587 * clutter_actor_set_position:
8588 * @self: A #ClutterActor
8589 * @x: New left position of actor in pixels.
8590 * @y: New top position of actor in pixels.
8592 * Sets the actor's fixed position in pixels relative to any parent
8595 * If a layout manager is in use, this position will override the
8596 * layout manager and force a fixed position.
8599 clutter_actor_set_position (ClutterActor *self,
8603 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8605 g_object_freeze_notify (G_OBJECT (self));
8607 clutter_actor_set_x (self, x);
8608 clutter_actor_set_y (self, y);
8610 g_object_thaw_notify (G_OBJECT (self));
8614 * clutter_actor_get_fixed_position_set:
8615 * @self: A #ClutterActor
8617 * Checks whether an actor has a fixed position set (and will thus be
8618 * unaffected by any layout manager).
8620 * Return value: %TRUE if the fixed position is set on the actor
8625 clutter_actor_get_fixed_position_set (ClutterActor *self)
8627 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8629 return self->priv->position_set;
8633 * clutter_actor_set_fixed_position_set:
8634 * @self: A #ClutterActor
8635 * @is_set: whether to use fixed position
8637 * Sets whether an actor has a fixed position set (and will thus be
8638 * unaffected by any layout manager).
8643 clutter_actor_set_fixed_position_set (ClutterActor *self,
8646 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8648 if (self->priv->position_set == (is_set != FALSE))
8651 self->priv->position_set = is_set != FALSE;
8652 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8654 clutter_actor_queue_relayout (self);
8658 * clutter_actor_move_by:
8659 * @self: A #ClutterActor
8660 * @dx: Distance to move Actor on X axis.
8661 * @dy: Distance to move Actor on Y axis.
8663 * Moves an actor by the specified distance relative to its current
8664 * position in pixels.
8666 * This function modifies the fixed position of an actor and thus removes
8667 * it from any layout management. Another way to move an actor is with an
8668 * anchor point, see clutter_actor_set_anchor_point().
8673 clutter_actor_move_by (ClutterActor *self,
8677 const ClutterLayoutInfo *info;
8680 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8682 info = _clutter_actor_get_layout_info_or_defaults (self);
8686 clutter_actor_set_position (self, x + dx, y + dy);
8690 clutter_actor_set_min_width (ClutterActor *self,
8693 ClutterActorPrivate *priv = self->priv;
8694 ClutterActorBox old = { 0, };
8695 ClutterLayoutInfo *info;
8697 /* if we are setting the size on a top-level actor and the
8698 * backend only supports static top-levels (e.g. framebuffers)
8699 * then we ignore the passed value and we override it with
8700 * the stage implementation's preferred size.
8702 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8703 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8706 info = _clutter_actor_get_layout_info (self);
8708 if (priv->min_width_set && min_width == info->min_width)
8711 g_object_freeze_notify (G_OBJECT (self));
8713 clutter_actor_store_old_geometry (self, &old);
8715 info->min_width = min_width;
8716 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8717 clutter_actor_set_min_width_set (self, TRUE);
8719 clutter_actor_notify_if_geometry_changed (self, &old);
8721 g_object_thaw_notify (G_OBJECT (self));
8723 clutter_actor_queue_relayout (self);
8727 clutter_actor_set_min_height (ClutterActor *self,
8731 ClutterActorPrivate *priv = self->priv;
8732 ClutterActorBox old = { 0, };
8733 ClutterLayoutInfo *info;
8735 /* if we are setting the size on a top-level actor and the
8736 * backend only supports static top-levels (e.g. framebuffers)
8737 * then we ignore the passed value and we override it with
8738 * the stage implementation's preferred size.
8740 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8741 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8744 info = _clutter_actor_get_layout_info (self);
8746 if (priv->min_height_set && min_height == info->min_height)
8749 g_object_freeze_notify (G_OBJECT (self));
8751 clutter_actor_store_old_geometry (self, &old);
8753 info->min_height = min_height;
8754 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8755 clutter_actor_set_min_height_set (self, TRUE);
8757 clutter_actor_notify_if_geometry_changed (self, &old);
8759 g_object_thaw_notify (G_OBJECT (self));
8761 clutter_actor_queue_relayout (self);
8765 clutter_actor_set_natural_width (ClutterActor *self,
8766 gfloat natural_width)
8768 ClutterActorPrivate *priv = self->priv;
8769 ClutterActorBox old = { 0, };
8770 ClutterLayoutInfo *info;
8772 /* if we are setting the size on a top-level actor and the
8773 * backend only supports static top-levels (e.g. framebuffers)
8774 * then we ignore the passed value and we override it with
8775 * the stage implementation's preferred size.
8777 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8778 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8781 info = _clutter_actor_get_layout_info (self);
8783 if (priv->natural_width_set && natural_width == info->natural_width)
8786 g_object_freeze_notify (G_OBJECT (self));
8788 clutter_actor_store_old_geometry (self, &old);
8790 info->natural_width = natural_width;
8791 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8792 clutter_actor_set_natural_width_set (self, TRUE);
8794 clutter_actor_notify_if_geometry_changed (self, &old);
8796 g_object_thaw_notify (G_OBJECT (self));
8798 clutter_actor_queue_relayout (self);
8802 clutter_actor_set_natural_height (ClutterActor *self,
8803 gfloat natural_height)
8805 ClutterActorPrivate *priv = self->priv;
8806 ClutterActorBox old = { 0, };
8807 ClutterLayoutInfo *info;
8809 /* if we are setting the size on a top-level actor and the
8810 * backend only supports static top-levels (e.g. framebuffers)
8811 * then we ignore the passed value and we override it with
8812 * the stage implementation's preferred size.
8814 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8815 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8818 info = _clutter_actor_get_layout_info (self);
8820 if (priv->natural_height_set && natural_height == info->natural_height)
8823 g_object_freeze_notify (G_OBJECT (self));
8825 clutter_actor_store_old_geometry (self, &old);
8827 info->natural_height = natural_height;
8828 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8829 clutter_actor_set_natural_height_set (self, TRUE);
8831 clutter_actor_notify_if_geometry_changed (self, &old);
8833 g_object_thaw_notify (G_OBJECT (self));
8835 clutter_actor_queue_relayout (self);
8839 clutter_actor_set_min_width_set (ClutterActor *self,
8840 gboolean use_min_width)
8842 ClutterActorPrivate *priv = self->priv;
8843 ClutterActorBox old = { 0, };
8845 if (priv->min_width_set == (use_min_width != FALSE))
8848 clutter_actor_store_old_geometry (self, &old);
8850 priv->min_width_set = use_min_width != FALSE;
8851 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8853 clutter_actor_notify_if_geometry_changed (self, &old);
8855 clutter_actor_queue_relayout (self);
8859 clutter_actor_set_min_height_set (ClutterActor *self,
8860 gboolean use_min_height)
8862 ClutterActorPrivate *priv = self->priv;
8863 ClutterActorBox old = { 0, };
8865 if (priv->min_height_set == (use_min_height != FALSE))
8868 clutter_actor_store_old_geometry (self, &old);
8870 priv->min_height_set = use_min_height != FALSE;
8871 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8873 clutter_actor_notify_if_geometry_changed (self, &old);
8875 clutter_actor_queue_relayout (self);
8879 clutter_actor_set_natural_width_set (ClutterActor *self,
8880 gboolean use_natural_width)
8882 ClutterActorPrivate *priv = self->priv;
8883 ClutterActorBox old = { 0, };
8885 if (priv->natural_width_set == (use_natural_width != FALSE))
8888 clutter_actor_store_old_geometry (self, &old);
8890 priv->natural_width_set = use_natural_width != FALSE;
8891 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8893 clutter_actor_notify_if_geometry_changed (self, &old);
8895 clutter_actor_queue_relayout (self);
8899 clutter_actor_set_natural_height_set (ClutterActor *self,
8900 gboolean use_natural_height)
8902 ClutterActorPrivate *priv = self->priv;
8903 ClutterActorBox old = { 0, };
8905 if (priv->natural_height_set == (use_natural_height != FALSE))
8908 clutter_actor_store_old_geometry (self, &old);
8910 priv->natural_height_set = use_natural_height != FALSE;
8911 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8913 clutter_actor_notify_if_geometry_changed (self, &old);
8915 clutter_actor_queue_relayout (self);
8919 * clutter_actor_set_request_mode:
8920 * @self: a #ClutterActor
8921 * @mode: the request mode
8923 * Sets the geometry request mode of @self.
8925 * The @mode determines the order for invoking
8926 * clutter_actor_get_preferred_width() and
8927 * clutter_actor_get_preferred_height()
8932 clutter_actor_set_request_mode (ClutterActor *self,
8933 ClutterRequestMode mode)
8935 ClutterActorPrivate *priv;
8937 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8941 if (priv->request_mode == mode)
8944 priv->request_mode = mode;
8946 priv->needs_width_request = TRUE;
8947 priv->needs_height_request = TRUE;
8949 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8951 clutter_actor_queue_relayout (self);
8955 * clutter_actor_get_request_mode:
8956 * @self: a #ClutterActor
8958 * Retrieves the geometry request mode of @self
8960 * Return value: the request mode for the actor
8965 clutter_actor_get_request_mode (ClutterActor *self)
8967 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8968 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8970 return self->priv->request_mode;
8973 /* variant of set_width() without checks and without notification
8974 * freeze+thaw, for internal usage only
8977 clutter_actor_set_width_internal (ClutterActor *self,
8982 /* the Stage will use the :min-width to control the minimum
8983 * width to be resized to, so we should not be setting it
8984 * along with the :natural-width
8986 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8987 clutter_actor_set_min_width (self, width);
8989 clutter_actor_set_natural_width (self, width);
8993 /* we only unset the :natural-width for the Stage */
8994 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8995 clutter_actor_set_min_width_set (self, FALSE);
8997 clutter_actor_set_natural_width_set (self, FALSE);
9001 /* variant of set_height() without checks and without notification
9002 * freeze+thaw, for internal usage only
9005 clutter_actor_set_height_internal (ClutterActor *self,
9010 /* see the comment above in set_width_internal() */
9011 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9012 clutter_actor_set_min_height (self, height);
9014 clutter_actor_set_natural_height (self, height);
9018 /* see the comment above in set_width_internal() */
9019 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9020 clutter_actor_set_min_height_set (self, FALSE);
9022 clutter_actor_set_natural_height_set (self, FALSE);
9027 * clutter_actor_set_size:
9028 * @self: A #ClutterActor
9029 * @width: New width of actor in pixels, or -1
9030 * @height: New height of actor in pixels, or -1
9032 * Sets the actor's size request in pixels. This overrides any
9033 * "normal" size request the actor would have. For example
9034 * a text actor might normally request the size of the text;
9035 * this function would force a specific size instead.
9037 * If @width and/or @height are -1 the actor will use its
9038 * "normal" size request instead of overriding it, i.e.
9039 * you can "unset" the size with -1.
9041 * This function sets or unsets both the minimum and natural size.
9044 clutter_actor_set_size (ClutterActor *self,
9048 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9050 g_object_freeze_notify (G_OBJECT (self));
9052 clutter_actor_set_width (self, width);
9053 clutter_actor_set_height (self, height);
9055 g_object_thaw_notify (G_OBJECT (self));
9059 * clutter_actor_get_size:
9060 * @self: A #ClutterActor
9061 * @width: (out) (allow-none): return location for the width, or %NULL.
9062 * @height: (out) (allow-none): return location for the height, or %NULL.
9064 * This function tries to "do what you mean" and return
9065 * the size an actor will have. If the actor has a valid
9066 * allocation, the allocation will be returned; otherwise,
9067 * the actors natural size request will be returned.
9069 * If you care whether you get the request vs. the allocation, you
9070 * should probably call a different function like
9071 * clutter_actor_get_allocation_box() or
9072 * clutter_actor_get_preferred_width().
9077 clutter_actor_get_size (ClutterActor *self,
9081 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9084 *width = clutter_actor_get_width (self);
9087 *height = clutter_actor_get_height (self);
9091 * clutter_actor_get_position:
9092 * @self: a #ClutterActor
9093 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9094 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9096 * This function tries to "do what you mean" and tell you where the
9097 * actor is, prior to any transformations. Retrieves the fixed
9098 * position of an actor in pixels, if one has been set; otherwise, if
9099 * the allocation is valid, returns the actor's allocated position;
9100 * otherwise, returns 0,0.
9102 * The returned position is in pixels.
9107 clutter_actor_get_position (ClutterActor *self,
9111 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9114 *x = clutter_actor_get_x (self);
9117 *y = clutter_actor_get_y (self);
9121 * clutter_actor_get_transformed_position:
9122 * @self: A #ClutterActor
9123 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9124 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9126 * Gets the absolute position of an actor, in pixels relative to the stage.
9131 clutter_actor_get_transformed_position (ClutterActor *self,
9138 v1.x = v1.y = v1.z = 0;
9139 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9149 * clutter_actor_get_transformed_size:
9150 * @self: A #ClutterActor
9151 * @width: (out) (allow-none): return location for the width, or %NULL
9152 * @height: (out) (allow-none): return location for the height, or %NULL
9154 * Gets the absolute size of an actor in pixels, taking into account the
9157 * If the actor has a valid allocation, the allocated size will be used.
9158 * If the actor has not a valid allocation then the preferred size will
9159 * be transformed and returned.
9161 * If you want the transformed allocation, see
9162 * clutter_actor_get_abs_allocation_vertices() instead.
9164 * <note>When the actor (or one of its ancestors) is rotated around the
9165 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9166 * as a generic quadrangle; in that case this function returns the size
9167 * of the smallest rectangle that encapsulates the entire quad. Please
9168 * note that in this case no assumptions can be made about the relative
9169 * position of this envelope to the absolute position of the actor, as
9170 * returned by clutter_actor_get_transformed_position(); if you need this
9171 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9172 * to get the coords of the actual quadrangle.</note>
9177 clutter_actor_get_transformed_size (ClutterActor *self,
9181 ClutterActorPrivate *priv;
9183 gfloat x_min, x_max, y_min, y_max;
9186 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9190 /* if the actor hasn't been allocated yet, get the preferred
9191 * size and transform that
9193 if (priv->needs_allocation)
9195 gfloat natural_width, natural_height;
9196 ClutterActorBox box;
9198 /* Make a fake allocation to transform.
9200 * NB: _clutter_actor_transform_and_project_box expects a box in
9201 * the actor's coordinate space... */
9206 natural_width = natural_height = 0;
9207 clutter_actor_get_preferred_size (self, NULL, NULL,
9211 box.x2 = natural_width;
9212 box.y2 = natural_height;
9214 _clutter_actor_transform_and_project_box (self, &box, v);
9217 clutter_actor_get_abs_allocation_vertices (self, v);
9219 x_min = x_max = v[0].x;
9220 y_min = y_max = v[0].y;
9222 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9238 *width = x_max - x_min;
9241 *height = y_max - y_min;
9245 * clutter_actor_get_width:
9246 * @self: A #ClutterActor
9248 * Retrieves the width of a #ClutterActor.
9250 * If the actor has a valid allocation, this function will return the
9251 * width of the allocated area given to the actor.
9253 * If the actor does not have a valid allocation, this function will
9254 * return the actor's natural width, that is the preferred width of
9257 * If you care whether you get the preferred width or the width that
9258 * has been assigned to the actor, you should probably call a different
9259 * function like clutter_actor_get_allocation_box() to retrieve the
9260 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9263 * If an actor has a fixed width, for instance a width that has been
9264 * assigned using clutter_actor_set_width(), the width returned will
9265 * be the same value.
9267 * Return value: the width of the actor, in pixels
9270 clutter_actor_get_width (ClutterActor *self)
9272 ClutterActorPrivate *priv;
9274 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9278 if (priv->needs_allocation)
9280 gfloat natural_width = 0;
9282 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9283 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9286 gfloat natural_height = 0;
9288 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9289 clutter_actor_get_preferred_width (self, natural_height,
9294 return natural_width;
9297 return priv->allocation.x2 - priv->allocation.x1;
9301 * clutter_actor_get_height:
9302 * @self: A #ClutterActor
9304 * Retrieves the height of a #ClutterActor.
9306 * If the actor has a valid allocation, this function will return the
9307 * height of the allocated area given to the actor.
9309 * If the actor does not have a valid allocation, this function will
9310 * return the actor's natural height, that is the preferred height of
9313 * If you care whether you get the preferred height or the height that
9314 * has been assigned to the actor, you should probably call a different
9315 * function like clutter_actor_get_allocation_box() to retrieve the
9316 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9319 * If an actor has a fixed height, for instance a height that has been
9320 * assigned using clutter_actor_set_height(), the height returned will
9321 * be the same value.
9323 * Return value: the height of the actor, in pixels
9326 clutter_actor_get_height (ClutterActor *self)
9328 ClutterActorPrivate *priv;
9330 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9334 if (priv->needs_allocation)
9336 gfloat natural_height = 0;
9338 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9340 gfloat natural_width = 0;
9342 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9343 clutter_actor_get_preferred_height (self, natural_width,
9344 NULL, &natural_height);
9347 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9349 return natural_height;
9352 return priv->allocation.y2 - priv->allocation.y1;
9356 * clutter_actor_set_width:
9357 * @self: A #ClutterActor
9358 * @width: Requested new width for the actor, in pixels, or -1
9360 * Forces a width on an actor, causing the actor's preferred width
9361 * and height (if any) to be ignored.
9363 * If @width is -1 the actor will use its preferred width request
9364 * instead of overriding it, i.e. you can "unset" the width with -1.
9366 * This function sets both the minimum and natural size of the actor.
9371 clutter_actor_set_width (ClutterActor *self,
9374 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9376 if (clutter_actor_get_easing_duration (self) != 0)
9378 ClutterTransition *transition;
9380 transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9381 if (transition == NULL)
9383 float old_width = clutter_actor_get_width (self);
9385 transition = _clutter_actor_create_transition (self,
9386 obj_props[PROP_WIDTH],
9389 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9392 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9394 clutter_actor_queue_relayout (self);
9398 g_object_freeze_notify (G_OBJECT (self));
9400 clutter_actor_set_width_internal (self, width);
9402 g_object_thaw_notify (G_OBJECT (self));
9407 * clutter_actor_set_height:
9408 * @self: A #ClutterActor
9409 * @height: Requested new height for the actor, in pixels, or -1
9411 * Forces a height on an actor, causing the actor's preferred width
9412 * and height (if any) to be ignored.
9414 * If @height is -1 the actor will use its preferred height instead of
9415 * overriding it, i.e. you can "unset" the height with -1.
9417 * This function sets both the minimum and natural size of the actor.
9422 clutter_actor_set_height (ClutterActor *self,
9425 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9427 if (clutter_actor_get_easing_duration (self) != 0)
9429 ClutterTransition *transition;
9431 transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9432 if (transition == NULL)
9434 float old_height = clutter_actor_get_height (self);
9436 transition = _clutter_actor_create_transition (self,
9437 obj_props[PROP_HEIGHT],
9440 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9443 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9445 clutter_actor_queue_relayout (self);
9449 g_object_freeze_notify (G_OBJECT (self));
9451 clutter_actor_set_height_internal (self, height);
9453 g_object_thaw_notify (G_OBJECT (self));
9458 clutter_actor_set_x_internal (ClutterActor *self,
9461 ClutterActorPrivate *priv = self->priv;
9462 ClutterLayoutInfo *linfo;
9463 ClutterActorBox old = { 0, };
9465 linfo = _clutter_actor_get_layout_info (self);
9467 if (priv->position_set && linfo->fixed_x == x)
9470 clutter_actor_store_old_geometry (self, &old);
9473 clutter_actor_set_fixed_position_set (self, TRUE);
9475 clutter_actor_notify_if_geometry_changed (self, &old);
9477 clutter_actor_queue_relayout (self);
9481 clutter_actor_set_y_internal (ClutterActor *self,
9484 ClutterActorPrivate *priv = self->priv;
9485 ClutterLayoutInfo *linfo;
9486 ClutterActorBox old = { 0, };
9488 linfo = _clutter_actor_get_layout_info (self);
9490 if (priv->position_set && linfo->fixed_y == y)
9493 clutter_actor_store_old_geometry (self, &old);
9496 clutter_actor_set_fixed_position_set (self, TRUE);
9498 clutter_actor_notify_if_geometry_changed (self, &old);
9500 clutter_actor_queue_relayout (self);
9504 * clutter_actor_set_x:
9505 * @self: a #ClutterActor
9506 * @x: the actor's position on the X axis
9508 * Sets the actor's X coordinate, relative to its parent, in pixels.
9510 * Overrides any layout manager and forces a fixed position for
9513 * The #ClutterActor:x property is animatable.
9518 clutter_actor_set_x (ClutterActor *self,
9521 const ClutterLayoutInfo *linfo;
9523 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9525 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9527 if (clutter_actor_get_easing_duration (self) != 0)
9529 ClutterTransition *transition;
9531 transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9532 if (transition == NULL)
9534 transition = _clutter_actor_create_transition (self,
9539 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9542 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9544 clutter_actor_queue_relayout (self);
9547 clutter_actor_set_x_internal (self, x);
9551 * clutter_actor_set_y:
9552 * @self: a #ClutterActor
9553 * @y: the actor's position on the Y axis
9555 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9557 * Overrides any layout manager and forces a fixed position for
9560 * The #ClutterActor:y property is animatable.
9565 clutter_actor_set_y (ClutterActor *self,
9568 const ClutterLayoutInfo *linfo;
9570 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9572 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9574 if (clutter_actor_get_easing_duration (self) != 0)
9576 ClutterTransition *transition;
9578 transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9579 if (transition == NULL)
9581 transition = _clutter_actor_create_transition (self,
9586 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9589 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9591 clutter_actor_queue_relayout (self);
9594 clutter_actor_set_y_internal (self, y);
9596 clutter_actor_queue_relayout (self);
9600 * clutter_actor_get_x:
9601 * @self: A #ClutterActor
9603 * Retrieves the X coordinate of a #ClutterActor.
9605 * This function tries to "do what you mean", by returning the
9606 * correct value depending on the actor's state.
9608 * If the actor has a valid allocation, this function will return
9609 * the X coordinate of the origin of the allocation box.
9611 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9612 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9613 * function will return that coordinate.
9615 * If both the allocation and a fixed position are missing, this function
9618 * Return value: the X coordinate, in pixels, ignoring any
9619 * transformation (i.e. scaling, rotation)
9622 clutter_actor_get_x (ClutterActor *self)
9624 ClutterActorPrivate *priv;
9626 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9630 if (priv->needs_allocation)
9632 if (priv->position_set)
9634 const ClutterLayoutInfo *info;
9636 info = _clutter_actor_get_layout_info_or_defaults (self);
9638 return info->fixed_x;
9644 return priv->allocation.x1;
9648 * clutter_actor_get_y:
9649 * @self: A #ClutterActor
9651 * Retrieves the Y coordinate of a #ClutterActor.
9653 * This function tries to "do what you mean", by returning the
9654 * correct value depending on the actor's state.
9656 * If the actor has a valid allocation, this function will return
9657 * the Y coordinate of the origin of the allocation box.
9659 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9660 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9661 * function will return that coordinate.
9663 * If both the allocation and a fixed position are missing, this function
9666 * Return value: the Y coordinate, in pixels, ignoring any
9667 * transformation (i.e. scaling, rotation)
9670 clutter_actor_get_y (ClutterActor *self)
9672 ClutterActorPrivate *priv;
9674 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9678 if (priv->needs_allocation)
9680 if (priv->position_set)
9682 const ClutterLayoutInfo *info;
9684 info = _clutter_actor_get_layout_info_or_defaults (self);
9686 return info->fixed_y;
9692 return priv->allocation.y1;
9696 * clutter_actor_set_scale:
9697 * @self: A #ClutterActor
9698 * @scale_x: double factor to scale actor by horizontally.
9699 * @scale_y: double factor to scale actor by vertically.
9701 * Scales an actor with the given factors. The scaling is relative to
9702 * the scale center and the anchor point. The scale center is
9703 * unchanged by this function and defaults to 0,0.
9705 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9711 clutter_actor_set_scale (ClutterActor *self,
9715 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9717 g_object_freeze_notify (G_OBJECT (self));
9719 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9720 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9722 g_object_thaw_notify (G_OBJECT (self));
9726 * clutter_actor_set_scale_full:
9727 * @self: A #ClutterActor
9728 * @scale_x: double factor to scale actor by horizontally.
9729 * @scale_y: double factor to scale actor by vertically.
9730 * @center_x: X coordinate of the center of the scale.
9731 * @center_y: Y coordinate of the center of the scale
9733 * Scales an actor with the given factors around the given center
9734 * point. The center point is specified in pixels relative to the
9735 * anchor point (usually the top left corner of the actor).
9737 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9743 clutter_actor_set_scale_full (ClutterActor *self,
9749 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9751 g_object_freeze_notify (G_OBJECT (self));
9753 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9754 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9755 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9756 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9758 g_object_thaw_notify (G_OBJECT (self));
9762 * clutter_actor_set_scale_with_gravity:
9763 * @self: A #ClutterActor
9764 * @scale_x: double factor to scale actor by horizontally.
9765 * @scale_y: double factor to scale actor by vertically.
9766 * @gravity: the location of the scale center expressed as a compass
9769 * Scales an actor with the given factors around the given
9770 * center point. The center point is specified as one of the compass
9771 * directions in #ClutterGravity. For example, setting it to north
9772 * will cause the top of the actor to remain unchanged and the rest of
9773 * the actor to expand left, right and downwards.
9775 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9781 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9784 ClutterGravity gravity)
9786 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9788 g_object_freeze_notify (G_OBJECT (self));
9790 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9791 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9792 clutter_actor_set_scale_gravity (self, gravity);
9794 g_object_thaw_notify (G_OBJECT (self));
9798 * clutter_actor_get_scale:
9799 * @self: A #ClutterActor
9800 * @scale_x: (out) (allow-none): Location to store horizonal
9801 * scale factor, or %NULL.
9802 * @scale_y: (out) (allow-none): Location to store vertical
9803 * scale factor, or %NULL.
9805 * Retrieves an actors scale factors.
9810 clutter_actor_get_scale (ClutterActor *self,
9814 const ClutterTransformInfo *info;
9816 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9818 info = _clutter_actor_get_transform_info_or_defaults (self);
9821 *scale_x = info->scale_x;
9824 *scale_y = info->scale_y;
9828 * clutter_actor_get_scale_center:
9829 * @self: A #ClutterActor
9830 * @center_x: (out) (allow-none): Location to store the X position
9831 * of the scale center, or %NULL.
9832 * @center_y: (out) (allow-none): Location to store the Y position
9833 * of the scale center, or %NULL.
9835 * Retrieves the scale center coordinate in pixels relative to the top
9836 * left corner of the actor. If the scale center was specified using a
9837 * #ClutterGravity this will calculate the pixel offset using the
9838 * current size of the actor.
9843 clutter_actor_get_scale_center (ClutterActor *self,
9847 const ClutterTransformInfo *info;
9849 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9851 info = _clutter_actor_get_transform_info_or_defaults (self);
9853 clutter_anchor_coord_get_units (self, &info->scale_center,
9860 * clutter_actor_get_scale_gravity:
9861 * @self: A #ClutterActor
9863 * Retrieves the scale center as a compass direction. If the scale
9864 * center was specified in pixels or units this will return
9865 * %CLUTTER_GRAVITY_NONE.
9867 * Return value: the scale gravity
9872 clutter_actor_get_scale_gravity (ClutterActor *self)
9874 const ClutterTransformInfo *info;
9876 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9878 info = _clutter_actor_get_transform_info_or_defaults (self);
9880 return clutter_anchor_coord_get_gravity (&info->scale_center);
9884 clutter_actor_set_opacity_internal (ClutterActor *self,
9887 ClutterActorPrivate *priv = self->priv;
9889 if (priv->opacity != opacity)
9891 priv->opacity = opacity;
9893 /* Queue a redraw from the flatten effect so that it can use
9894 its cached image if available instead of having to redraw the
9895 actual actor. If it doesn't end up using the FBO then the
9896 effect is still able to continue the paint anyway. If there
9897 is no flatten effect yet then this is equivalent to queueing
9899 _clutter_actor_queue_redraw_full (self,
9902 priv->flatten_effect);
9904 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9909 * clutter_actor_set_opacity:
9910 * @self: A #ClutterActor
9911 * @opacity: New opacity value for the actor.
9913 * Sets the actor's opacity, with zero being completely transparent and
9914 * 255 (0xff) being fully opaque.
9916 * The #ClutterActor:opacity property is animatable.
9919 clutter_actor_set_opacity (ClutterActor *self,
9922 ClutterActorPrivate *priv;
9924 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9928 if (clutter_actor_get_easing_duration (self) != 0)
9930 ClutterTransition *transition;
9932 transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9933 if (transition == NULL)
9935 transition = _clutter_actor_create_transition (self,
9936 obj_props[PROP_OPACITY],
9939 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9942 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9944 clutter_actor_queue_redraw (self);
9947 clutter_actor_set_opacity_internal (self, opacity);
9951 * clutter_actor_get_paint_opacity_internal:
9952 * @self: a #ClutterActor
9954 * Retrieves the absolute opacity of the actor, as it appears on the stage
9956 * This function does not do type checks
9958 * Return value: the absolute opacity of the actor
9961 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9963 ClutterActorPrivate *priv = self->priv;
9964 ClutterActor *parent;
9966 /* override the top-level opacity to always be 255; even in
9967 * case of ClutterStage:use-alpha being TRUE we want the rest
9968 * of the scene to be painted
9970 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9973 if (priv->opacity_override >= 0)
9974 return priv->opacity_override;
9976 parent = priv->parent;
9978 /* Factor in the actual actors opacity with parents */
9981 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9983 if (opacity != 0xff)
9984 return (opacity * priv->opacity) / 0xff;
9987 return priv->opacity;
9992 * clutter_actor_get_paint_opacity:
9993 * @self: A #ClutterActor
9995 * Retrieves the absolute opacity of the actor, as it appears on the stage.
9997 * This function traverses the hierarchy chain and composites the opacity of
9998 * the actor with that of its parents.
10000 * This function is intended for subclasses to use in the paint virtual
10001 * function, to paint themselves with the correct opacity.
10003 * Return value: The actor opacity value.
10008 clutter_actor_get_paint_opacity (ClutterActor *self)
10010 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10012 return clutter_actor_get_paint_opacity_internal (self);
10016 * clutter_actor_get_opacity:
10017 * @self: a #ClutterActor
10019 * Retrieves the opacity value of an actor, as set by
10020 * clutter_actor_set_opacity().
10022 * For retrieving the absolute opacity of the actor inside a paint
10023 * virtual function, see clutter_actor_get_paint_opacity().
10025 * Return value: the opacity of the actor
10028 clutter_actor_get_opacity (ClutterActor *self)
10030 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10032 return self->priv->opacity;
10036 * clutter_actor_set_offscreen_redirect:
10037 * @self: A #ClutterActor
10038 * @redirect: New offscreen redirect flags for the actor.
10040 * Defines the circumstances where the actor should be redirected into
10041 * an offscreen image. The offscreen image is used to flatten the
10042 * actor into a single image while painting for two main reasons.
10043 * Firstly, when the actor is painted a second time without any of its
10044 * contents changing it can simply repaint the cached image without
10045 * descending further down the actor hierarchy. Secondly, it will make
10046 * the opacity look correct even if there are overlapping primitives
10049 * Caching the actor could in some cases be a performance win and in
10050 * some cases be a performance lose so it is important to determine
10051 * which value is right for an actor before modifying this value. For
10052 * example, there is never any reason to flatten an actor that is just
10053 * a single texture (such as a #ClutterTexture) because it is
10054 * effectively already cached in an image so the offscreen would be
10055 * redundant. Also if the actor contains primitives that are far apart
10056 * with a large transparent area in the middle (such as a large
10057 * CluterGroup with a small actor in the top left and a small actor in
10058 * the bottom right) then the cached image will contain the entire
10059 * image of the large area and the paint will waste time blending all
10060 * of the transparent pixels in the middle.
10062 * The default method of implementing opacity on a container simply
10063 * forwards on the opacity to all of the children. If the children are
10064 * overlapping then it will appear as if they are two separate glassy
10065 * objects and there will be a break in the color where they
10066 * overlap. By redirecting to an offscreen buffer it will be as if the
10067 * two opaque objects are combined into one and then made transparent
10068 * which is usually what is expected.
10070 * The image below demonstrates the difference between redirecting and
10071 * not. The image shows two Clutter groups, each containing a red and
10072 * a green rectangle which overlap. The opacity on the group is set to
10073 * 128 (which is 50%). When the offscreen redirect is not used, the
10074 * red rectangle can be seen through the blue rectangle as if the two
10075 * rectangles were separately transparent. When the redirect is used
10076 * the group as a whole is transparent instead so the red rectangle is
10077 * not visible where they overlap.
10079 * <figure id="offscreen-redirect">
10080 * <title>Sample of using an offscreen redirect for transparency</title>
10081 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10084 * The default value for this property is 0, so we effectively will
10085 * never redirect an actor offscreen by default. This means that there
10086 * are times that transparent actors may look glassy as described
10087 * above. The reason this is the default is because there is a
10088 * performance trade off between quality and performance here. In many
10089 * cases the default form of glassy opacity looks good enough, but if
10090 * it's not you will need to set the
10091 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10092 * redirection for opacity.
10094 * Custom actors that don't contain any overlapping primitives are
10095 * recommended to override the has_overlaps() virtual to return %FALSE
10096 * for maximum efficiency.
10101 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10102 ClutterOffscreenRedirect redirect)
10104 ClutterActorPrivate *priv;
10106 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10110 if (priv->offscreen_redirect != redirect)
10112 priv->offscreen_redirect = redirect;
10114 /* Queue a redraw from the effect so that it can use its cached
10115 image if available instead of having to redraw the actual
10116 actor. If it doesn't end up using the FBO then the effect is
10117 still able to continue the paint anyway. If there is no
10118 effect then this is equivalent to queuing a full redraw */
10119 _clutter_actor_queue_redraw_full (self,
10122 priv->flatten_effect);
10124 g_object_notify_by_pspec (G_OBJECT (self),
10125 obj_props[PROP_OFFSCREEN_REDIRECT]);
10130 * clutter_actor_get_offscreen_redirect:
10131 * @self: a #ClutterActor
10133 * Retrieves whether to redirect the actor to an offscreen buffer, as
10134 * set by clutter_actor_set_offscreen_redirect().
10136 * Return value: the value of the offscreen-redirect property of the actor
10140 ClutterOffscreenRedirect
10141 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10143 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10145 return self->priv->offscreen_redirect;
10149 * clutter_actor_set_name:
10150 * @self: A #ClutterActor
10151 * @name: Textual tag to apply to actor
10153 * Sets the given name to @self. The name can be used to identify
10157 clutter_actor_set_name (ClutterActor *self,
10160 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10162 g_free (self->priv->name);
10163 self->priv->name = g_strdup (name);
10165 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10169 * clutter_actor_get_name:
10170 * @self: A #ClutterActor
10172 * Retrieves the name of @self.
10174 * Return value: the name of the actor, or %NULL. The returned string is
10175 * owned by the actor and should not be modified or freed.
10178 clutter_actor_get_name (ClutterActor *self)
10180 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10182 return self->priv->name;
10186 * clutter_actor_get_gid:
10187 * @self: A #ClutterActor
10189 * Retrieves the unique id for @self.
10191 * Return value: Globally unique value for this object instance.
10195 * Deprecated: 1.8: The id is not used any longer.
10198 clutter_actor_get_gid (ClutterActor *self)
10200 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10202 return self->priv->id;
10206 clutter_actor_set_depth_internal (ClutterActor *self,
10209 ClutterTransformInfo *info;
10211 info = _clutter_actor_get_transform_info (self);
10213 if (info->depth != depth)
10215 /* Sets Z value - XXX 2.0: should we invert? */
10216 info->depth = depth;
10218 self->priv->transform_valid = FALSE;
10220 /* FIXME - remove this crap; sadly, there are still containers
10221 * in Clutter that depend on this utter brain damage
10223 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10225 clutter_actor_queue_redraw (self);
10227 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10232 * clutter_actor_set_depth:
10233 * @self: a #ClutterActor
10236 * Sets the Z coordinate of @self to @depth.
10238 * The unit used by @depth is dependant on the perspective setup. See
10239 * also clutter_stage_set_perspective().
10242 clutter_actor_set_depth (ClutterActor *self,
10245 const ClutterTransformInfo *tinfo;
10247 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10249 tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10251 if (clutter_actor_get_easing_duration (self) != 0)
10253 ClutterTransition *transition;
10255 transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10256 if (transition == NULL)
10258 transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10261 clutter_timeline_start (CLUTTER_TIMELINE (transition));
10264 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10266 clutter_actor_queue_redraw (self);
10269 clutter_actor_set_depth_internal (self, depth);
10273 * clutter_actor_get_depth:
10274 * @self: a #ClutterActor
10276 * Retrieves the depth of @self.
10278 * Return value: the depth of the actor
10281 clutter_actor_get_depth (ClutterActor *self)
10283 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10285 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10289 * clutter_actor_set_rotation:
10290 * @self: a #ClutterActor
10291 * @axis: the axis of rotation
10292 * @angle: the angle of rotation
10293 * @x: X coordinate of the rotation center
10294 * @y: Y coordinate of the rotation center
10295 * @z: Z coordinate of the rotation center
10297 * Sets the rotation angle of @self around the given axis.
10299 * The rotation center coordinates used depend on the value of @axis:
10301 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10302 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10303 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10306 * The rotation coordinates are relative to the anchor point of the
10307 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10308 * point is set, the upper left corner is assumed as the origin.
10313 clutter_actor_set_rotation (ClutterActor *self,
10314 ClutterRotateAxis axis,
10322 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10328 g_object_freeze_notify (G_OBJECT (self));
10330 clutter_actor_set_rotation_angle (self, axis, angle);
10331 clutter_actor_set_rotation_center_internal (self, axis, &v);
10333 g_object_thaw_notify (G_OBJECT (self));
10337 * clutter_actor_set_z_rotation_from_gravity:
10338 * @self: a #ClutterActor
10339 * @angle: the angle of rotation
10340 * @gravity: the center point of the rotation
10342 * Sets the rotation angle of @self around the Z axis using the center
10343 * point specified as a compass point. For example to rotate such that
10344 * the center of the actor remains static you can use
10345 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10346 * will move accordingly.
10351 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10353 ClutterGravity gravity)
10355 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10357 if (gravity == CLUTTER_GRAVITY_NONE)
10358 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10361 GObject *obj = G_OBJECT (self);
10362 ClutterTransformInfo *info;
10364 info = _clutter_actor_get_transform_info (self);
10366 g_object_freeze_notify (obj);
10368 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10370 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10371 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10372 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10374 g_object_thaw_notify (obj);
10379 * clutter_actor_get_rotation:
10380 * @self: a #ClutterActor
10381 * @axis: the axis of rotation
10382 * @x: (out): return value for the X coordinate of the center of rotation
10383 * @y: (out): return value for the Y coordinate of the center of rotation
10384 * @z: (out): return value for the Z coordinate of the center of rotation
10386 * Retrieves the angle and center of rotation on the given axis,
10387 * set using clutter_actor_set_rotation().
10389 * Return value: the angle of rotation
10394 clutter_actor_get_rotation (ClutterActor *self,
10395 ClutterRotateAxis axis,
10400 const ClutterTransformInfo *info;
10401 const AnchorCoord *anchor_coord;
10402 gdouble retval = 0;
10404 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10406 info = _clutter_actor_get_transform_info_or_defaults (self);
10410 case CLUTTER_X_AXIS:
10411 anchor_coord = &info->rx_center;
10412 retval = info->rx_angle;
10415 case CLUTTER_Y_AXIS:
10416 anchor_coord = &info->ry_center;
10417 retval = info->ry_angle;
10420 case CLUTTER_Z_AXIS:
10421 anchor_coord = &info->rz_center;
10422 retval = info->rz_angle;
10426 anchor_coord = NULL;
10431 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10437 * clutter_actor_get_z_rotation_gravity:
10438 * @self: A #ClutterActor
10440 * Retrieves the center for the rotation around the Z axis as a
10441 * compass direction. If the center was specified in pixels or units
10442 * this will return %CLUTTER_GRAVITY_NONE.
10444 * Return value: the Z rotation center
10449 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10451 const ClutterTransformInfo *info;
10453 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10455 info = _clutter_actor_get_transform_info_or_defaults (self);
10457 return clutter_anchor_coord_get_gravity (&info->rz_center);
10461 * clutter_actor_set_clip:
10462 * @self: A #ClutterActor
10463 * @xoff: X offset of the clip rectangle
10464 * @yoff: Y offset of the clip rectangle
10465 * @width: Width of the clip rectangle
10466 * @height: Height of the clip rectangle
10468 * Sets clip area for @self. The clip area is always computed from the
10469 * upper left corner of the actor, even if the anchor point is set
10475 clutter_actor_set_clip (ClutterActor *self,
10481 ClutterActorPrivate *priv;
10483 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10487 if (priv->has_clip &&
10488 priv->clip.x == xoff &&
10489 priv->clip.y == yoff &&
10490 priv->clip.width == width &&
10491 priv->clip.height == height)
10494 priv->clip.x = xoff;
10495 priv->clip.y = yoff;
10496 priv->clip.width = width;
10497 priv->clip.height = height;
10499 priv->has_clip = TRUE;
10501 clutter_actor_queue_redraw (self);
10503 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10504 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10508 * clutter_actor_remove_clip:
10509 * @self: A #ClutterActor
10511 * Removes clip area from @self.
10514 clutter_actor_remove_clip (ClutterActor *self)
10516 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10518 if (!self->priv->has_clip)
10521 self->priv->has_clip = FALSE;
10523 clutter_actor_queue_redraw (self);
10525 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10529 * clutter_actor_has_clip:
10530 * @self: a #ClutterActor
10532 * Determines whether the actor has a clip area set or not.
10534 * Return value: %TRUE if the actor has a clip area set.
10539 clutter_actor_has_clip (ClutterActor *self)
10541 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10543 return self->priv->has_clip;
10547 * clutter_actor_get_clip:
10548 * @self: a #ClutterActor
10549 * @xoff: (out) (allow-none): return location for the X offset of
10550 * the clip rectangle, or %NULL
10551 * @yoff: (out) (allow-none): return location for the Y offset of
10552 * the clip rectangle, or %NULL
10553 * @width: (out) (allow-none): return location for the width of
10554 * the clip rectangle, or %NULL
10555 * @height: (out) (allow-none): return location for the height of
10556 * the clip rectangle, or %NULL
10558 * Gets the clip area for @self, if any is set
10563 clutter_actor_get_clip (ClutterActor *self,
10569 ClutterActorPrivate *priv;
10571 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10575 if (!priv->has_clip)
10579 *xoff = priv->clip.x;
10582 *yoff = priv->clip.y;
10585 *width = priv->clip.width;
10587 if (height != NULL)
10588 *height = priv->clip.height;
10592 * clutter_actor_get_children:
10593 * @self: a #ClutterActor
10595 * Retrieves the list of children of @self.
10597 * Return value: (transfer container) (element-type ClutterActor): A newly
10598 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10604 clutter_actor_get_children (ClutterActor *self)
10606 ClutterActor *iter;
10609 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10611 /* we walk the list backward so that we can use prepend(),
10614 for (iter = self->priv->last_child, res = NULL;
10616 iter = iter->priv->prev_sibling)
10618 res = g_list_prepend (res, iter);
10625 * insert_child_at_depth:
10626 * @self: a #ClutterActor
10627 * @child: a #ClutterActor
10629 * Inserts @child inside the list of children held by @self, using
10630 * the depth as the insertion criteria.
10632 * This sadly makes the insertion not O(1), but we can keep the
10633 * list sorted so that the painters algorithm we use for painting
10634 * the children will work correctly.
10637 insert_child_at_depth (ClutterActor *self,
10638 ClutterActor *child,
10639 gpointer dummy G_GNUC_UNUSED)
10641 ClutterActor *iter;
10644 child->priv->parent = self;
10647 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10649 /* special-case the first child */
10650 if (self->priv->n_children == 0)
10652 self->priv->first_child = child;
10653 self->priv->last_child = child;
10655 child->priv->next_sibling = NULL;
10656 child->priv->prev_sibling = NULL;
10661 /* Find the right place to insert the child so that it will still be
10662 sorted and the child will be after all of the actors at the same
10664 for (iter = self->priv->first_child;
10666 iter = iter->priv->next_sibling)
10671 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10673 if (iter_depth > child_depth)
10679 ClutterActor *tmp = iter->priv->prev_sibling;
10682 tmp->priv->next_sibling = child;
10684 /* Insert the node before the found one */
10685 child->priv->prev_sibling = iter->priv->prev_sibling;
10686 child->priv->next_sibling = iter;
10687 iter->priv->prev_sibling = child;
10691 ClutterActor *tmp = self->priv->last_child;
10694 tmp->priv->next_sibling = child;
10696 /* insert the node at the end of the list */
10697 child->priv->prev_sibling = self->priv->last_child;
10698 child->priv->next_sibling = NULL;
10701 if (child->priv->prev_sibling == NULL)
10702 self->priv->first_child = child;
10704 if (child->priv->next_sibling == NULL)
10705 self->priv->last_child = child;
10709 insert_child_at_index (ClutterActor *self,
10710 ClutterActor *child,
10713 gint index_ = GPOINTER_TO_INT (data_);
10715 child->priv->parent = self;
10719 ClutterActor *tmp = self->priv->first_child;
10722 tmp->priv->prev_sibling = child;
10724 child->priv->prev_sibling = NULL;
10725 child->priv->next_sibling = tmp;
10727 else if (index_ < 0 || index_ >= self->priv->n_children)
10729 ClutterActor *tmp = self->priv->last_child;
10732 tmp->priv->next_sibling = child;
10734 child->priv->prev_sibling = tmp;
10735 child->priv->next_sibling = NULL;
10739 ClutterActor *iter;
10742 for (iter = self->priv->first_child, i = 0;
10744 iter = iter->priv->next_sibling, i += 1)
10748 ClutterActor *tmp = iter->priv->prev_sibling;
10750 child->priv->prev_sibling = tmp;
10751 child->priv->next_sibling = iter;
10753 iter->priv->prev_sibling = child;
10756 tmp->priv->next_sibling = child;
10763 if (child->priv->prev_sibling == NULL)
10764 self->priv->first_child = child;
10766 if (child->priv->next_sibling == NULL)
10767 self->priv->last_child = child;
10771 insert_child_above (ClutterActor *self,
10772 ClutterActor *child,
10775 ClutterActor *sibling = data;
10777 child->priv->parent = self;
10779 if (sibling == NULL)
10780 sibling = self->priv->last_child;
10782 child->priv->prev_sibling = sibling;
10784 if (sibling != NULL)
10786 ClutterActor *tmp = sibling->priv->next_sibling;
10788 child->priv->next_sibling = tmp;
10791 tmp->priv->prev_sibling = child;
10793 sibling->priv->next_sibling = child;
10796 child->priv->next_sibling = NULL;
10798 if (child->priv->prev_sibling == NULL)
10799 self->priv->first_child = child;
10801 if (child->priv->next_sibling == NULL)
10802 self->priv->last_child = child;
10806 insert_child_below (ClutterActor *self,
10807 ClutterActor *child,
10810 ClutterActor *sibling = data;
10812 child->priv->parent = self;
10814 if (sibling == NULL)
10815 sibling = self->priv->first_child;
10817 child->priv->next_sibling = sibling;
10819 if (sibling != NULL)
10821 ClutterActor *tmp = sibling->priv->prev_sibling;
10823 child->priv->prev_sibling = tmp;
10826 tmp->priv->next_sibling = child;
10828 sibling->priv->prev_sibling = child;
10831 child->priv->prev_sibling = NULL;
10833 if (child->priv->prev_sibling == NULL)
10834 self->priv->first_child = child;
10836 if (child->priv->next_sibling == NULL)
10837 self->priv->last_child = child;
10840 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10841 ClutterActor *child,
10845 ADD_CHILD_CREATE_META = 1 << 0,
10846 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10847 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10848 ADD_CHILD_CHECK_STATE = 1 << 3,
10849 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10851 /* default flags for public API */
10852 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10853 ADD_CHILD_EMIT_PARENT_SET |
10854 ADD_CHILD_EMIT_ACTOR_ADDED |
10855 ADD_CHILD_CHECK_STATE |
10856 ADD_CHILD_NOTIFY_FIRST_LAST,
10858 /* flags for legacy/deprecated API */
10859 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10860 ADD_CHILD_CHECK_STATE |
10861 ADD_CHILD_NOTIFY_FIRST_LAST
10862 } ClutterActorAddChildFlags;
10865 * clutter_actor_add_child_internal:
10866 * @self: a #ClutterActor
10867 * @child: a #ClutterActor
10868 * @flags: control flags for actions
10869 * @add_func: delegate function
10870 * @data: (closure): data to pass to @add_func
10872 * Adds @child to the list of children of @self.
10874 * The actual insertion inside the list is delegated to @add_func: this
10875 * function will just set up the state, perform basic checks, and emit
10878 * The @flags argument is used to perform additional operations.
10881 clutter_actor_add_child_internal (ClutterActor *self,
10882 ClutterActor *child,
10883 ClutterActorAddChildFlags flags,
10884 ClutterActorAddChildFunc add_func,
10887 ClutterTextDirection text_dir;
10888 gboolean create_meta;
10889 gboolean emit_parent_set, emit_actor_added;
10890 gboolean check_state;
10891 gboolean notify_first_last;
10892 ClutterActor *old_first_child, *old_last_child;
10894 if (child->priv->parent != NULL)
10896 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10897 "use clutter_actor_remove_child() first.",
10898 _clutter_actor_get_debug_name (child),
10899 _clutter_actor_get_debug_name (child->priv->parent));
10903 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10905 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10906 "a child of another actor.",
10907 _clutter_actor_get_debug_name (child));
10912 /* XXX - this check disallows calling methods that change the stacking
10913 * order within the destruction sequence, by triggering a critical
10914 * warning first, and leaving the actor in an undefined state, which
10915 * then ends up being caught by an assertion.
10917 * the reproducible sequence is:
10919 * - actor gets destroyed;
10920 * - another actor, linked to the first, will try to change the
10921 * stacking order of the first actor;
10922 * - changing the stacking order is a composite operation composed
10923 * by the following steps:
10924 * 1. ref() the child;
10925 * 2. remove_child_internal(), which removes the reference;
10926 * 3. add_child_internal(), which adds a reference;
10927 * - the state of the actor is not changed between (2) and (3), as
10928 * it could be an expensive recomputation;
10929 * - if (3) bails out, then the actor is in an undefined state, but
10931 * - the destruction sequence terminates, but the actor is unparented
10932 * while its state indicates being parented instead.
10933 * - assertion failure.
10935 * the obvious fix would be to decompose each set_child_*_sibling()
10936 * method into proper remove_child()/add_child(), with state validation;
10937 * this may cause excessive work, though, and trigger a cascade of other
10938 * bugs in code that assumes that a change in the stacking order is an
10939 * atomic operation.
10941 * another potential fix is to just remove this check here, and let
10942 * code doing stacking order changes inside the destruction sequence
10943 * of an actor continue doing the work.
10945 * the third fix is to silently bail out early from every
10946 * set_child_*_sibling() and set_child_at_index() method, and avoid
10949 * I have a preference for the second solution, since it involves the
10950 * least amount of work, and the least amount of code duplication.
10952 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10954 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10956 g_warning ("The actor '%s' is currently being destroyed, and "
10957 "cannot be added as a child of another actor.",
10958 _clutter_actor_get_debug_name (child));
10963 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10964 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10965 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10966 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10967 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10969 old_first_child = self->priv->first_child;
10970 old_last_child = self->priv->last_child;
10972 g_object_freeze_notify (G_OBJECT (self));
10975 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10977 g_object_ref_sink (child);
10978 child->priv->parent = NULL;
10979 child->priv->next_sibling = NULL;
10980 child->priv->prev_sibling = NULL;
10982 /* delegate the actual insertion */
10983 add_func (self, child, data);
10985 g_assert (child->priv->parent == self);
10987 self->priv->n_children += 1;
10989 self->priv->age += 1;
10991 /* if push_internal() has been called then we automatically set
10992 * the flag on the actor
10994 if (self->priv->internal_child)
10995 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10997 /* clutter_actor_reparent() will emit ::parent-set for us */
10998 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10999 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11003 /* If parent is mapped or realized, we need to also be mapped or
11004 * realized once we're inside the parent.
11006 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11008 /* propagate the parent's text direction to the child */
11009 text_dir = clutter_actor_get_text_direction (self);
11010 clutter_actor_set_text_direction (child, text_dir);
11013 if (child->priv->show_on_set_parent)
11014 clutter_actor_show (child);
11016 if (CLUTTER_ACTOR_IS_MAPPED (child))
11017 clutter_actor_queue_redraw (child);
11019 /* maintain the invariant that if an actor needs layout,
11020 * its parents do as well
11022 if (child->priv->needs_width_request ||
11023 child->priv->needs_height_request ||
11024 child->priv->needs_allocation)
11026 /* we work around the short-circuiting we do
11027 * in clutter_actor_queue_relayout() since we
11028 * want to force a relayout
11030 child->priv->needs_width_request = TRUE;
11031 child->priv->needs_height_request = TRUE;
11032 child->priv->needs_allocation = TRUE;
11034 clutter_actor_queue_relayout (child->priv->parent);
11037 if (emit_actor_added)
11038 g_signal_emit_by_name (self, "actor-added", child);
11040 if (notify_first_last)
11042 if (old_first_child != self->priv->first_child)
11043 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11045 if (old_last_child != self->priv->last_child)
11046 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11049 g_object_thaw_notify (G_OBJECT (self));
11053 * clutter_actor_add_child:
11054 * @self: a #ClutterActor
11055 * @child: a #ClutterActor
11057 * Adds @child to the children of @self.
11059 * This function will acquire a reference on @child that will only
11060 * be released when calling clutter_actor_remove_child().
11062 * This function will take into consideration the #ClutterActor:depth
11063 * of @child, and will keep the list of children sorted.
11065 * This function will emit the #ClutterContainer::actor-added signal
11071 clutter_actor_add_child (ClutterActor *self,
11072 ClutterActor *child)
11074 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11075 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11076 g_return_if_fail (self != child);
11077 g_return_if_fail (child->priv->parent == NULL);
11079 clutter_actor_add_child_internal (self, child,
11080 ADD_CHILD_DEFAULT_FLAGS,
11081 insert_child_at_depth,
11086 * clutter_actor_insert_child_at_index:
11087 * @self: a #ClutterActor
11088 * @child: a #ClutterActor
11089 * @index_: the index
11091 * Inserts @child into the list of children of @self, using the
11092 * given @index_. If @index_ is greater than the number of children
11093 * in @self, or is less than 0, then the new child is added at the end.
11095 * This function will acquire a reference on @child that will only
11096 * be released when calling clutter_actor_remove_child().
11098 * This function will not take into consideration the #ClutterActor:depth
11101 * This function will emit the #ClutterContainer::actor-added signal
11107 clutter_actor_insert_child_at_index (ClutterActor *self,
11108 ClutterActor *child,
11111 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11112 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11113 g_return_if_fail (self != child);
11114 g_return_if_fail (child->priv->parent == NULL);
11116 clutter_actor_add_child_internal (self, child,
11117 ADD_CHILD_DEFAULT_FLAGS,
11118 insert_child_at_index,
11119 GINT_TO_POINTER (index_));
11123 * clutter_actor_insert_child_above:
11124 * @self: a #ClutterActor
11125 * @child: a #ClutterActor
11126 * @sibling: (allow-none): a child of @self, or %NULL
11128 * Inserts @child into the list of children of @self, above another
11129 * child of @self or, if @sibling is %NULL, above all the children
11132 * This function will acquire a reference on @child that will only
11133 * be released when calling clutter_actor_remove_child().
11135 * This function will not take into consideration the #ClutterActor:depth
11138 * This function will emit the #ClutterContainer::actor-added signal
11144 clutter_actor_insert_child_above (ClutterActor *self,
11145 ClutterActor *child,
11146 ClutterActor *sibling)
11148 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11149 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11150 g_return_if_fail (self != child);
11151 g_return_if_fail (child != sibling);
11152 g_return_if_fail (child->priv->parent == NULL);
11153 g_return_if_fail (sibling == NULL ||
11154 (CLUTTER_IS_ACTOR (sibling) &&
11155 sibling->priv->parent == self));
11157 clutter_actor_add_child_internal (self, child,
11158 ADD_CHILD_DEFAULT_FLAGS,
11159 insert_child_above,
11164 * clutter_actor_insert_child_below:
11165 * @self: a #ClutterActor
11166 * @child: a #ClutterActor
11167 * @sibling: (allow-none): a child of @self, or %NULL
11169 * Inserts @child into the list of children of @self, below another
11170 * child of @self or, if @sibling is %NULL, below all the children
11173 * This function will acquire a reference on @child that will only
11174 * be released when calling clutter_actor_remove_child().
11176 * This function will not take into consideration the #ClutterActor:depth
11179 * This function will emit the #ClutterContainer::actor-added signal
11185 clutter_actor_insert_child_below (ClutterActor *self,
11186 ClutterActor *child,
11187 ClutterActor *sibling)
11189 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11190 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11191 g_return_if_fail (self != child);
11192 g_return_if_fail (child != sibling);
11193 g_return_if_fail (child->priv->parent == NULL);
11194 g_return_if_fail (sibling == NULL ||
11195 (CLUTTER_IS_ACTOR (sibling) &&
11196 sibling->priv->parent == self));
11198 clutter_actor_add_child_internal (self, child,
11199 ADD_CHILD_DEFAULT_FLAGS,
11200 insert_child_below,
11205 * clutter_actor_set_parent:
11206 * @self: A #ClutterActor
11207 * @parent: A new #ClutterActor parent
11209 * Sets the parent of @self to @parent.
11211 * This function will result in @parent acquiring a reference on @self,
11212 * eventually by sinking its floating reference first. The reference
11213 * will be released by clutter_actor_unparent().
11215 * This function should only be called by legacy #ClutterActor<!-- -->s
11216 * implementing the #ClutterContainer interface.
11218 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11221 clutter_actor_set_parent (ClutterActor *self,
11222 ClutterActor *parent)
11224 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11225 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11226 g_return_if_fail (self != parent);
11227 g_return_if_fail (self->priv->parent == NULL);
11229 /* as this function will be called inside ClutterContainer::add
11230 * implementations or when building up a composite actor, we have
11231 * to preserve the old behaviour, and not create child meta or
11232 * emit the ::actor-added signal, to avoid recursion or double
11235 clutter_actor_add_child_internal (parent, self,
11236 ADD_CHILD_LEGACY_FLAGS,
11237 insert_child_at_depth,
11242 * clutter_actor_get_parent:
11243 * @self: A #ClutterActor
11245 * Retrieves the parent of @self.
11247 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11248 * if no parent is set
11251 clutter_actor_get_parent (ClutterActor *self)
11253 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11255 return self->priv->parent;
11259 * clutter_actor_get_paint_visibility:
11260 * @self: A #ClutterActor
11262 * Retrieves the 'paint' visibility of an actor recursively checking for non
11265 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11267 * Return Value: %TRUE if the actor is visibile and will be painted.
11272 clutter_actor_get_paint_visibility (ClutterActor *actor)
11274 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11276 return CLUTTER_ACTOR_IS_MAPPED (actor);
11280 * clutter_actor_remove_child:
11281 * @self: a #ClutterActor
11282 * @child: a #ClutterActor
11284 * Removes @child from the children of @self.
11286 * This function will release the reference added by
11287 * clutter_actor_add_child(), so if you want to keep using @child
11288 * you will have to acquire a referenced on it before calling this
11291 * This function will emit the #ClutterContainer::actor-removed
11297 clutter_actor_remove_child (ClutterActor *self,
11298 ClutterActor *child)
11300 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11301 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11302 g_return_if_fail (self != child);
11303 g_return_if_fail (child->priv->parent != NULL);
11304 g_return_if_fail (child->priv->parent == self);
11306 clutter_actor_remove_child_internal (self, child,
11307 REMOVE_CHILD_DEFAULT_FLAGS);
11311 * clutter_actor_remove_all_children:
11312 * @self: a #ClutterActor
11314 * Removes all children of @self.
11316 * This function releases the reference added by inserting a child actor
11317 * in the list of children of @self.
11319 * If the reference count of a child drops to zero, the child will be
11320 * destroyed. If you want to ensure the destruction of all the children
11321 * of @self, use clutter_actor_destroy_all_children().
11326 clutter_actor_remove_all_children (ClutterActor *self)
11328 ClutterActorIter iter;
11330 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11332 if (self->priv->n_children == 0)
11335 g_object_freeze_notify (G_OBJECT (self));
11337 clutter_actor_iter_init (&iter, self);
11338 while (clutter_actor_iter_next (&iter, NULL))
11339 clutter_actor_iter_remove (&iter);
11341 g_object_thaw_notify (G_OBJECT (self));
11344 g_assert (self->priv->first_child == NULL);
11345 g_assert (self->priv->last_child == NULL);
11346 g_assert (self->priv->n_children == 0);
11350 * clutter_actor_destroy_all_children:
11351 * @self: a #ClutterActor
11353 * Destroys all children of @self.
11355 * This function releases the reference added by inserting a child
11356 * actor in the list of children of @self, and ensures that the
11357 * #ClutterActor::destroy signal is emitted on each child of the
11360 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11361 * when its reference count drops to 0; the default handler of the
11362 * #ClutterActor::destroy signal will destroy all the children of an
11363 * actor. This function ensures that all children are destroyed, instead
11364 * of just removed from @self, unlike clutter_actor_remove_all_children()
11365 * which will merely release the reference and remove each child.
11367 * Unless you acquired an additional reference on each child of @self
11368 * prior to calling clutter_actor_remove_all_children() and want to reuse
11369 * the actors, you should use clutter_actor_destroy_all_children() in
11370 * order to make sure that children are destroyed and signal handlers
11371 * are disconnected even in cases where circular references prevent this
11372 * from automatically happening through reference counting alone.
11377 clutter_actor_destroy_all_children (ClutterActor *self)
11379 ClutterActorIter iter;
11381 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11383 if (self->priv->n_children == 0)
11386 g_object_freeze_notify (G_OBJECT (self));
11388 clutter_actor_iter_init (&iter, self);
11389 while (clutter_actor_iter_next (&iter, NULL))
11390 clutter_actor_iter_destroy (&iter);
11392 g_object_thaw_notify (G_OBJECT (self));
11395 g_assert (self->priv->first_child == NULL);
11396 g_assert (self->priv->last_child == NULL);
11397 g_assert (self->priv->n_children == 0);
11400 typedef struct _InsertBetweenData {
11401 ClutterActor *prev_sibling;
11402 ClutterActor *next_sibling;
11403 } InsertBetweenData;
11406 insert_child_between (ClutterActor *self,
11407 ClutterActor *child,
11410 InsertBetweenData *data = data_;
11411 ClutterActor *prev_sibling = data->prev_sibling;
11412 ClutterActor *next_sibling = data->next_sibling;
11414 child->priv->parent = self;
11415 child->priv->prev_sibling = prev_sibling;
11416 child->priv->next_sibling = next_sibling;
11418 if (prev_sibling != NULL)
11419 prev_sibling->priv->next_sibling = child;
11421 if (next_sibling != NULL)
11422 next_sibling->priv->prev_sibling = child;
11424 if (child->priv->prev_sibling == NULL)
11425 self->priv->first_child = child;
11427 if (child->priv->next_sibling == NULL)
11428 self->priv->last_child = child;
11432 * clutter_actor_replace_child:
11433 * @self: a #ClutterActor
11434 * @old_child: the child of @self to replace
11435 * @new_child: the #ClutterActor to replace @old_child
11437 * Replaces @old_child with @new_child in the list of children of @self.
11442 clutter_actor_replace_child (ClutterActor *self,
11443 ClutterActor *old_child,
11444 ClutterActor *new_child)
11446 ClutterActor *prev_sibling, *next_sibling;
11447 InsertBetweenData clos;
11449 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11450 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11451 g_return_if_fail (old_child->priv->parent == self);
11452 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11453 g_return_if_fail (old_child != new_child);
11454 g_return_if_fail (new_child != self);
11455 g_return_if_fail (new_child->priv->parent == NULL);
11457 prev_sibling = old_child->priv->prev_sibling;
11458 next_sibling = old_child->priv->next_sibling;
11459 clutter_actor_remove_child_internal (self, old_child,
11460 REMOVE_CHILD_DEFAULT_FLAGS);
11462 clos.prev_sibling = prev_sibling;
11463 clos.next_sibling = next_sibling;
11464 clutter_actor_add_child_internal (self, new_child,
11465 ADD_CHILD_DEFAULT_FLAGS,
11466 insert_child_between,
11471 * clutter_actor_unparent:
11472 * @self: a #ClutterActor
11474 * Removes the parent of @self.
11476 * This will cause the parent of @self to release the reference
11477 * acquired when calling clutter_actor_set_parent(), so if you
11478 * want to keep @self you will have to acquire a reference of
11479 * your own, through g_object_ref().
11481 * This function should only be called by legacy #ClutterActor<!-- -->s
11482 * implementing the #ClutterContainer interface.
11486 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11489 clutter_actor_unparent (ClutterActor *self)
11491 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11493 if (self->priv->parent == NULL)
11496 clutter_actor_remove_child_internal (self->priv->parent, self,
11497 REMOVE_CHILD_LEGACY_FLAGS);
11501 * clutter_actor_reparent:
11502 * @self: a #ClutterActor
11503 * @new_parent: the new #ClutterActor parent
11505 * Resets the parent actor of @self.
11507 * This function is logically equivalent to calling clutter_actor_unparent()
11508 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11509 * ensures the child is not finalized when unparented, and emits the
11510 * #ClutterActor::parent-set signal only once.
11512 * In reality, calling this function is less useful than it sounds, as some
11513 * application code may rely on changes in the intermediate state between
11514 * removal and addition of the actor from its old parent to the @new_parent.
11515 * Thus, it is strongly encouraged to avoid using this function in application
11520 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11521 * clutter_actor_add_child() instead; remember to take a reference on
11522 * the actor being removed before calling clutter_actor_remove_child()
11523 * to avoid the reference count dropping to zero and the actor being
11527 clutter_actor_reparent (ClutterActor *self,
11528 ClutterActor *new_parent)
11530 ClutterActorPrivate *priv;
11532 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11533 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11534 g_return_if_fail (self != new_parent);
11536 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11538 g_warning ("Cannot set a parent on a toplevel actor");
11542 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11544 g_warning ("Cannot set a parent currently being destroyed");
11550 if (priv->parent != new_parent)
11552 ClutterActor *old_parent;
11554 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11556 old_parent = priv->parent;
11558 g_object_ref (self);
11560 if (old_parent != NULL)
11562 /* go through the Container implementation if this is a regular
11563 * child and not an internal one
11565 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11567 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11569 /* this will have to call unparent() */
11570 clutter_container_remove_actor (parent, self);
11573 clutter_actor_remove_child_internal (old_parent, self,
11574 REMOVE_CHILD_LEGACY_FLAGS);
11577 /* Note, will call set_parent() */
11578 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11579 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11581 clutter_actor_add_child_internal (new_parent, self,
11582 ADD_CHILD_LEGACY_FLAGS,
11583 insert_child_at_depth,
11586 /* we emit the ::parent-set signal once */
11587 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11589 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11591 /* the IN_REPARENT flag suspends state updates */
11592 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11594 g_object_unref (self);
11599 * clutter_actor_contains:
11600 * @self: A #ClutterActor
11601 * @descendant: A #ClutterActor, possibly contained in @self
11603 * Determines if @descendant is contained inside @self (either as an
11604 * immediate child, or as a deeper descendant). If @self and
11605 * @descendant point to the same actor then it will also return %TRUE.
11607 * Return value: whether @descendent is contained within @self
11612 clutter_actor_contains (ClutterActor *self,
11613 ClutterActor *descendant)
11615 ClutterActor *actor;
11617 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11618 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11620 for (actor = descendant; actor; actor = actor->priv->parent)
11628 * clutter_actor_set_child_above_sibling:
11629 * @self: a #ClutterActor
11630 * @child: a #ClutterActor child of @self
11631 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11633 * Sets @child to be above @sibling in the list of children of @self.
11635 * If @sibling is %NULL, @child will be the new last child of @self.
11637 * This function is logically equivalent to removing @child and using
11638 * clutter_actor_insert_child_above(), but it will not emit signals
11639 * or change state on @child.
11644 clutter_actor_set_child_above_sibling (ClutterActor *self,
11645 ClutterActor *child,
11646 ClutterActor *sibling)
11648 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11649 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11650 g_return_if_fail (child->priv->parent == self);
11651 g_return_if_fail (child != sibling);
11652 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11654 if (sibling != NULL)
11655 g_return_if_fail (sibling->priv->parent == self);
11657 /* we don't want to change the state of child, or emit signals, or
11658 * regenerate ChildMeta instances here, but we still want to follow
11659 * the correct sequence of steps encoded in remove_child() and
11660 * add_child(), so that correctness is ensured, and we only go
11661 * through one known code path.
11663 g_object_ref (child);
11664 clutter_actor_remove_child_internal (self, child, 0);
11665 clutter_actor_add_child_internal (self, child,
11666 ADD_CHILD_NOTIFY_FIRST_LAST,
11667 insert_child_above,
11670 clutter_actor_queue_relayout (self);
11674 * clutter_actor_set_child_below_sibling:
11675 * @self: a #ClutterActor
11676 * @child: a #ClutterActor child of @self
11677 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11679 * Sets @child to be below @sibling in the list of children of @self.
11681 * If @sibling is %NULL, @child will be the new first child of @self.
11683 * This function is logically equivalent to removing @self and using
11684 * clutter_actor_insert_child_below(), but it will not emit signals
11685 * or change state on @child.
11690 clutter_actor_set_child_below_sibling (ClutterActor *self,
11691 ClutterActor *child,
11692 ClutterActor *sibling)
11694 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11695 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11696 g_return_if_fail (child->priv->parent == self);
11697 g_return_if_fail (child != sibling);
11698 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11700 if (sibling != NULL)
11701 g_return_if_fail (sibling->priv->parent == self);
11703 /* see the comment in set_child_above_sibling() */
11704 g_object_ref (child);
11705 clutter_actor_remove_child_internal (self, child, 0);
11706 clutter_actor_add_child_internal (self, child,
11707 ADD_CHILD_NOTIFY_FIRST_LAST,
11708 insert_child_below,
11711 clutter_actor_queue_relayout (self);
11715 * clutter_actor_set_child_at_index:
11716 * @self: a #ClutterActor
11717 * @child: a #ClutterActor child of @self
11718 * @index_: the new index for @child
11720 * Changes the index of @child in the list of children of @self.
11722 * This function is logically equivalent to removing @child and
11723 * calling clutter_actor_insert_child_at_index(), but it will not
11724 * emit signals or change state on @child.
11729 clutter_actor_set_child_at_index (ClutterActor *self,
11730 ClutterActor *child,
11733 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11734 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11735 g_return_if_fail (child->priv->parent == self);
11736 g_return_if_fail (index_ <= self->priv->n_children);
11738 g_object_ref (child);
11739 clutter_actor_remove_child_internal (self, child, 0);
11740 clutter_actor_add_child_internal (self, child,
11741 ADD_CHILD_NOTIFY_FIRST_LAST,
11742 insert_child_at_index,
11743 GINT_TO_POINTER (index_));
11745 clutter_actor_queue_relayout (self);
11749 * clutter_actor_raise:
11750 * @self: A #ClutterActor
11751 * @below: (allow-none): A #ClutterActor to raise above.
11753 * Puts @self above @below.
11755 * Both actors must have the same parent, and the parent must implement
11756 * the #ClutterContainer interface
11758 * This function calls clutter_container_raise_child() internally.
11760 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11763 clutter_actor_raise (ClutterActor *self,
11764 ClutterActor *below)
11766 ClutterActor *parent;
11768 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11770 parent = clutter_actor_get_parent (self);
11771 if (parent == NULL)
11773 g_warning ("%s: Actor '%s' is not inside a container",
11775 _clutter_actor_get_debug_name (self));
11781 if (parent != clutter_actor_get_parent (below))
11783 g_warning ("%s Actor '%s' is not in the same container as "
11786 _clutter_actor_get_debug_name (self),
11787 _clutter_actor_get_debug_name (below));
11792 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11796 * clutter_actor_lower:
11797 * @self: A #ClutterActor
11798 * @above: (allow-none): A #ClutterActor to lower below
11800 * Puts @self below @above.
11802 * Both actors must have the same parent, and the parent must implement
11803 * the #ClutterContainer interface.
11805 * This function calls clutter_container_lower_child() internally.
11807 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11810 clutter_actor_lower (ClutterActor *self,
11811 ClutterActor *above)
11813 ClutterActor *parent;
11815 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11817 parent = clutter_actor_get_parent (self);
11818 if (parent == NULL)
11820 g_warning ("%s: Actor of type %s is not inside a container",
11822 _clutter_actor_get_debug_name (self));
11828 if (parent != clutter_actor_get_parent (above))
11830 g_warning ("%s: Actor '%s' is not in the same container as "
11833 _clutter_actor_get_debug_name (self),
11834 _clutter_actor_get_debug_name (above));
11839 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11843 * clutter_actor_raise_top:
11844 * @self: A #ClutterActor
11846 * Raises @self to the top.
11848 * This function calls clutter_actor_raise() internally.
11850 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11851 * a %NULL sibling, instead.
11854 clutter_actor_raise_top (ClutterActor *self)
11856 clutter_actor_raise (self, NULL);
11860 * clutter_actor_lower_bottom:
11861 * @self: A #ClutterActor
11863 * Lowers @self to the bottom.
11865 * This function calls clutter_actor_lower() internally.
11867 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11868 * a %NULL sibling, instead.
11871 clutter_actor_lower_bottom (ClutterActor *self)
11873 clutter_actor_lower (self, NULL);
11881 * clutter_actor_event:
11882 * @actor: a #ClutterActor
11883 * @event: a #ClutterEvent
11884 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11886 * This function is used to emit an event on the main stage.
11887 * You should rarely need to use this function, except for
11888 * synthetising events.
11890 * Return value: the return value from the signal emission: %TRUE
11891 * if the actor handled the event, or %FALSE if the event was
11897 clutter_actor_event (ClutterActor *actor,
11898 ClutterEvent *event,
11901 gboolean retval = FALSE;
11902 gint signal_num = -1;
11904 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11905 g_return_val_if_fail (event != NULL, FALSE);
11907 g_object_ref (actor);
11911 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11917 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11921 switch (event->type)
11923 case CLUTTER_NOTHING:
11925 case CLUTTER_BUTTON_PRESS:
11926 signal_num = BUTTON_PRESS_EVENT;
11928 case CLUTTER_BUTTON_RELEASE:
11929 signal_num = BUTTON_RELEASE_EVENT;
11931 case CLUTTER_SCROLL:
11932 signal_num = SCROLL_EVENT;
11934 case CLUTTER_KEY_PRESS:
11935 signal_num = KEY_PRESS_EVENT;
11937 case CLUTTER_KEY_RELEASE:
11938 signal_num = KEY_RELEASE_EVENT;
11940 case CLUTTER_MOTION:
11941 signal_num = MOTION_EVENT;
11943 case CLUTTER_ENTER:
11944 signal_num = ENTER_EVENT;
11946 case CLUTTER_LEAVE:
11947 signal_num = LEAVE_EVENT;
11949 case CLUTTER_DELETE:
11950 case CLUTTER_DESTROY_NOTIFY:
11951 case CLUTTER_CLIENT_MESSAGE:
11957 if (signal_num != -1)
11958 g_signal_emit (actor, actor_signals[signal_num], 0,
11963 g_object_unref (actor);
11969 * clutter_actor_set_reactive:
11970 * @actor: a #ClutterActor
11971 * @reactive: whether the actor should be reactive to events
11973 * Sets @actor as reactive. Reactive actors will receive events.
11978 clutter_actor_set_reactive (ClutterActor *actor,
11981 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11983 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11987 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11989 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11991 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11995 * clutter_actor_get_reactive:
11996 * @actor: a #ClutterActor
11998 * Checks whether @actor is marked as reactive.
12000 * Return value: %TRUE if the actor is reactive
12005 clutter_actor_get_reactive (ClutterActor *actor)
12007 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12009 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12013 * clutter_actor_get_anchor_point:
12014 * @self: a #ClutterActor
12015 * @anchor_x: (out): return location for the X coordinate of the anchor point
12016 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12018 * Gets the current anchor point of the @actor in pixels.
12023 clutter_actor_get_anchor_point (ClutterActor *self,
12027 const ClutterTransformInfo *info;
12029 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12031 info = _clutter_actor_get_transform_info_or_defaults (self);
12032 clutter_anchor_coord_get_units (self, &info->anchor,
12039 * clutter_actor_set_anchor_point:
12040 * @self: a #ClutterActor
12041 * @anchor_x: X coordinate of the anchor point
12042 * @anchor_y: Y coordinate of the anchor point
12044 * Sets an anchor point for @self. The anchor point is a point in the
12045 * coordinate space of an actor to which the actor position within its
12046 * parent is relative; the default is (0, 0), i.e. the top-left corner
12052 clutter_actor_set_anchor_point (ClutterActor *self,
12056 ClutterTransformInfo *info;
12057 ClutterActorPrivate *priv;
12058 gboolean changed = FALSE;
12059 gfloat old_anchor_x, old_anchor_y;
12062 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12064 obj = G_OBJECT (self);
12066 info = _clutter_actor_get_transform_info (self);
12068 g_object_freeze_notify (obj);
12070 clutter_anchor_coord_get_units (self, &info->anchor,
12075 if (info->anchor.is_fractional)
12076 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12078 if (old_anchor_x != anchor_x)
12080 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12084 if (old_anchor_y != anchor_y)
12086 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12090 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12094 priv->transform_valid = FALSE;
12095 clutter_actor_queue_redraw (self);
12098 g_object_thaw_notify (obj);
12102 * clutter_actor_get_anchor_point_gravity:
12103 * @self: a #ClutterActor
12105 * Retrieves the anchor position expressed as a #ClutterGravity. If
12106 * the anchor point was specified using pixels or units this will
12107 * return %CLUTTER_GRAVITY_NONE.
12109 * Return value: the #ClutterGravity used by the anchor point
12114 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12116 const ClutterTransformInfo *info;
12118 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12120 info = _clutter_actor_get_transform_info_or_defaults (self);
12122 return clutter_anchor_coord_get_gravity (&info->anchor);
12126 * clutter_actor_move_anchor_point:
12127 * @self: a #ClutterActor
12128 * @anchor_x: X coordinate of the anchor point
12129 * @anchor_y: Y coordinate of the anchor point
12131 * Sets an anchor point for the actor, and adjusts the actor postion so that
12132 * the relative position of the actor toward its parent remains the same.
12137 clutter_actor_move_anchor_point (ClutterActor *self,
12141 gfloat old_anchor_x, old_anchor_y;
12142 const ClutterTransformInfo *info;
12144 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12146 info = _clutter_actor_get_transform_info (self);
12147 clutter_anchor_coord_get_units (self, &info->anchor,
12152 g_object_freeze_notify (G_OBJECT (self));
12154 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12156 if (self->priv->position_set)
12157 clutter_actor_move_by (self,
12158 anchor_x - old_anchor_x,
12159 anchor_y - old_anchor_y);
12161 g_object_thaw_notify (G_OBJECT (self));
12165 * clutter_actor_move_anchor_point_from_gravity:
12166 * @self: a #ClutterActor
12167 * @gravity: #ClutterGravity.
12169 * Sets an anchor point on the actor based on the given gravity, adjusting the
12170 * actor postion so that its relative position within its parent remains
12173 * Since version 1.0 the anchor point will be stored as a gravity so
12174 * that if the actor changes size then the anchor point will move. For
12175 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12176 * and later double the size of the actor, the anchor point will move
12177 * to the bottom right.
12182 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12183 ClutterGravity gravity)
12185 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12186 const ClutterTransformInfo *info;
12187 ClutterActorPrivate *priv;
12189 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12192 info = _clutter_actor_get_transform_info (self);
12194 g_object_freeze_notify (G_OBJECT (self));
12196 clutter_anchor_coord_get_units (self, &info->anchor,
12200 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12201 clutter_anchor_coord_get_units (self, &info->anchor,
12206 if (priv->position_set)
12207 clutter_actor_move_by (self,
12208 new_anchor_x - old_anchor_x,
12209 new_anchor_y - old_anchor_y);
12211 g_object_thaw_notify (G_OBJECT (self));
12215 * clutter_actor_set_anchor_point_from_gravity:
12216 * @self: a #ClutterActor
12217 * @gravity: #ClutterGravity.
12219 * Sets an anchor point on the actor, based on the given gravity (this is a
12220 * convenience function wrapping clutter_actor_set_anchor_point()).
12222 * Since version 1.0 the anchor point will be stored as a gravity so
12223 * that if the actor changes size then the anchor point will move. For
12224 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12225 * and later double the size of the actor, the anchor point will move
12226 * to the bottom right.
12231 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12232 ClutterGravity gravity)
12234 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12236 if (gravity == CLUTTER_GRAVITY_NONE)
12237 clutter_actor_set_anchor_point (self, 0, 0);
12240 GObject *obj = G_OBJECT (self);
12241 ClutterTransformInfo *info;
12243 g_object_freeze_notify (obj);
12245 info = _clutter_actor_get_transform_info (self);
12246 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12248 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12249 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12250 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12252 self->priv->transform_valid = FALSE;
12254 clutter_actor_queue_redraw (self);
12256 g_object_thaw_notify (obj);
12261 clutter_container_iface_init (ClutterContainerIface *iface)
12263 /* we don't override anything, as ClutterContainer already has a default
12264 * implementation that we can use, and which calls into our own API.
12279 parse_units (ClutterActor *self,
12280 ParseDimension dimension,
12283 GValue value = G_VALUE_INIT;
12286 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12289 json_node_get_value (node, &value);
12291 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12293 retval = (gfloat) g_value_get_int64 (&value);
12295 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12297 retval = g_value_get_double (&value);
12299 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12301 ClutterUnits units;
12304 res = clutter_units_from_string (&units, g_value_get_string (&value));
12306 retval = clutter_units_to_pixels (&units);
12309 g_warning ("Invalid value '%s': integers, strings or floating point "
12310 "values can be used for the x, y, width and height "
12311 "properties. Valid modifiers for strings are 'px', 'mm', "
12313 g_value_get_string (&value));
12319 g_warning ("Invalid value of type '%s': integers, strings of floating "
12320 "point values can be used for the x, y, width, height "
12321 "anchor-x and anchor-y properties.",
12322 g_type_name (G_VALUE_TYPE (&value)));
12325 g_value_unset (&value);
12331 ClutterRotateAxis axis;
12340 static inline gboolean
12341 parse_rotation_array (ClutterActor *actor,
12343 RotationInfo *info)
12347 if (json_array_get_length (array) != 2)
12351 element = json_array_get_element (array, 0);
12352 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12353 info->angle = json_node_get_double (element);
12358 element = json_array_get_element (array, 1);
12359 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12361 JsonArray *center = json_node_get_array (element);
12363 if (json_array_get_length (center) != 2)
12366 switch (info->axis)
12368 case CLUTTER_X_AXIS:
12369 info->center_y = parse_units (actor, PARSE_Y,
12370 json_array_get_element (center, 0));
12371 info->center_z = parse_units (actor, PARSE_Y,
12372 json_array_get_element (center, 1));
12375 case CLUTTER_Y_AXIS:
12376 info->center_x = parse_units (actor, PARSE_X,
12377 json_array_get_element (center, 0));
12378 info->center_z = parse_units (actor, PARSE_X,
12379 json_array_get_element (center, 1));
12382 case CLUTTER_Z_AXIS:
12383 info->center_x = parse_units (actor, PARSE_X,
12384 json_array_get_element (center, 0));
12385 info->center_y = parse_units (actor, PARSE_Y,
12386 json_array_get_element (center, 1));
12395 parse_rotation (ClutterActor *actor,
12397 RotationInfo *info)
12401 gboolean retval = FALSE;
12403 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12405 g_warning ("Invalid node of type '%s' found, expecting an array",
12406 json_node_type_name (node));
12410 array = json_node_get_array (node);
12411 len = json_array_get_length (array);
12413 for (i = 0; i < len; i++)
12415 JsonNode *element = json_array_get_element (array, i);
12416 JsonObject *object;
12419 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12421 g_warning ("Invalid node of type '%s' found, expecting an object",
12422 json_node_type_name (element));
12426 object = json_node_get_object (element);
12428 if (json_object_has_member (object, "x-axis"))
12430 member = json_object_get_member (object, "x-axis");
12432 info->axis = CLUTTER_X_AXIS;
12434 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12436 info->angle = json_node_get_double (member);
12439 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12440 retval = parse_rotation_array (actor,
12441 json_node_get_array (member),
12446 else if (json_object_has_member (object, "y-axis"))
12448 member = json_object_get_member (object, "y-axis");
12450 info->axis = CLUTTER_Y_AXIS;
12452 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12454 info->angle = json_node_get_double (member);
12457 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12458 retval = parse_rotation_array (actor,
12459 json_node_get_array (member),
12464 else if (json_object_has_member (object, "z-axis"))
12466 member = json_object_get_member (object, "z-axis");
12468 info->axis = CLUTTER_Z_AXIS;
12470 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12472 info->angle = json_node_get_double (member);
12475 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12476 retval = parse_rotation_array (actor,
12477 json_node_get_array (member),
12488 parse_actor_metas (ClutterScript *script,
12489 ClutterActor *actor,
12492 GList *elements, *l;
12493 GSList *retval = NULL;
12495 if (!JSON_NODE_HOLDS_ARRAY (node))
12498 elements = json_array_get_elements (json_node_get_array (node));
12500 for (l = elements; l != NULL; l = l->next)
12502 JsonNode *element = l->data;
12503 const gchar *id_ = _clutter_script_get_id_from_node (element);
12506 if (id_ == NULL || *id_ == '\0')
12509 meta = clutter_script_get_object (script, id_);
12513 retval = g_slist_prepend (retval, meta);
12516 g_list_free (elements);
12518 return g_slist_reverse (retval);
12522 parse_behaviours (ClutterScript *script,
12523 ClutterActor *actor,
12526 GList *elements, *l;
12527 GSList *retval = NULL;
12529 if (!JSON_NODE_HOLDS_ARRAY (node))
12532 elements = json_array_get_elements (json_node_get_array (node));
12534 for (l = elements; l != NULL; l = l->next)
12536 JsonNode *element = l->data;
12537 const gchar *id_ = _clutter_script_get_id_from_node (element);
12538 GObject *behaviour;
12540 if (id_ == NULL || *id_ == '\0')
12543 behaviour = clutter_script_get_object (script, id_);
12544 if (behaviour == NULL)
12547 retval = g_slist_prepend (retval, behaviour);
12550 g_list_free (elements);
12552 return g_slist_reverse (retval);
12556 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12557 ClutterScript *script,
12562 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12563 gboolean retval = FALSE;
12565 if ((name[0] == 'x' && name[1] == '\0') ||
12566 (name[0] == 'y' && name[1] == '\0') ||
12567 (strcmp (name, "width") == 0) ||
12568 (strcmp (name, "height") == 0) ||
12569 (strcmp (name, "anchor_x") == 0) ||
12570 (strcmp (name, "anchor_y") == 0))
12572 ParseDimension dimension;
12575 if (name[0] == 'x')
12576 dimension = PARSE_X;
12577 else if (name[0] == 'y')
12578 dimension = PARSE_Y;
12579 else if (name[0] == 'w')
12580 dimension = PARSE_WIDTH;
12581 else if (name[0] == 'h')
12582 dimension = PARSE_HEIGHT;
12583 else if (name[0] == 'a' && name[7] == 'x')
12584 dimension = PARSE_ANCHOR_X;
12585 else if (name[0] == 'a' && name[7] == 'y')
12586 dimension = PARSE_ANCHOR_Y;
12590 units = parse_units (actor, dimension, node);
12592 /* convert back to pixels: all properties are pixel-based */
12593 g_value_init (value, G_TYPE_FLOAT);
12594 g_value_set_float (value, units);
12598 else if (strcmp (name, "rotation") == 0)
12600 RotationInfo *info;
12602 info = g_slice_new0 (RotationInfo);
12603 retval = parse_rotation (actor, node, info);
12607 g_value_init (value, G_TYPE_POINTER);
12608 g_value_set_pointer (value, info);
12611 g_slice_free (RotationInfo, info);
12613 else if (strcmp (name, "behaviours") == 0)
12617 #ifdef CLUTTER_ENABLE_DEBUG
12618 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12619 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12620 "and it should not be used in newly "
12621 "written ClutterScript definitions.");
12624 l = parse_behaviours (script, actor, node);
12626 g_value_init (value, G_TYPE_POINTER);
12627 g_value_set_pointer (value, l);
12631 else if (strcmp (name, "actions") == 0 ||
12632 strcmp (name, "constraints") == 0 ||
12633 strcmp (name, "effects") == 0)
12637 l = parse_actor_metas (script, actor, node);
12639 g_value_init (value, G_TYPE_POINTER);
12640 g_value_set_pointer (value, l);
12649 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12650 ClutterScript *script,
12652 const GValue *value)
12654 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12656 #ifdef CLUTTER_ENABLE_DEBUG
12657 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12659 gchar *tmp = g_strdup_value_contents (value);
12661 CLUTTER_NOTE (SCRIPT,
12662 "in ClutterActor::set_custom_property('%s') = %s",
12668 #endif /* CLUTTER_ENABLE_DEBUG */
12670 if (strcmp (name, "rotation") == 0)
12672 RotationInfo *info;
12674 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12677 info = g_value_get_pointer (value);
12679 clutter_actor_set_rotation (actor,
12680 info->axis, info->angle,
12685 g_slice_free (RotationInfo, info);
12690 if (strcmp (name, "behaviours") == 0)
12692 GSList *behaviours, *l;
12694 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12697 behaviours = g_value_get_pointer (value);
12698 for (l = behaviours; l != NULL; l = l->next)
12700 ClutterBehaviour *behaviour = l->data;
12702 clutter_behaviour_apply (behaviour, actor);
12705 g_slist_free (behaviours);
12710 if (strcmp (name, "actions") == 0 ||
12711 strcmp (name, "constraints") == 0 ||
12712 strcmp (name, "effects") == 0)
12716 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12719 metas = g_value_get_pointer (value);
12720 for (l = metas; l != NULL; l = l->next)
12722 if (name[0] == 'a')
12723 clutter_actor_add_action (actor, l->data);
12725 if (name[0] == 'c')
12726 clutter_actor_add_constraint (actor, l->data);
12728 if (name[0] == 'e')
12729 clutter_actor_add_effect (actor, l->data);
12732 g_slist_free (metas);
12737 g_object_set_property (G_OBJECT (scriptable), name, value);
12741 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12743 iface->parse_custom_node = clutter_actor_parse_custom_node;
12744 iface->set_custom_property = clutter_actor_set_custom_property;
12747 static ClutterActorMeta *
12748 get_meta_from_animation_property (ClutterActor *actor,
12752 ClutterActorPrivate *priv = actor->priv;
12753 ClutterActorMeta *meta = NULL;
12756 /* if this is not a special property, fall through */
12757 if (name[0] != '@')
12760 /* detect the properties named using the following spec:
12762 * @<section>.<meta-name>.<property-name>
12764 * where <section> can be one of the following:
12770 * and <meta-name> is the name set on a specific ActorMeta
12773 tokens = g_strsplit (name + 1, ".", -1);
12774 if (tokens == NULL || g_strv_length (tokens) != 3)
12776 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12778 g_strfreev (tokens);
12782 if (strcmp (tokens[0], "actions") == 0)
12783 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12785 if (strcmp (tokens[0], "constraints") == 0)
12786 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12788 if (strcmp (tokens[0], "effects") == 0)
12789 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12791 if (name_p != NULL)
12792 *name_p = g_strdup (tokens[2]);
12794 CLUTTER_NOTE (ANIMATION,
12795 "Looking for property '%s' of object '%s' in section '%s'",
12800 g_strfreev (tokens);
12805 static GParamSpec *
12806 clutter_actor_find_property (ClutterAnimatable *animatable,
12807 const gchar *property_name)
12809 ClutterActorMeta *meta = NULL;
12810 GObjectClass *klass = NULL;
12811 GParamSpec *pspec = NULL;
12812 gchar *p_name = NULL;
12814 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12820 klass = G_OBJECT_GET_CLASS (meta);
12822 pspec = g_object_class_find_property (klass, p_name);
12826 klass = G_OBJECT_GET_CLASS (animatable);
12828 pspec = g_object_class_find_property (klass, property_name);
12837 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12838 const gchar *property_name,
12841 ClutterActorMeta *meta = NULL;
12842 gchar *p_name = NULL;
12844 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12849 g_object_get_property (G_OBJECT (meta), p_name, initial);
12851 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12857 * clutter_actor_set_animatable_property:
12858 * @actor: a #ClutterActor
12859 * @prop_id: the paramspec id
12860 * @value: the value to set
12861 * @pspec: the paramspec
12863 * Sets values of animatable properties.
12865 * This is a variant of clutter_actor_set_property() that gets called
12866 * by the #ClutterAnimatable implementation of #ClutterActor for the
12867 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12870 * Unlike the implementation of #GObjectClass.set_property(), this
12871 * function will not update the interval if a transition involving an
12872 * animatable property is in progress - this avoids cycles with the
12873 * transition API calling the public API.
12876 clutter_actor_set_animatable_property (ClutterActor *actor,
12878 const GValue *value,
12884 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12888 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12892 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12896 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12900 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12904 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12907 case PROP_BACKGROUND_COLOR:
12908 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12912 clutter_actor_set_scale_factor_internal (actor,
12913 g_value_get_double (value),
12918 clutter_actor_set_scale_factor_internal (actor,
12919 g_value_get_double (value),
12923 case PROP_ROTATION_ANGLE_X:
12924 clutter_actor_set_rotation_angle_internal (actor,
12926 g_value_get_double (value));
12929 case PROP_ROTATION_ANGLE_Y:
12930 clutter_actor_set_rotation_angle_internal (actor,
12932 g_value_get_double (value));
12935 case PROP_ROTATION_ANGLE_Z:
12936 clutter_actor_set_rotation_angle_internal (actor,
12938 g_value_get_double (value));
12942 g_object_set_property (G_OBJECT (actor), pspec->name, value);
12948 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12949 const gchar *property_name,
12950 const GValue *final)
12952 ClutterActor *actor = CLUTTER_ACTOR (animatable);
12953 ClutterActorMeta *meta = NULL;
12954 gchar *p_name = NULL;
12956 meta = get_meta_from_animation_property (actor,
12960 g_object_set_property (G_OBJECT (meta), p_name, final);
12963 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12966 pspec = g_object_class_find_property (obj_class, property_name);
12968 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12970 /* XXX - I'm going to the special hell for this */
12971 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12974 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
12981 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12983 iface->find_property = clutter_actor_find_property;
12984 iface->get_initial_state = clutter_actor_get_initial_state;
12985 iface->set_final_state = clutter_actor_set_final_state;
12989 * clutter_actor_transform_stage_point:
12990 * @self: A #ClutterActor
12991 * @x: (in): x screen coordinate of the point to unproject
12992 * @y: (in): y screen coordinate of the point to unproject
12993 * @x_out: (out): return location for the unprojected x coordinance
12994 * @y_out: (out): return location for the unprojected y coordinance
12996 * This function translates screen coordinates (@x, @y) to
12997 * coordinates relative to the actor. For example, it can be used to translate
12998 * screen events from global screen coordinates into actor-local coordinates.
13000 * The conversion can fail, notably if the transform stack results in the
13001 * actor being projected on the screen as a mere line.
13003 * The conversion should not be expected to be pixel-perfect due to the
13004 * nature of the operation. In general the error grows when the skewing
13005 * of the actor rectangle on screen increases.
13007 * <note><para>This function can be computationally intensive.</para></note>
13009 * <note><para>This function only works when the allocation is up-to-date,
13010 * i.e. inside of paint().</para></note>
13012 * Return value: %TRUE if conversion was successful.
13017 clutter_actor_transform_stage_point (ClutterActor *self,
13023 ClutterVertex v[4];
13026 int du, dv, xi, yi;
13028 float xf, yf, wf, det;
13029 ClutterActorPrivate *priv;
13031 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13035 /* This implementation is based on the quad -> quad projection algorithm
13036 * described by Paul Heckbert in:
13038 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13040 * and the sample implementation at:
13042 * http://www.cs.cmu.edu/~ph/src/texfund/
13044 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13045 * quad to rectangle only, which significantly simplifies things; the
13046 * function calls have been unrolled, and most of the math is done in fixed
13050 clutter_actor_get_abs_allocation_vertices (self, v);
13052 /* Keeping these as ints simplifies the multiplication (no significant
13053 * loss of precision here).
13055 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13056 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13061 #define UX2FP(x) (x)
13062 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13064 /* First, find mapping from unit uv square to xy quadrilateral; this
13065 * equivalent to the pmap_square_quad() functions in the sample
13066 * implementation, which we can simplify, since our target is always
13069 px = v[0].x - v[1].x + v[3].x - v[2].x;
13070 py = v[0].y - v[1].y + v[3].y - v[2].y;
13074 /* affine transform */
13075 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13076 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13077 RQ[2][0] = UX2FP (v[0].x);
13078 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13079 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13080 RQ[2][1] = UX2FP (v[0].y);
13087 /* projective transform */
13088 double dx1, dx2, dy1, dy2, del;
13090 dx1 = UX2FP (v[1].x - v[3].x);
13091 dx2 = UX2FP (v[2].x - v[3].x);
13092 dy1 = UX2FP (v[1].y - v[3].y);
13093 dy2 = UX2FP (v[2].y - v[3].y);
13095 del = DET2FP (dx1, dx2, dy1, dy2);
13100 * The division here needs to be done in floating point for
13101 * precisions reasons.
13103 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13104 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13105 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13107 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13108 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13109 RQ[2][0] = UX2FP (v[0].x);
13110 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13111 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13112 RQ[2][1] = UX2FP (v[0].y);
13116 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13117 * square. Since our rectangle is based at 0,0 we only need to scale.
13127 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13130 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13131 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13132 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13133 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13134 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13135 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13136 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13137 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13138 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13141 * Check the resulting matrix is OK.
13143 det = (RQ[0][0] * ST[0][0])
13144 + (RQ[0][1] * ST[0][1])
13145 + (RQ[0][2] * ST[0][2]);
13150 * Now transform our point with the ST matrix; the notional w
13151 * coordinate is 1, hence the last part is simply added.
13156 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13157 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13158 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13176 static ClutterGeometry*
13177 clutter_geometry_copy (const ClutterGeometry *geometry)
13179 return g_slice_dup (ClutterGeometry, geometry);
13183 clutter_geometry_free (ClutterGeometry *geometry)
13185 if (G_LIKELY (geometry != NULL))
13186 g_slice_free (ClutterGeometry, geometry);
13190 * clutter_geometry_union:
13191 * @geometry_a: a #ClutterGeometry
13192 * @geometry_b: another #ClutterGeometry
13193 * @result: (out): location to store the result
13195 * Find the union of two rectangles represented as #ClutterGeometry.
13200 clutter_geometry_union (const ClutterGeometry *geometry_a,
13201 const ClutterGeometry *geometry_b,
13202 ClutterGeometry *result)
13204 /* We don't try to handle rectangles that can't be represented
13205 * as a signed integer box */
13206 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13207 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13208 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13209 geometry_b->x + (gint)geometry_b->width);
13210 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13211 geometry_b->y + (gint)geometry_b->height);
13214 result->width = x_2 - x_1;
13215 result->height = y_2 - y_1;
13219 * clutter_geometry_intersects:
13220 * @geometry0: The first geometry to test
13221 * @geometry1: The second geometry to test
13223 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13224 * they do else %FALSE.
13226 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13232 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13233 const ClutterGeometry *geometry1)
13235 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13236 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13237 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13238 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13245 clutter_geometry_progress (const GValue *a,
13250 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13251 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13252 ClutterGeometry res = { 0, };
13253 gint a_width = a_geom->width;
13254 gint b_width = b_geom->width;
13255 gint a_height = a_geom->height;
13256 gint b_height = b_geom->height;
13258 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13259 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13261 res.width = a_width + (b_width - a_width) * progress;
13262 res.height = a_height + (b_height - a_height) * progress;
13264 g_value_set_boxed (retval, &res);
13269 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13270 clutter_geometry_copy,
13271 clutter_geometry_free,
13272 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13279 * clutter_vertex_new:
13284 * Creates a new #ClutterVertex for the point in 3D space
13285 * identified by the 3 coordinates @x, @y, @z
13287 * Return value: the newly allocate #ClutterVertex. Use
13288 * clutter_vertex_free() to free the resources
13293 clutter_vertex_new (gfloat x,
13297 ClutterVertex *vertex;
13299 vertex = g_slice_new (ClutterVertex);
13300 clutter_vertex_init (vertex, x, y, z);
13306 * clutter_vertex_init:
13307 * @vertex: a #ClutterVertex
13312 * Initializes @vertex with the given coordinates.
13317 clutter_vertex_init (ClutterVertex *vertex,
13322 g_return_if_fail (vertex != NULL);
13330 * clutter_vertex_copy:
13331 * @vertex: a #ClutterVertex
13335 * Return value: a newly allocated copy of #ClutterVertex. Use
13336 * clutter_vertex_free() to free the allocated resources
13341 clutter_vertex_copy (const ClutterVertex *vertex)
13343 if (G_LIKELY (vertex != NULL))
13344 return g_slice_dup (ClutterVertex, vertex);
13350 * clutter_vertex_free:
13351 * @vertex: a #ClutterVertex
13353 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13358 clutter_vertex_free (ClutterVertex *vertex)
13360 if (G_UNLIKELY (vertex != NULL))
13361 g_slice_free (ClutterVertex, vertex);
13365 * clutter_vertex_equal:
13366 * @vertex_a: a #ClutterVertex
13367 * @vertex_b: a #ClutterVertex
13369 * Compares @vertex_a and @vertex_b for equality
13371 * Return value: %TRUE if the passed #ClutterVertex are equal
13376 clutter_vertex_equal (const ClutterVertex *vertex_a,
13377 const ClutterVertex *vertex_b)
13379 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13381 if (vertex_a == vertex_b)
13384 return vertex_a->x == vertex_b->x &&
13385 vertex_a->y == vertex_b->y &&
13386 vertex_a->z == vertex_b->z;
13390 clutter_vertex_progress (const GValue *a,
13395 const ClutterVertex *av = g_value_get_boxed (a);
13396 const ClutterVertex *bv = g_value_get_boxed (b);
13397 ClutterVertex res = { 0, };
13399 res.x = av->x + (bv->x - av->x) * progress;
13400 res.y = av->y + (bv->y - av->y) * progress;
13401 res.z = av->z + (bv->z - av->z) * progress;
13403 g_value_set_boxed (retval, &res);
13408 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13409 clutter_vertex_copy,
13410 clutter_vertex_free,
13411 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13414 * clutter_actor_is_rotated:
13415 * @self: a #ClutterActor
13417 * Checks whether any rotation is applied to the actor.
13419 * Return value: %TRUE if the actor is rotated.
13424 clutter_actor_is_rotated (ClutterActor *self)
13426 const ClutterTransformInfo *info;
13428 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13430 info = _clutter_actor_get_transform_info_or_defaults (self);
13432 if (info->rx_angle || info->ry_angle || info->rz_angle)
13439 * clutter_actor_is_scaled:
13440 * @self: a #ClutterActor
13442 * Checks whether the actor is scaled in either dimension.
13444 * Return value: %TRUE if the actor is scaled.
13449 clutter_actor_is_scaled (ClutterActor *self)
13451 const ClutterTransformInfo *info;
13453 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13455 info = _clutter_actor_get_transform_info_or_defaults (self);
13457 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13464 _clutter_actor_get_stage_internal (ClutterActor *actor)
13466 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13467 actor = actor->priv->parent;
13473 * clutter_actor_get_stage:
13474 * @actor: a #ClutterActor
13476 * Retrieves the #ClutterStage where @actor is contained.
13478 * Return value: (transfer none) (type Clutter.Stage): the stage
13479 * containing the actor, or %NULL
13484 clutter_actor_get_stage (ClutterActor *actor)
13486 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13488 return _clutter_actor_get_stage_internal (actor);
13492 * clutter_actor_allocate_available_size:
13493 * @self: a #ClutterActor
13494 * @x: the actor's X coordinate
13495 * @y: the actor's Y coordinate
13496 * @available_width: the maximum available width, or -1 to use the
13497 * actor's natural width
13498 * @available_height: the maximum available height, or -1 to use the
13499 * actor's natural height
13500 * @flags: flags controlling the allocation
13502 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13503 * preferred size, but limiting it to the maximum available width
13504 * and height provided.
13506 * This function will do the right thing when dealing with the
13507 * actor's request mode.
13509 * The implementation of this function is equivalent to:
13512 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13514 * clutter_actor_get_preferred_width (self, available_height,
13516 * &natural_width);
13517 * width = CLAMP (natural_width, min_width, available_width);
13519 * clutter_actor_get_preferred_height (self, width,
13521 * &natural_height);
13522 * height = CLAMP (natural_height, min_height, available_height);
13526 * clutter_actor_get_preferred_height (self, available_width,
13528 * &natural_height);
13529 * height = CLAMP (natural_height, min_height, available_height);
13531 * clutter_actor_get_preferred_width (self, height,
13533 * &natural_width);
13534 * width = CLAMP (natural_width, min_width, available_width);
13537 * box.x1 = x; box.y1 = y;
13538 * box.x2 = box.x1 + available_width;
13539 * box.y2 = box.y1 + available_height;
13540 * clutter_actor_allocate (self, &box, flags);
13543 * This function can be used by fluid layout managers to allocate
13544 * an actor's preferred size without making it bigger than the area
13545 * available for the container.
13550 clutter_actor_allocate_available_size (ClutterActor *self,
13553 gfloat available_width,
13554 gfloat available_height,
13555 ClutterAllocationFlags flags)
13557 ClutterActorPrivate *priv;
13558 gfloat width, height;
13559 gfloat min_width, min_height;
13560 gfloat natural_width, natural_height;
13561 ClutterActorBox box;
13563 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13567 width = height = 0.0;
13569 switch (priv->request_mode)
13571 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13572 clutter_actor_get_preferred_width (self, available_height,
13575 width = CLAMP (natural_width, min_width, available_width);
13577 clutter_actor_get_preferred_height (self, width,
13580 height = CLAMP (natural_height, min_height, available_height);
13583 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13584 clutter_actor_get_preferred_height (self, available_width,
13587 height = CLAMP (natural_height, min_height, available_height);
13589 clutter_actor_get_preferred_width (self, height,
13592 width = CLAMP (natural_width, min_width, available_width);
13599 box.x2 = box.x1 + width;
13600 box.y2 = box.y1 + height;
13601 clutter_actor_allocate (self, &box, flags);
13605 * clutter_actor_allocate_preferred_size:
13606 * @self: a #ClutterActor
13607 * @flags: flags controlling the allocation
13609 * Allocates the natural size of @self.
13611 * This function is a utility call for #ClutterActor implementations
13612 * that allocates the actor's preferred natural size. It can be used
13613 * by fixed layout managers (like #ClutterGroup or so called
13614 * 'composite actors') inside the ClutterActor::allocate
13615 * implementation to give each child exactly how much space it
13618 * This function is not meant to be used by applications. It is also
13619 * not meant to be used outside the implementation of the
13620 * ClutterActor::allocate virtual function.
13625 clutter_actor_allocate_preferred_size (ClutterActor *self,
13626 ClutterAllocationFlags flags)
13628 gfloat actor_x, actor_y;
13629 gfloat natural_width, natural_height;
13630 ClutterActorBox actor_box;
13632 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13634 actor_x = clutter_actor_get_x (self);
13635 actor_y = clutter_actor_get_y (self);
13637 clutter_actor_get_preferred_size (self,
13642 actor_box.x1 = actor_x;
13643 actor_box.y1 = actor_y;
13644 actor_box.x2 = actor_box.x1 + natural_width;
13645 actor_box.y2 = actor_box.y1 + natural_height;
13647 clutter_actor_allocate (self, &actor_box, flags);
13651 * clutter_actor_allocate_align_fill:
13652 * @self: a #ClutterActor
13653 * @box: a #ClutterActorBox, containing the available width and height
13654 * @x_align: the horizontal alignment, between 0 and 1
13655 * @y_align: the vertical alignment, between 0 and 1
13656 * @x_fill: whether the actor should fill horizontally
13657 * @y_fill: whether the actor should fill vertically
13658 * @flags: allocation flags to be passed to clutter_actor_allocate()
13660 * Allocates @self by taking into consideration the available allocation
13661 * area; an alignment factor on either axis; and whether the actor should
13662 * fill the allocation on either axis.
13664 * The @box should contain the available allocation width and height;
13665 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13666 * allocation will be offset by their value.
13668 * This function takes into consideration the geometry request specified by
13669 * the #ClutterActor:request-mode property, and the text direction.
13671 * This function is useful for fluid layout managers, like #ClutterBinLayout
13672 * or #ClutterTableLayout
13677 clutter_actor_allocate_align_fill (ClutterActor *self,
13678 const ClutterActorBox *box,
13683 ClutterAllocationFlags flags)
13685 ClutterActorPrivate *priv;
13686 ClutterActorBox allocation = { 0, };
13687 gfloat x_offset, y_offset;
13688 gfloat available_width, available_height;
13689 gfloat child_width, child_height;
13691 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13692 g_return_if_fail (box != NULL);
13693 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13694 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13698 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13699 clutter_actor_box_get_size (box, &available_width, &available_height);
13701 if (available_width < 0)
13702 available_width = 0;
13704 if (available_height < 0)
13705 available_height = 0;
13709 allocation.x1 = x_offset;
13710 allocation.x2 = allocation.x1 + available_width;
13715 allocation.y1 = y_offset;
13716 allocation.y2 = allocation.y1 + available_height;
13719 /* if we are filling horizontally and vertically then we're done */
13720 if (x_fill && y_fill)
13723 child_width = child_height = 0.0f;
13725 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13727 gfloat min_width, natural_width;
13728 gfloat min_height, natural_height;
13730 clutter_actor_get_preferred_width (self, available_height,
13734 child_width = CLAMP (natural_width, min_width, available_width);
13738 clutter_actor_get_preferred_height (self, child_width,
13742 child_height = CLAMP (natural_height, min_height, available_height);
13747 gfloat min_width, natural_width;
13748 gfloat min_height, natural_height;
13750 clutter_actor_get_preferred_height (self, available_width,
13754 child_height = CLAMP (natural_height, min_height, available_height);
13758 clutter_actor_get_preferred_width (self, child_height,
13762 child_width = CLAMP (natural_width, min_width, available_width);
13766 /* invert the horizontal alignment for RTL languages */
13767 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13768 x_align = 1.0 - x_align;
13772 allocation.x1 = x_offset
13773 + ((available_width - child_width) * x_align);
13774 allocation.x2 = allocation.x1 + child_width;
13779 allocation.y1 = y_offset
13780 + ((available_height - child_height) * y_align);
13781 allocation.y2 = allocation.y1 + child_height;
13785 clutter_actor_box_clamp_to_pixel (&allocation);
13786 clutter_actor_allocate (self, &allocation, flags);
13790 * clutter_actor_grab_key_focus:
13791 * @self: a #ClutterActor
13793 * Sets the key focus of the #ClutterStage including @self
13794 * to this #ClutterActor.
13799 clutter_actor_grab_key_focus (ClutterActor *self)
13801 ClutterActor *stage;
13803 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13805 stage = _clutter_actor_get_stage_internal (self);
13807 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13811 * clutter_actor_get_pango_context:
13812 * @self: a #ClutterActor
13814 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13815 * is already configured using the appropriate font map, resolution
13816 * and font options.
13818 * Unlike clutter_actor_create_pango_context(), this context is owend
13819 * by the #ClutterActor and it will be updated each time the options
13820 * stored by the #ClutterBackend change.
13822 * You can use the returned #PangoContext to create a #PangoLayout
13823 * and render text using cogl_pango_render_layout() to reuse the
13824 * glyphs cache also used by Clutter.
13826 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13827 * The returned #PangoContext is owned by the actor and should not be
13828 * unreferenced by the application code
13833 clutter_actor_get_pango_context (ClutterActor *self)
13835 ClutterActorPrivate *priv;
13837 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13841 if (priv->pango_context != NULL)
13842 return priv->pango_context;
13844 priv->pango_context = _clutter_context_get_pango_context ();
13845 g_object_ref (priv->pango_context);
13847 return priv->pango_context;
13851 * clutter_actor_create_pango_context:
13852 * @self: a #ClutterActor
13854 * Creates a #PangoContext for the given actor. The #PangoContext
13855 * is already configured using the appropriate font map, resolution
13856 * and font options.
13858 * See also clutter_actor_get_pango_context().
13860 * Return value: (transfer full): the newly created #PangoContext.
13861 * Use g_object_unref() on the returned value to deallocate its
13867 clutter_actor_create_pango_context (ClutterActor *self)
13869 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13871 return _clutter_context_create_pango_context ();
13875 * clutter_actor_create_pango_layout:
13876 * @self: a #ClutterActor
13877 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13879 * Creates a new #PangoLayout from the same #PangoContext used
13880 * by the #ClutterActor. The #PangoLayout is already configured
13881 * with the font map, resolution and font options, and the
13884 * If you want to keep around a #PangoLayout created by this
13885 * function you will have to connect to the #ClutterBackend::font-changed
13886 * and #ClutterBackend::resolution-changed signals, and call
13887 * pango_layout_context_changed() in response to them.
13889 * Return value: (transfer full): the newly created #PangoLayout.
13890 * Use g_object_unref() when done
13895 clutter_actor_create_pango_layout (ClutterActor *self,
13898 PangoContext *context;
13899 PangoLayout *layout;
13901 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13903 context = clutter_actor_get_pango_context (self);
13904 layout = pango_layout_new (context);
13907 pango_layout_set_text (layout, text, -1);
13912 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13913 * ClutterOffscreenEffect.
13916 _clutter_actor_set_opacity_override (ClutterActor *self,
13919 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13921 self->priv->opacity_override = opacity;
13925 _clutter_actor_get_opacity_override (ClutterActor *self)
13927 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13929 return self->priv->opacity_override;
13932 /* Allows you to disable applying the actors model view transform during
13933 * a paint. Used by ClutterClone. */
13935 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13938 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13940 self->priv->enable_model_view_transform = enable;
13944 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13947 ClutterActorPrivate *priv;
13949 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13953 priv->enable_paint_unmapped = enable;
13955 if (priv->enable_paint_unmapped)
13957 /* Make sure that the parents of the widget are realized first;
13958 * otherwise checks in clutter_actor_update_map_state() will
13961 clutter_actor_realize (self);
13963 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13967 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13972 clutter_anchor_coord_get_units (ClutterActor *self,
13973 const AnchorCoord *coord,
13978 if (coord->is_fractional)
13980 gfloat actor_width, actor_height;
13982 clutter_actor_get_size (self, &actor_width, &actor_height);
13985 *x = actor_width * coord->v.fraction.x;
13988 *y = actor_height * coord->v.fraction.y;
13996 *x = coord->v.units.x;
13999 *y = coord->v.units.y;
14002 *z = coord->v.units.z;
14007 clutter_anchor_coord_set_units (AnchorCoord *coord,
14012 coord->is_fractional = FALSE;
14013 coord->v.units.x = x;
14014 coord->v.units.y = y;
14015 coord->v.units.z = z;
14018 static ClutterGravity
14019 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14021 if (coord->is_fractional)
14023 if (coord->v.fraction.x == 0.0)
14025 if (coord->v.fraction.y == 0.0)
14026 return CLUTTER_GRAVITY_NORTH_WEST;
14027 else if (coord->v.fraction.y == 0.5)
14028 return CLUTTER_GRAVITY_WEST;
14029 else if (coord->v.fraction.y == 1.0)
14030 return CLUTTER_GRAVITY_SOUTH_WEST;
14032 return CLUTTER_GRAVITY_NONE;
14034 else if (coord->v.fraction.x == 0.5)
14036 if (coord->v.fraction.y == 0.0)
14037 return CLUTTER_GRAVITY_NORTH;
14038 else if (coord->v.fraction.y == 0.5)
14039 return CLUTTER_GRAVITY_CENTER;
14040 else if (coord->v.fraction.y == 1.0)
14041 return CLUTTER_GRAVITY_SOUTH;
14043 return CLUTTER_GRAVITY_NONE;
14045 else if (coord->v.fraction.x == 1.0)
14047 if (coord->v.fraction.y == 0.0)
14048 return CLUTTER_GRAVITY_NORTH_EAST;
14049 else if (coord->v.fraction.y == 0.5)
14050 return CLUTTER_GRAVITY_EAST;
14051 else if (coord->v.fraction.y == 1.0)
14052 return CLUTTER_GRAVITY_SOUTH_EAST;
14054 return CLUTTER_GRAVITY_NONE;
14057 return CLUTTER_GRAVITY_NONE;
14060 return CLUTTER_GRAVITY_NONE;
14064 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14065 ClutterGravity gravity)
14069 case CLUTTER_GRAVITY_NORTH:
14070 coord->v.fraction.x = 0.5;
14071 coord->v.fraction.y = 0.0;
14074 case CLUTTER_GRAVITY_NORTH_EAST:
14075 coord->v.fraction.x = 1.0;
14076 coord->v.fraction.y = 0.0;
14079 case CLUTTER_GRAVITY_EAST:
14080 coord->v.fraction.x = 1.0;
14081 coord->v.fraction.y = 0.5;
14084 case CLUTTER_GRAVITY_SOUTH_EAST:
14085 coord->v.fraction.x = 1.0;
14086 coord->v.fraction.y = 1.0;
14089 case CLUTTER_GRAVITY_SOUTH:
14090 coord->v.fraction.x = 0.5;
14091 coord->v.fraction.y = 1.0;
14094 case CLUTTER_GRAVITY_SOUTH_WEST:
14095 coord->v.fraction.x = 0.0;
14096 coord->v.fraction.y = 1.0;
14099 case CLUTTER_GRAVITY_WEST:
14100 coord->v.fraction.x = 0.0;
14101 coord->v.fraction.y = 0.5;
14104 case CLUTTER_GRAVITY_NORTH_WEST:
14105 coord->v.fraction.x = 0.0;
14106 coord->v.fraction.y = 0.0;
14109 case CLUTTER_GRAVITY_CENTER:
14110 coord->v.fraction.x = 0.5;
14111 coord->v.fraction.y = 0.5;
14115 coord->v.fraction.x = 0.0;
14116 coord->v.fraction.y = 0.0;
14120 coord->is_fractional = TRUE;
14124 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14126 if (coord->is_fractional)
14127 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14129 return (coord->v.units.x == 0.0
14130 && coord->v.units.y == 0.0
14131 && coord->v.units.z == 0.0);
14135 * clutter_actor_get_flags:
14136 * @self: a #ClutterActor
14138 * Retrieves the flags set on @self
14140 * Return value: a bitwise or of #ClutterActorFlags or 0
14145 clutter_actor_get_flags (ClutterActor *self)
14147 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14149 return self->flags;
14153 * clutter_actor_set_flags:
14154 * @self: a #ClutterActor
14155 * @flags: the flags to set
14157 * Sets @flags on @self
14159 * This function will emit notifications for the changed properties
14164 clutter_actor_set_flags (ClutterActor *self,
14165 ClutterActorFlags flags)
14167 ClutterActorFlags old_flags;
14169 gboolean was_reactive_set, reactive_set;
14170 gboolean was_realized_set, realized_set;
14171 gboolean was_mapped_set, mapped_set;
14172 gboolean was_visible_set, visible_set;
14174 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14176 if (self->flags == flags)
14179 obj = G_OBJECT (self);
14180 g_object_ref (obj);
14181 g_object_freeze_notify (obj);
14183 old_flags = self->flags;
14185 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14186 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14187 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14188 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14190 self->flags |= flags;
14192 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14193 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14194 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14195 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14197 if (reactive_set != was_reactive_set)
14198 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14200 if (realized_set != was_realized_set)
14201 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14203 if (mapped_set != was_mapped_set)
14204 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14206 if (visible_set != was_visible_set)
14207 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14209 g_object_thaw_notify (obj);
14210 g_object_unref (obj);
14214 * clutter_actor_unset_flags:
14215 * @self: a #ClutterActor
14216 * @flags: the flags to unset
14218 * Unsets @flags on @self
14220 * This function will emit notifications for the changed properties
14225 clutter_actor_unset_flags (ClutterActor *self,
14226 ClutterActorFlags flags)
14228 ClutterActorFlags old_flags;
14230 gboolean was_reactive_set, reactive_set;
14231 gboolean was_realized_set, realized_set;
14232 gboolean was_mapped_set, mapped_set;
14233 gboolean was_visible_set, visible_set;
14235 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14237 obj = G_OBJECT (self);
14238 g_object_freeze_notify (obj);
14240 old_flags = self->flags;
14242 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14243 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14244 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14245 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14247 self->flags &= ~flags;
14249 if (self->flags == old_flags)
14252 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14253 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14254 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14255 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14257 if (reactive_set != was_reactive_set)
14258 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14260 if (realized_set != was_realized_set)
14261 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14263 if (mapped_set != was_mapped_set)
14264 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14266 if (visible_set != was_visible_set)
14267 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14269 g_object_thaw_notify (obj);
14273 * clutter_actor_get_transformation_matrix:
14274 * @self: a #ClutterActor
14275 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14277 * Retrieves the transformations applied to @self relative to its
14283 clutter_actor_get_transformation_matrix (ClutterActor *self,
14284 CoglMatrix *matrix)
14286 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14288 cogl_matrix_init_identity (matrix);
14290 _clutter_actor_apply_modelview_transform (self, matrix);
14294 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14295 gboolean is_in_clone_paint)
14297 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14298 self->priv->in_clone_paint = is_in_clone_paint;
14302 * clutter_actor_is_in_clone_paint:
14303 * @self: a #ClutterActor
14305 * Checks whether @self is being currently painted by a #ClutterClone
14307 * This function is useful only inside the ::paint virtual function
14308 * implementations or within handlers for the #ClutterActor::paint
14311 * This function should not be used by applications
14313 * Return value: %TRUE if the #ClutterActor is currently being painted
14314 * by a #ClutterClone, and %FALSE otherwise
14319 clutter_actor_is_in_clone_paint (ClutterActor *self)
14321 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14323 return self->priv->in_clone_paint;
14327 set_direction_recursive (ClutterActor *actor,
14328 gpointer user_data)
14330 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14332 clutter_actor_set_text_direction (actor, text_dir);
14338 * clutter_actor_set_text_direction:
14339 * @self: a #ClutterActor
14340 * @text_dir: the text direction for @self
14342 * Sets the #ClutterTextDirection for an actor
14344 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14346 * If @self implements #ClutterContainer then this function will recurse
14347 * inside all the children of @self (including the internal ones).
14349 * Composite actors not implementing #ClutterContainer, or actors requiring
14350 * special handling when the text direction changes, should connect to
14351 * the #GObject::notify signal for the #ClutterActor:text-direction property
14356 clutter_actor_set_text_direction (ClutterActor *self,
14357 ClutterTextDirection text_dir)
14359 ClutterActorPrivate *priv;
14361 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14362 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14366 if (priv->text_direction != text_dir)
14368 priv->text_direction = text_dir;
14370 /* we need to emit the notify::text-direction first, so that
14371 * the sub-classes can catch that and do specific handling of
14372 * the text direction; see clutter_text_direction_changed_cb()
14373 * inside clutter-text.c
14375 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14377 _clutter_actor_foreach_child (self, set_direction_recursive,
14378 GINT_TO_POINTER (text_dir));
14380 clutter_actor_queue_relayout (self);
14385 _clutter_actor_set_has_pointer (ClutterActor *self,
14386 gboolean has_pointer)
14388 ClutterActorPrivate *priv = self->priv;
14390 if (priv->has_pointer != has_pointer)
14392 priv->has_pointer = has_pointer;
14394 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14399 * clutter_actor_get_text_direction:
14400 * @self: a #ClutterActor
14402 * Retrieves the value set using clutter_actor_set_text_direction()
14404 * If no text direction has been previously set, the default text
14405 * direction, as returned by clutter_get_default_text_direction(), will
14406 * be returned instead
14408 * Return value: the #ClutterTextDirection for the actor
14412 ClutterTextDirection
14413 clutter_actor_get_text_direction (ClutterActor *self)
14415 ClutterActorPrivate *priv;
14417 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14418 CLUTTER_TEXT_DIRECTION_LTR);
14422 /* if no direction has been set yet use the default */
14423 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14424 priv->text_direction = clutter_get_default_text_direction ();
14426 return priv->text_direction;
14430 * clutter_actor_push_internal:
14431 * @self: a #ClutterActor
14433 * Should be used by actors implementing the #ClutterContainer and with
14434 * internal children added through clutter_actor_set_parent(), for instance:
14438 * my_actor_init (MyActor *self)
14440 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14442 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14444 * /* calling clutter_actor_set_parent() now will result in
14445 * * the internal flag being set on a child of MyActor
14448 * /* internal child - a background texture */
14449 * self->priv->background_tex = clutter_texture_new ();
14450 * clutter_actor_set_parent (self->priv->background_tex,
14451 * CLUTTER_ACTOR (self));
14453 * /* internal child - a label */
14454 * self->priv->label = clutter_text_new ();
14455 * clutter_actor_set_parent (self->priv->label,
14456 * CLUTTER_ACTOR (self));
14458 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14460 * /* calling clutter_actor_set_parent() now will not result in
14461 * * the internal flag being set on a child of MyActor
14466 * This function will be used by Clutter to toggle an "internal child"
14467 * flag whenever clutter_actor_set_parent() is called; internal children
14468 * are handled differently by Clutter, specifically when destroying their
14471 * Call clutter_actor_pop_internal() when you finished adding internal
14474 * Nested calls to clutter_actor_push_internal() are allowed, but each
14475 * one must by followed by a clutter_actor_pop_internal() call.
14479 * Deprecated: 1.10: All children of an actor are accessible through
14480 * the #ClutterActor API, and #ClutterActor implements the
14481 * #ClutterContainer interface, so this function is only useful
14482 * for legacy containers overriding the default implementation.
14485 clutter_actor_push_internal (ClutterActor *self)
14487 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14489 self->priv->internal_child += 1;
14493 * clutter_actor_pop_internal:
14494 * @self: a #ClutterActor
14496 * Disables the effects of clutter_actor_push_internal().
14500 * Deprecated: 1.10: All children of an actor are accessible through
14501 * the #ClutterActor API. This function is only useful for legacy
14502 * containers overriding the default implementation of the
14503 * #ClutterContainer interface.
14506 clutter_actor_pop_internal (ClutterActor *self)
14508 ClutterActorPrivate *priv;
14510 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14514 if (priv->internal_child == 0)
14516 g_warning ("Mismatched %s: you need to call "
14517 "clutter_actor_push_composite() at least once before "
14518 "calling this function", G_STRFUNC);
14522 priv->internal_child -= 1;
14526 * clutter_actor_has_pointer:
14527 * @self: a #ClutterActor
14529 * Checks whether an actor contains the pointer of a
14530 * #ClutterInputDevice
14532 * Return value: %TRUE if the actor contains the pointer, and
14538 clutter_actor_has_pointer (ClutterActor *self)
14540 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14542 return self->priv->has_pointer;
14545 /* XXX: This is a workaround for not being able to break the ABI of
14546 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14547 * clutter_actor_queue_clipped_redraw() for details.
14549 ClutterPaintVolume *
14550 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14552 return g_object_get_data (G_OBJECT (self),
14553 "-clutter-actor-queue-redraw-clip");
14557 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14558 ClutterPaintVolume *clip)
14560 g_object_set_data (G_OBJECT (self),
14561 "-clutter-actor-queue-redraw-clip",
14566 * clutter_actor_has_allocation:
14567 * @self: a #ClutterActor
14569 * Checks if the actor has an up-to-date allocation assigned to
14570 * it. This means that the actor should have an allocation: it's
14571 * visible and has a parent. It also means that there is no
14572 * outstanding relayout request in progress for the actor or its
14573 * children (There might be other outstanding layout requests in
14574 * progress that will cause the actor to get a new allocation
14575 * when the stage is laid out, however).
14577 * If this function returns %FALSE, then the actor will normally
14578 * be allocated before it is next drawn on the screen.
14580 * Return value: %TRUE if the actor has an up-to-date allocation
14585 clutter_actor_has_allocation (ClutterActor *self)
14587 ClutterActorPrivate *priv;
14589 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14593 return priv->parent != NULL &&
14594 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14595 !priv->needs_allocation;
14599 * clutter_actor_add_action:
14600 * @self: a #ClutterActor
14601 * @action: a #ClutterAction
14603 * Adds @action to the list of actions applied to @self
14605 * A #ClutterAction can only belong to one actor at a time
14607 * The #ClutterActor will hold a reference on @action until either
14608 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14614 clutter_actor_add_action (ClutterActor *self,
14615 ClutterAction *action)
14617 ClutterActorPrivate *priv;
14619 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14620 g_return_if_fail (CLUTTER_IS_ACTION (action));
14624 if (priv->actions == NULL)
14626 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14627 priv->actions->actor = self;
14630 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14632 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14636 * clutter_actor_add_action_with_name:
14637 * @self: a #ClutterActor
14638 * @name: the name to set on the action
14639 * @action: a #ClutterAction
14641 * A convenience function for setting the name of a #ClutterAction
14642 * while adding it to the list of actions applied to @self
14644 * This function is the logical equivalent of:
14647 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14648 * clutter_actor_add_action (self, action);
14654 clutter_actor_add_action_with_name (ClutterActor *self,
14656 ClutterAction *action)
14658 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14659 g_return_if_fail (name != NULL);
14660 g_return_if_fail (CLUTTER_IS_ACTION (action));
14662 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14663 clutter_actor_add_action (self, action);
14667 * clutter_actor_remove_action:
14668 * @self: a #ClutterActor
14669 * @action: a #ClutterAction
14671 * Removes @action from the list of actions applied to @self
14673 * The reference held by @self on the #ClutterAction will be released
14678 clutter_actor_remove_action (ClutterActor *self,
14679 ClutterAction *action)
14681 ClutterActorPrivate *priv;
14683 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14684 g_return_if_fail (CLUTTER_IS_ACTION (action));
14688 if (priv->actions == NULL)
14691 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14693 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14697 * clutter_actor_remove_action_by_name:
14698 * @self: a #ClutterActor
14699 * @name: the name of the action to remove
14701 * Removes the #ClutterAction with the given name from the list
14702 * of actions applied to @self
14707 clutter_actor_remove_action_by_name (ClutterActor *self,
14710 ClutterActorPrivate *priv;
14711 ClutterActorMeta *meta;
14713 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14714 g_return_if_fail (name != NULL);
14718 if (priv->actions == NULL)
14721 meta = _clutter_meta_group_get_meta (priv->actions, name);
14725 _clutter_meta_group_remove_meta (priv->actions, meta);
14727 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14731 * clutter_actor_get_actions:
14732 * @self: a #ClutterActor
14734 * Retrieves the list of actions applied to @self
14736 * Return value: (transfer container) (element-type Clutter.Action): a copy
14737 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14738 * owned by the #ClutterActor. Use g_list_free() to free the resources
14739 * allocated by the returned #GList
14744 clutter_actor_get_actions (ClutterActor *self)
14746 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14748 if (self->priv->actions == NULL)
14751 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14755 * clutter_actor_get_action:
14756 * @self: a #ClutterActor
14757 * @name: the name of the action to retrieve
14759 * Retrieves the #ClutterAction with the given name in the list
14760 * of actions applied to @self
14762 * Return value: (transfer none): a #ClutterAction for the given
14763 * name, or %NULL. The returned #ClutterAction is owned by the
14764 * actor and it should not be unreferenced directly
14769 clutter_actor_get_action (ClutterActor *self,
14772 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14773 g_return_val_if_fail (name != NULL, NULL);
14775 if (self->priv->actions == NULL)
14778 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14782 * clutter_actor_clear_actions:
14783 * @self: a #ClutterActor
14785 * Clears the list of actions applied to @self
14790 clutter_actor_clear_actions (ClutterActor *self)
14792 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14794 if (self->priv->actions == NULL)
14797 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14801 * clutter_actor_add_constraint:
14802 * @self: a #ClutterActor
14803 * @constraint: a #ClutterConstraint
14805 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14808 * The #ClutterActor will hold a reference on the @constraint until
14809 * either clutter_actor_remove_constraint() or
14810 * clutter_actor_clear_constraints() is called.
14815 clutter_actor_add_constraint (ClutterActor *self,
14816 ClutterConstraint *constraint)
14818 ClutterActorPrivate *priv;
14820 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14821 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14825 if (priv->constraints == NULL)
14827 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14828 priv->constraints->actor = self;
14831 _clutter_meta_group_add_meta (priv->constraints,
14832 CLUTTER_ACTOR_META (constraint));
14833 clutter_actor_queue_relayout (self);
14835 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14839 * clutter_actor_add_constraint_with_name:
14840 * @self: a #ClutterActor
14841 * @name: the name to set on the constraint
14842 * @constraint: a #ClutterConstraint
14844 * A convenience function for setting the name of a #ClutterConstraint
14845 * while adding it to the list of constraints applied to @self
14847 * This function is the logical equivalent of:
14850 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14851 * clutter_actor_add_constraint (self, constraint);
14857 clutter_actor_add_constraint_with_name (ClutterActor *self,
14859 ClutterConstraint *constraint)
14861 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14862 g_return_if_fail (name != NULL);
14863 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14865 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14866 clutter_actor_add_constraint (self, constraint);
14870 * clutter_actor_remove_constraint:
14871 * @self: a #ClutterActor
14872 * @constraint: a #ClutterConstraint
14874 * Removes @constraint from the list of constraints applied to @self
14876 * The reference held by @self on the #ClutterConstraint will be released
14881 clutter_actor_remove_constraint (ClutterActor *self,
14882 ClutterConstraint *constraint)
14884 ClutterActorPrivate *priv;
14886 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14887 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14891 if (priv->constraints == NULL)
14894 _clutter_meta_group_remove_meta (priv->constraints,
14895 CLUTTER_ACTOR_META (constraint));
14896 clutter_actor_queue_relayout (self);
14898 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14902 * clutter_actor_remove_constraint_by_name:
14903 * @self: a #ClutterActor
14904 * @name: the name of the constraint to remove
14906 * Removes the #ClutterConstraint with the given name from the list
14907 * of constraints applied to @self
14912 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14915 ClutterActorPrivate *priv;
14916 ClutterActorMeta *meta;
14918 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14919 g_return_if_fail (name != NULL);
14923 if (priv->constraints == NULL)
14926 meta = _clutter_meta_group_get_meta (priv->constraints, name);
14930 _clutter_meta_group_remove_meta (priv->constraints, meta);
14931 clutter_actor_queue_relayout (self);
14935 * clutter_actor_get_constraints:
14936 * @self: a #ClutterActor
14938 * Retrieves the list of constraints applied to @self
14940 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14941 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14942 * owned by the #ClutterActor. Use g_list_free() to free the resources
14943 * allocated by the returned #GList
14948 clutter_actor_get_constraints (ClutterActor *self)
14950 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14952 if (self->priv->constraints == NULL)
14955 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14959 * clutter_actor_get_constraint:
14960 * @self: a #ClutterActor
14961 * @name: the name of the constraint to retrieve
14963 * Retrieves the #ClutterConstraint with the given name in the list
14964 * of constraints applied to @self
14966 * Return value: (transfer none): a #ClutterConstraint for the given
14967 * name, or %NULL. The returned #ClutterConstraint is owned by the
14968 * actor and it should not be unreferenced directly
14972 ClutterConstraint *
14973 clutter_actor_get_constraint (ClutterActor *self,
14976 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14977 g_return_val_if_fail (name != NULL, NULL);
14979 if (self->priv->constraints == NULL)
14982 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14986 * clutter_actor_clear_constraints:
14987 * @self: a #ClutterActor
14989 * Clears the list of constraints applied to @self
14994 clutter_actor_clear_constraints (ClutterActor *self)
14996 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14998 if (self->priv->constraints == NULL)
15001 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15003 clutter_actor_queue_relayout (self);
15007 * clutter_actor_set_clip_to_allocation:
15008 * @self: a #ClutterActor
15009 * @clip_set: %TRUE to apply a clip tracking the allocation
15011 * Sets whether @self should be clipped to the same size as its
15017 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15020 ClutterActorPrivate *priv;
15022 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15024 clip_set = !!clip_set;
15028 if (priv->clip_to_allocation != clip_set)
15030 priv->clip_to_allocation = clip_set;
15032 clutter_actor_queue_redraw (self);
15034 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15039 * clutter_actor_get_clip_to_allocation:
15040 * @self: a #ClutterActor
15042 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15044 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15049 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15051 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15053 return self->priv->clip_to_allocation;
15057 * clutter_actor_add_effect:
15058 * @self: a #ClutterActor
15059 * @effect: a #ClutterEffect
15061 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15063 * The #ClutterActor will hold a reference on the @effect until either
15064 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15070 clutter_actor_add_effect (ClutterActor *self,
15071 ClutterEffect *effect)
15073 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15074 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15076 _clutter_actor_add_effect_internal (self, effect);
15078 clutter_actor_queue_redraw (self);
15080 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15084 * clutter_actor_add_effect_with_name:
15085 * @self: a #ClutterActor
15086 * @name: the name to set on the effect
15087 * @effect: a #ClutterEffect
15089 * A convenience function for setting the name of a #ClutterEffect
15090 * while adding it to the list of effectss applied to @self
15092 * This function is the logical equivalent of:
15095 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15096 * clutter_actor_add_effect (self, effect);
15102 clutter_actor_add_effect_with_name (ClutterActor *self,
15104 ClutterEffect *effect)
15106 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15107 g_return_if_fail (name != NULL);
15108 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15110 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15111 clutter_actor_add_effect (self, effect);
15115 * clutter_actor_remove_effect:
15116 * @self: a #ClutterActor
15117 * @effect: a #ClutterEffect
15119 * Removes @effect from the list of effects applied to @self
15121 * The reference held by @self on the #ClutterEffect will be released
15126 clutter_actor_remove_effect (ClutterActor *self,
15127 ClutterEffect *effect)
15129 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15130 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15132 _clutter_actor_remove_effect_internal (self, effect);
15134 clutter_actor_queue_redraw (self);
15136 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15140 * clutter_actor_remove_effect_by_name:
15141 * @self: a #ClutterActor
15142 * @name: the name of the effect to remove
15144 * Removes the #ClutterEffect with the given name from the list
15145 * of effects applied to @self
15150 clutter_actor_remove_effect_by_name (ClutterActor *self,
15153 ClutterActorPrivate *priv;
15154 ClutterActorMeta *meta;
15156 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15157 g_return_if_fail (name != NULL);
15161 if (priv->effects == NULL)
15164 meta = _clutter_meta_group_get_meta (priv->effects, name);
15168 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15172 * clutter_actor_get_effects:
15173 * @self: a #ClutterActor
15175 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15177 * Return value: (transfer container) (element-type Clutter.Effect): a list
15178 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15179 * list are owned by Clutter and they should not be freed. You should
15180 * free the returned list using g_list_free() when done
15185 clutter_actor_get_effects (ClutterActor *self)
15187 ClutterActorPrivate *priv;
15189 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15193 if (priv->effects == NULL)
15196 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15200 * clutter_actor_get_effect:
15201 * @self: a #ClutterActor
15202 * @name: the name of the effect to retrieve
15204 * Retrieves the #ClutterEffect with the given name in the list
15205 * of effects applied to @self
15207 * Return value: (transfer none): a #ClutterEffect for the given
15208 * name, or %NULL. The returned #ClutterEffect is owned by the
15209 * actor and it should not be unreferenced directly
15214 clutter_actor_get_effect (ClutterActor *self,
15217 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15218 g_return_val_if_fail (name != NULL, NULL);
15220 if (self->priv->effects == NULL)
15223 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15227 * clutter_actor_clear_effects:
15228 * @self: a #ClutterActor
15230 * Clears the list of effects applied to @self
15235 clutter_actor_clear_effects (ClutterActor *self)
15237 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15239 if (self->priv->effects == NULL)
15242 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15244 clutter_actor_queue_redraw (self);
15248 * clutter_actor_has_key_focus:
15249 * @self: a #ClutterActor
15251 * Checks whether @self is the #ClutterActor that has key focus
15253 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15258 clutter_actor_has_key_focus (ClutterActor *self)
15260 ClutterActor *stage;
15262 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15264 stage = _clutter_actor_get_stage_internal (self);
15268 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15272 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15273 ClutterPaintVolume *pv)
15275 ClutterActorPrivate *priv = self->priv;
15277 /* Actors are only expected to report a valid paint volume
15278 * while they have a valid allocation. */
15279 if (G_UNLIKELY (priv->needs_allocation))
15281 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15282 "Actor needs allocation",
15283 _clutter_actor_get_debug_name (self));
15287 /* Check if there are any handlers connected to the paint
15288 * signal. If there are then all bets are off for what the paint
15289 * volume for this actor might possibly be!
15291 * XXX: It's expected that this is going to end up being quite a
15292 * costly check to have to do here, but we haven't come up with
15293 * another solution that can reliably catch paint signal handlers at
15294 * the right time to either avoid artefacts due to invalid stage
15295 * clipping or due to incorrect culling.
15297 * Previously we checked in clutter_actor_paint(), but at that time
15298 * we may already be using a stage clip that could be derived from
15299 * an invalid paint-volume. We used to try and handle that by
15300 * queuing a follow up, unclipped, redraw but still the previous
15301 * checking wasn't enough to catch invalid volumes involved in
15302 * culling (considering that containers may derive their volume from
15303 * children that haven't yet been painted)
15305 * Longer term, improved solutions could be:
15306 * - Disallow painting in the paint signal, only allow using it
15307 * for tracking when paints happen. We can add another API that
15308 * allows monkey patching the paint of arbitrary actors but in a
15309 * more controlled way and that also supports modifying the
15311 * - If we could be notified somehow when signal handlers are
15312 * connected we wouldn't have to poll for handlers like this.
15314 if (g_signal_has_handler_pending (self,
15315 actor_signals[PAINT],
15319 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15320 "Actor has \"paint\" signal handlers",
15321 _clutter_actor_get_debug_name (self));
15325 _clutter_paint_volume_init_static (pv, self);
15327 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15329 clutter_paint_volume_free (pv);
15330 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15331 "Actor failed to report a volume",
15332 _clutter_actor_get_debug_name (self));
15336 /* since effects can modify the paint volume, we allow them to actually
15337 * do this by making get_paint_volume() "context sensitive"
15339 if (priv->effects != NULL)
15341 if (priv->current_effect != NULL)
15343 const GList *effects, *l;
15345 /* if we are being called from within the paint sequence of
15346 * an actor, get the paint volume up to the current effect
15348 effects = _clutter_meta_group_peek_metas (priv->effects);
15350 l != NULL || (l != NULL && l->data != priv->current_effect);
15353 if (!_clutter_effect_get_paint_volume (l->data, pv))
15355 clutter_paint_volume_free (pv);
15356 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15357 "Effect (%s) failed to report a volume",
15358 _clutter_actor_get_debug_name (self),
15359 _clutter_actor_meta_get_debug_name (l->data));
15366 const GList *effects, *l;
15368 /* otherwise, get the cumulative volume */
15369 effects = _clutter_meta_group_peek_metas (priv->effects);
15370 for (l = effects; l != NULL; l = l->next)
15371 if (!_clutter_effect_get_paint_volume (l->data, pv))
15373 clutter_paint_volume_free (pv);
15374 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15375 "Effect (%s) failed to report a volume",
15376 _clutter_actor_get_debug_name (self),
15377 _clutter_actor_meta_get_debug_name (l->data));
15386 /* The public clutter_actor_get_paint_volume API returns a const
15387 * pointer since we return a pointer directly to the cached
15388 * PaintVolume associated with the actor and don't want the user to
15389 * inadvertently modify it, but for internal uses we sometimes need
15390 * access to the same PaintVolume but need to apply some book-keeping
15391 * modifications to it so we don't want a const pointer.
15393 static ClutterPaintVolume *
15394 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15396 ClutterActorPrivate *priv;
15400 if (priv->paint_volume_valid)
15401 clutter_paint_volume_free (&priv->paint_volume);
15403 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15405 priv->paint_volume_valid = TRUE;
15406 return &priv->paint_volume;
15410 priv->paint_volume_valid = FALSE;
15416 * clutter_actor_get_paint_volume:
15417 * @self: a #ClutterActor
15419 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15420 * when a paint volume can't be determined.
15422 * The paint volume is defined as the 3D space occupied by an actor
15423 * when being painted.
15425 * This function will call the <function>get_paint_volume()</function>
15426 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15427 * should not usually care about overriding the default implementation,
15428 * unless they are, for instance: painting outside their allocation, or
15429 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15432 * <note>2D actors overriding <function>get_paint_volume()</function>
15433 * ensure their volume has a depth of 0. (This will be true so long as
15434 * you don't call clutter_paint_volume_set_depth().)</note>
15436 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15437 * or %NULL if no volume could be determined. The returned pointer
15438 * is not guaranteed to be valid across multiple frames; if you want
15439 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15443 const ClutterPaintVolume *
15444 clutter_actor_get_paint_volume (ClutterActor *self)
15446 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15448 return _clutter_actor_get_paint_volume_mutable (self);
15452 * clutter_actor_get_transformed_paint_volume:
15453 * @self: a #ClutterActor
15454 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15455 * (or %NULL for the stage)
15457 * Retrieves the 3D paint volume of an actor like
15458 * clutter_actor_get_paint_volume() does (Please refer to the
15459 * documentation of clutter_actor_get_paint_volume() for more
15460 * details.) and it additionally transforms the paint volume into the
15461 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15462 * is passed for @relative_to_ancestor)
15464 * This can be used by containers that base their paint volume on
15465 * the volume of their children. Such containers can query the
15466 * transformed paint volume of all of its children and union them
15467 * together using clutter_paint_volume_union().
15469 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15470 * or %NULL if no volume could be determined. The returned pointer is
15471 * not guaranteed to be valid across multiple frames; if you wish to
15472 * keep it, you will have to copy it using clutter_paint_volume_copy().
15476 const ClutterPaintVolume *
15477 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15478 ClutterActor *relative_to_ancestor)
15480 const ClutterPaintVolume *volume;
15481 ClutterActor *stage;
15482 ClutterPaintVolume *transformed_volume;
15484 stage = _clutter_actor_get_stage_internal (self);
15485 if (G_UNLIKELY (stage == NULL))
15488 if (relative_to_ancestor == NULL)
15489 relative_to_ancestor = stage;
15491 volume = clutter_actor_get_paint_volume (self);
15492 if (volume == NULL)
15495 transformed_volume =
15496 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15498 _clutter_paint_volume_copy_static (volume, transformed_volume);
15500 _clutter_paint_volume_transform_relative (transformed_volume,
15501 relative_to_ancestor);
15503 return transformed_volume;
15507 * clutter_actor_get_paint_box:
15508 * @self: a #ClutterActor
15509 * @box: (out): return location for a #ClutterActorBox
15511 * Retrieves the paint volume of the passed #ClutterActor, and
15512 * transforms it into a 2D bounding box in stage coordinates.
15514 * This function is useful to determine the on screen area occupied by
15515 * the actor. The box is only an approximation and may often be
15516 * considerably larger due to the optimizations used to calculate the
15517 * box. The box is never smaller though, so it can reliably be used
15520 * There are times when a 2D paint box can't be determined, e.g.
15521 * because the actor isn't yet parented under a stage or because
15522 * the actor is unable to determine a paint volume.
15524 * Return value: %TRUE if a 2D paint box could be determined, else
15530 clutter_actor_get_paint_box (ClutterActor *self,
15531 ClutterActorBox *box)
15533 ClutterActor *stage;
15534 ClutterPaintVolume *pv;
15536 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15537 g_return_val_if_fail (box != NULL, FALSE);
15539 stage = _clutter_actor_get_stage_internal (self);
15540 if (G_UNLIKELY (!stage))
15543 pv = _clutter_actor_get_paint_volume_mutable (self);
15544 if (G_UNLIKELY (!pv))
15547 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15553 * clutter_actor_has_overlaps:
15554 * @self: A #ClutterActor
15556 * Asks the actor's implementation whether it may contain overlapping
15559 * For example; Clutter may use this to determine whether the painting
15560 * should be redirected to an offscreen buffer to correctly implement
15561 * the opacity property.
15563 * Custom actors can override the default response by implementing the
15564 * #ClutterActor <function>has_overlaps</function> virtual function. See
15565 * clutter_actor_set_offscreen_redirect() for more information.
15567 * Return value: %TRUE if the actor may have overlapping primitives, and
15573 clutter_actor_has_overlaps (ClutterActor *self)
15575 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15577 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15581 * clutter_actor_has_effects:
15582 * @self: A #ClutterActor
15584 * Returns whether the actor has any effects applied.
15586 * Return value: %TRUE if the actor has any effects,
15592 clutter_actor_has_effects (ClutterActor *self)
15594 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15596 if (self->priv->effects == NULL)
15599 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15603 * clutter_actor_has_constraints:
15604 * @self: A #ClutterActor
15606 * Returns whether the actor has any constraints applied.
15608 * Return value: %TRUE if the actor has any constraints,
15614 clutter_actor_has_constraints (ClutterActor *self)
15616 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15618 return self->priv->constraints != NULL;
15622 * clutter_actor_has_actions:
15623 * @self: A #ClutterActor
15625 * Returns whether the actor has any actions applied.
15627 * Return value: %TRUE if the actor has any actions,
15633 clutter_actor_has_actions (ClutterActor *self)
15635 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15637 return self->priv->actions != NULL;
15641 * clutter_actor_get_n_children:
15642 * @self: a #ClutterActor
15644 * Retrieves the number of children of @self.
15646 * Return value: the number of children of an actor
15651 clutter_actor_get_n_children (ClutterActor *self)
15653 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15655 return self->priv->n_children;
15659 * clutter_actor_get_child_at_index:
15660 * @self: a #ClutterActor
15661 * @index_: the position in the list of children
15663 * Retrieves the actor at the given @index_ inside the list of
15664 * children of @self.
15666 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15671 clutter_actor_get_child_at_index (ClutterActor *self,
15674 ClutterActor *iter;
15677 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15678 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15680 for (iter = self->priv->first_child, i = 0;
15681 iter != NULL && i < index_;
15682 iter = iter->priv->next_sibling, i += 1)
15689 * _clutter_actor_foreach_child:
15690 * @actor: The actor whos children you want to iterate
15691 * @callback: The function to call for each child
15692 * @user_data: Private data to pass to @callback
15694 * Calls a given @callback once for each child of the specified @actor and
15695 * passing the @user_data pointer each time.
15697 * Return value: returns %TRUE if all children were iterated, else
15698 * %FALSE if a callback broke out of iteration early.
15701 _clutter_actor_foreach_child (ClutterActor *self,
15702 ClutterForeachCallback callback,
15703 gpointer user_data)
15705 ClutterActorPrivate *priv = self->priv;
15706 ClutterActor *iter;
15709 for (cont = TRUE, iter = priv->first_child;
15710 cont && iter != NULL;
15711 iter = iter->priv->next_sibling)
15713 cont = callback (iter, user_data);
15720 /* For debugging purposes this gives us a simple way to print out
15721 * the scenegraph e.g in gdb using:
15723 * _clutter_actor_traverse (stage,
15725 * clutter_debug_print_actor_cb,
15730 static ClutterActorTraverseVisitFlags
15731 clutter_debug_print_actor_cb (ClutterActor *actor,
15735 g_print ("%*s%s:%p\n",
15737 _clutter_actor_get_debug_name (actor),
15740 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15745 _clutter_actor_traverse_breadth (ClutterActor *actor,
15746 ClutterTraverseCallback callback,
15747 gpointer user_data)
15749 GQueue *queue = g_queue_new ();
15750 ClutterActor dummy;
15751 int current_depth = 0;
15753 g_queue_push_tail (queue, actor);
15754 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15756 while ((actor = g_queue_pop_head (queue)))
15758 ClutterActorTraverseVisitFlags flags;
15760 if (actor == &dummy)
15763 g_queue_push_tail (queue, &dummy);
15767 flags = callback (actor, current_depth, user_data);
15768 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15770 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15772 ClutterActor *iter;
15774 for (iter = actor->priv->first_child;
15776 iter = iter->priv->next_sibling)
15778 g_queue_push_tail (queue, iter);
15783 g_queue_free (queue);
15786 static ClutterActorTraverseVisitFlags
15787 _clutter_actor_traverse_depth (ClutterActor *actor,
15788 ClutterTraverseCallback before_children_callback,
15789 ClutterTraverseCallback after_children_callback,
15791 gpointer user_data)
15793 ClutterActorTraverseVisitFlags flags;
15795 flags = before_children_callback (actor, current_depth, user_data);
15796 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15797 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15799 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15801 ClutterActor *iter;
15803 for (iter = actor->priv->first_child;
15805 iter = iter->priv->next_sibling)
15807 flags = _clutter_actor_traverse_depth (iter,
15808 before_children_callback,
15809 after_children_callback,
15813 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15814 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15818 if (after_children_callback)
15819 return after_children_callback (actor, current_depth, user_data);
15821 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15824 /* _clutter_actor_traverse:
15825 * @actor: The actor to start traversing the graph from
15826 * @flags: These flags may affect how the traversal is done
15827 * @before_children_callback: A function to call before visiting the
15828 * children of the current actor.
15829 * @after_children_callback: A function to call after visiting the
15830 * children of the current actor. (Ignored if
15831 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15832 * @user_data: The private data to pass to the callbacks
15834 * Traverses the scenegraph starting at the specified @actor and
15835 * descending through all its children and its children's children.
15836 * For each actor traversed @before_children_callback and
15837 * @after_children_callback are called with the specified
15838 * @user_data, before and after visiting that actor's children.
15840 * The callbacks can return flags that affect the ongoing traversal
15841 * such as by skipping over an actors children or bailing out of
15842 * any further traversing.
15845 _clutter_actor_traverse (ClutterActor *actor,
15846 ClutterActorTraverseFlags flags,
15847 ClutterTraverseCallback before_children_callback,
15848 ClutterTraverseCallback after_children_callback,
15849 gpointer user_data)
15851 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15852 _clutter_actor_traverse_breadth (actor,
15853 before_children_callback,
15855 else /* DEPTH_FIRST */
15856 _clutter_actor_traverse_depth (actor,
15857 before_children_callback,
15858 after_children_callback,
15859 0, /* start depth */
15864 on_layout_manager_changed (ClutterLayoutManager *manager,
15865 ClutterActor *self)
15867 clutter_actor_queue_relayout (self);
15871 * clutter_actor_set_layout_manager:
15872 * @self: a #ClutterActor
15873 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15875 * Sets the #ClutterLayoutManager delegate object that will be used to
15876 * lay out the children of @self.
15878 * The #ClutterActor will take a reference on the passed @manager which
15879 * will be released either when the layout manager is removed, or when
15880 * the actor is destroyed.
15885 clutter_actor_set_layout_manager (ClutterActor *self,
15886 ClutterLayoutManager *manager)
15888 ClutterActorPrivate *priv;
15890 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15891 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15895 if (priv->layout_manager != NULL)
15897 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15898 G_CALLBACK (on_layout_manager_changed),
15900 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15901 g_object_unref (priv->layout_manager);
15904 priv->layout_manager = manager;
15906 if (priv->layout_manager != NULL)
15908 g_object_ref_sink (priv->layout_manager);
15909 clutter_layout_manager_set_container (priv->layout_manager,
15910 CLUTTER_CONTAINER (self));
15911 g_signal_connect (priv->layout_manager, "layout-changed",
15912 G_CALLBACK (on_layout_manager_changed),
15916 clutter_actor_queue_relayout (self);
15918 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15922 * clutter_actor_get_layout_manager:
15923 * @self: a #ClutterActor
15925 * Retrieves the #ClutterLayoutManager used by @self.
15927 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15932 ClutterLayoutManager *
15933 clutter_actor_get_layout_manager (ClutterActor *self)
15935 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15937 return self->priv->layout_manager;
15940 static const ClutterLayoutInfo default_layout_info = {
15943 { 0, 0, 0, 0 }, /* margin */
15944 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
15945 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
15946 0.f, 0.f, /* min_width, natural_width */
15947 0.f, 0.f, /* natual_width, natural_height */
15951 layout_info_free (gpointer data)
15953 if (G_LIKELY (data != NULL))
15954 g_slice_free (ClutterLayoutInfo, data);
15958 * _clutter_actor_get_layout_info:
15959 * @self: a #ClutterActor
15961 * Retrieves a pointer to the ClutterLayoutInfo structure.
15963 * If the actor does not have a ClutterLayoutInfo associated to it, one
15964 * will be created and initialized to the default values.
15966 * This function should be used for setters.
15968 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15971 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15973 ClutterLayoutInfo *
15974 _clutter_actor_get_layout_info (ClutterActor *self)
15976 ClutterLayoutInfo *retval;
15978 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15979 if (retval == NULL)
15981 retval = g_slice_new (ClutterLayoutInfo);
15983 *retval = default_layout_info;
15985 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15994 * _clutter_actor_get_layout_info_or_defaults:
15995 * @self: a #ClutterActor
15997 * Retrieves the ClutterLayoutInfo structure associated to an actor.
15999 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16000 * then the default structure will be returned.
16002 * This function should only be used for getters.
16004 * Return value: a const pointer to the ClutterLayoutInfo structure
16006 const ClutterLayoutInfo *
16007 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16009 const ClutterLayoutInfo *info;
16011 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16013 return &default_layout_info;
16019 * clutter_actor_set_x_align:
16020 * @self: a #ClutterActor
16021 * @x_align: the horizontal alignment policy
16023 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16024 * actor received extra horizontal space.
16026 * See also the #ClutterActor:x-align property.
16031 clutter_actor_set_x_align (ClutterActor *self,
16032 ClutterActorAlign x_align)
16034 ClutterLayoutInfo *info;
16036 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16038 info = _clutter_actor_get_layout_info (self);
16040 if (info->x_align != x_align)
16042 info->x_align = x_align;
16044 clutter_actor_queue_relayout (self);
16046 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16051 * clutter_actor_get_x_align:
16052 * @self: a #ClutterActor
16054 * Retrieves the horizontal alignment policy set using
16055 * clutter_actor_set_x_align().
16057 * Return value: the horizontal alignment policy.
16062 clutter_actor_get_x_align (ClutterActor *self)
16064 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16066 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16070 * clutter_actor_set_y_align:
16071 * @self: a #ClutterActor
16072 * @y_align: the vertical alignment policy
16074 * Sets the vertical alignment policy of a #ClutterActor, in case the
16075 * actor received extra vertical space.
16077 * See also the #ClutterActor:y-align property.
16082 clutter_actor_set_y_align (ClutterActor *self,
16083 ClutterActorAlign y_align)
16085 ClutterLayoutInfo *info;
16087 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16089 info = _clutter_actor_get_layout_info (self);
16091 if (info->y_align != y_align)
16093 info->y_align = y_align;
16095 clutter_actor_queue_relayout (self);
16097 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16102 * clutter_actor_get_y_align:
16103 * @self: a #ClutterActor
16105 * Retrieves the vertical alignment policy set using
16106 * clutter_actor_set_y_align().
16108 * Return value: the vertical alignment policy.
16113 clutter_actor_get_y_align (ClutterActor *self)
16115 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16117 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16122 * clutter_margin_new:
16124 * Creates a new #ClutterMargin.
16126 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16127 * clutter_margin_free() to free the resources associated with it when
16133 clutter_margin_new (void)
16135 return g_slice_new0 (ClutterMargin);
16139 * clutter_margin_copy:
16140 * @margin_: a #ClutterMargin
16142 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16143 * the newly created structure.
16145 * Return value: (transfer full): a copy of the #ClutterMargin.
16150 clutter_margin_copy (const ClutterMargin *margin_)
16152 if (G_LIKELY (margin_ != NULL))
16153 return g_slice_dup (ClutterMargin, margin_);
16159 * clutter_margin_free:
16160 * @margin_: a #ClutterMargin
16162 * Frees the resources allocated by clutter_margin_new() and
16163 * clutter_margin_copy().
16168 clutter_margin_free (ClutterMargin *margin_)
16170 if (G_LIKELY (margin_ != NULL))
16171 g_slice_free (ClutterMargin, margin_);
16174 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16175 clutter_margin_copy,
16176 clutter_margin_free)
16179 * clutter_actor_set_margin:
16180 * @self: a #ClutterActor
16181 * @margin: a #ClutterMargin
16183 * Sets all the components of the margin of a #ClutterActor.
16188 clutter_actor_set_margin (ClutterActor *self,
16189 const ClutterMargin *margin)
16191 ClutterLayoutInfo *info;
16195 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16196 g_return_if_fail (margin != NULL);
16198 obj = G_OBJECT (self);
16201 g_object_freeze_notify (obj);
16203 info = _clutter_actor_get_layout_info (self);
16205 if (info->margin.top != margin->top)
16207 info->margin.top = margin->top;
16208 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16212 if (info->margin.right != margin->right)
16214 info->margin.right = margin->right;
16215 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16219 if (info->margin.bottom != margin->bottom)
16221 info->margin.bottom = margin->bottom;
16222 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16226 if (info->margin.left != margin->left)
16228 info->margin.left = margin->left;
16229 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16234 clutter_actor_queue_relayout (self);
16236 g_object_thaw_notify (obj);
16240 * clutter_actor_get_margin:
16241 * @self: a #ClutterActor
16242 * @margin: (out caller-allocates): return location for a #ClutterMargin
16244 * Retrieves all the components of the margin of a #ClutterActor.
16249 clutter_actor_get_margin (ClutterActor *self,
16250 ClutterMargin *margin)
16252 const ClutterLayoutInfo *info;
16254 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16255 g_return_if_fail (margin != NULL);
16257 info = _clutter_actor_get_layout_info_or_defaults (self);
16259 *margin = info->margin;
16263 * clutter_actor_set_margin_top:
16264 * @self: a #ClutterActor
16265 * @margin: the top margin
16267 * Sets the margin from the top of a #ClutterActor.
16272 clutter_actor_set_margin_top (ClutterActor *self,
16275 ClutterLayoutInfo *info;
16277 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16278 g_return_if_fail (margin >= 0.f);
16280 info = _clutter_actor_get_layout_info (self);
16282 if (info->margin.top == margin)
16285 info->margin.top = margin;
16287 clutter_actor_queue_relayout (self);
16289 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16293 * clutter_actor_get_margin_top:
16294 * @self: a #ClutterActor
16296 * Retrieves the top margin of a #ClutterActor.
16298 * Return value: the top margin
16303 clutter_actor_get_margin_top (ClutterActor *self)
16305 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16307 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16311 * clutter_actor_set_margin_bottom:
16312 * @self: a #ClutterActor
16313 * @margin: the bottom margin
16315 * Sets the margin from the bottom of a #ClutterActor.
16320 clutter_actor_set_margin_bottom (ClutterActor *self,
16323 ClutterLayoutInfo *info;
16325 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16326 g_return_if_fail (margin >= 0.f);
16328 info = _clutter_actor_get_layout_info (self);
16330 if (info->margin.bottom == margin)
16333 info->margin.bottom = margin;
16335 clutter_actor_queue_relayout (self);
16337 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16341 * clutter_actor_get_margin_bottom:
16342 * @self: a #ClutterActor
16344 * Retrieves the bottom margin of a #ClutterActor.
16346 * Return value: the bottom margin
16351 clutter_actor_get_margin_bottom (ClutterActor *self)
16353 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16355 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16359 * clutter_actor_set_margin_left:
16360 * @self: a #ClutterActor
16361 * @margin: the left margin
16363 * Sets the margin from the left of a #ClutterActor.
16368 clutter_actor_set_margin_left (ClutterActor *self,
16371 ClutterLayoutInfo *info;
16373 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16374 g_return_if_fail (margin >= 0.f);
16376 info = _clutter_actor_get_layout_info (self);
16378 if (info->margin.left == margin)
16381 info->margin.left = margin;
16383 clutter_actor_queue_relayout (self);
16385 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16389 * clutter_actor_get_margin_left:
16390 * @self: a #ClutterActor
16392 * Retrieves the left margin of a #ClutterActor.
16394 * Return value: the left margin
16399 clutter_actor_get_margin_left (ClutterActor *self)
16401 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16403 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16407 * clutter_actor_set_margin_right:
16408 * @self: a #ClutterActor
16409 * @margin: the right margin
16411 * Sets the margin from the right of a #ClutterActor.
16416 clutter_actor_set_margin_right (ClutterActor *self,
16419 ClutterLayoutInfo *info;
16421 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16422 g_return_if_fail (margin >= 0.f);
16424 info = _clutter_actor_get_layout_info (self);
16426 if (info->margin.right == margin)
16429 info->margin.right = margin;
16431 clutter_actor_queue_relayout (self);
16433 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16437 * clutter_actor_get_margin_right:
16438 * @self: a #ClutterActor
16440 * Retrieves the right margin of a #ClutterActor.
16442 * Return value: the right margin
16447 clutter_actor_get_margin_right (ClutterActor *self)
16449 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16451 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16455 clutter_actor_set_background_color_internal (ClutterActor *self,
16456 const ClutterColor *color)
16458 ClutterActorPrivate *priv = self->priv;
16461 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16464 obj = G_OBJECT (self);
16466 priv->bg_color = *color;
16467 priv->bg_color_set = TRUE;
16469 clutter_actor_queue_redraw (self);
16471 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16472 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16476 * clutter_actor_set_background_color:
16477 * @self: a #ClutterActor
16478 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16481 * Sets the background color of a #ClutterActor.
16483 * The background color will be used to cover the whole allocation of the
16484 * actor. The default background color of an actor is transparent.
16486 * To check whether an actor has a background color, you can use the
16487 * #ClutterActor:background-color-set actor property.
16489 * The #ClutterActor:background-color property is animatable.
16494 clutter_actor_set_background_color (ClutterActor *self,
16495 const ClutterColor *color)
16497 ClutterActorPrivate *priv;
16499 GParamSpec *bg_color_pspec;
16501 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16503 obj = G_OBJECT (self);
16509 priv->bg_color_set = FALSE;
16510 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16511 clutter_actor_queue_redraw (self);
16515 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16516 if (clutter_actor_get_easing_duration (self) != 0)
16518 ClutterTransition *transition;
16520 transition = _clutter_actor_get_transition (self, bg_color_pspec);
16521 if (transition == NULL)
16523 transition = _clutter_actor_create_transition (self, bg_color_pspec,
16526 clutter_timeline_start (CLUTTER_TIMELINE (transition));
16529 _clutter_actor_update_transition (self, bg_color_pspec, color);
16531 clutter_actor_queue_redraw (self);
16534 clutter_actor_set_background_color_internal (self, color);
16538 * clutter_actor_get_background_color:
16539 * @self: a #ClutterActor
16540 * @color: (out caller-allocates): return location for a #ClutterColor
16542 * Retrieves the color set using clutter_actor_set_background_color().
16547 clutter_actor_get_background_color (ClutterActor *self,
16548 ClutterColor *color)
16550 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16551 g_return_if_fail (color != NULL);
16553 *color = self->priv->bg_color;
16557 * clutter_actor_get_previous_sibling:
16558 * @self: a #ClutterActor
16560 * Retrieves the sibling of @self that comes before it in the list
16561 * of children of @self's parent.
16563 * The returned pointer is only valid until the scene graph changes; it
16564 * is not safe to modify the list of children of @self while iterating
16567 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16572 clutter_actor_get_previous_sibling (ClutterActor *self)
16574 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16576 return self->priv->prev_sibling;
16580 * clutter_actor_get_next_sibling:
16581 * @self: a #ClutterActor
16583 * Retrieves the sibling of @self that comes after it in the list
16584 * of children of @self's parent.
16586 * The returned pointer is only valid until the scene graph changes; it
16587 * is not safe to modify the list of children of @self while iterating
16590 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16595 clutter_actor_get_next_sibling (ClutterActor *self)
16597 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16599 return self->priv->next_sibling;
16603 * clutter_actor_get_first_child:
16604 * @self: a #ClutterActor
16606 * Retrieves the first child of @self.
16608 * The returned pointer is only valid until the scene graph changes; it
16609 * is not safe to modify the list of children of @self while iterating
16612 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16617 clutter_actor_get_first_child (ClutterActor *self)
16619 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16621 return self->priv->first_child;
16625 * clutter_actor_get_last_child:
16626 * @self: a #ClutterActor
16628 * Retrieves the last child of @self.
16630 * The returned pointer is only valid until the scene graph changes; it
16631 * is not safe to modify the list of children of @self while iterating
16634 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16639 clutter_actor_get_last_child (ClutterActor *self)
16641 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16643 return self->priv->last_child;
16646 /* easy way to have properly named fields instead of the dummy ones
16647 * we use in the public structure
16649 typedef struct _RealActorIter
16651 ClutterActor *root; /* dummy1 */
16652 ClutterActor *current; /* dummy2 */
16653 gpointer padding_1; /* dummy3 */
16654 gint age; /* dummy4 */
16655 gpointer padding_2; /* dummy5 */
16659 * clutter_actor_iter_init:
16660 * @iter: a #ClutterActorIter
16661 * @root: a #ClutterActor
16663 * Initializes a #ClutterActorIter, which can then be used to iterate
16664 * efficiently over a section of the scene graph, and associates it
16667 * Modifying the scene graph section that contains @root will invalidate
16671 * ClutterActorIter iter;
16672 * ClutterActor *child;
16674 * clutter_actor_iter_init (&iter, container);
16675 * while (clutter_actor_iter_next (&iter, &child))
16677 * /* do something with child */
16684 clutter_actor_iter_init (ClutterActorIter *iter,
16685 ClutterActor *root)
16687 RealActorIter *ri = (RealActorIter *) iter;
16689 g_return_if_fail (iter != NULL);
16690 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16693 ri->current = NULL;
16694 ri->age = root->priv->age;
16698 * clutter_actor_iter_next:
16699 * @iter: a #ClutterActorIter
16700 * @child: (out): return location for a #ClutterActor
16702 * Advances the @iter and retrieves the next child of the root #ClutterActor
16703 * that was used to initialize the #ClutterActorIterator.
16705 * If the iterator can advance, this function returns %TRUE and sets the
16708 * If the iterator cannot advance, this function returns %FALSE, and
16709 * the contents of @child are undefined.
16711 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16716 clutter_actor_iter_next (ClutterActorIter *iter,
16717 ClutterActor **child)
16719 RealActorIter *ri = (RealActorIter *) iter;
16721 g_return_val_if_fail (iter != NULL, FALSE);
16722 g_return_val_if_fail (ri->root != NULL, FALSE);
16723 #ifndef G_DISABLE_ASSERT
16724 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16727 if (ri->current == NULL)
16728 ri->current = ri->root->priv->first_child;
16730 ri->current = ri->current->priv->next_sibling;
16733 *child = ri->current;
16735 return ri->current != NULL;
16739 * clutter_actor_iter_prev:
16740 * @iter: a #ClutterActorIter
16741 * @child: (out): return location for a #ClutterActor
16743 * Advances the @iter and retrieves the previous child of the root
16744 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16746 * If the iterator can advance, this function returns %TRUE and sets the
16749 * If the iterator cannot advance, this function returns %FALSE, and
16750 * the contents of @child are undefined.
16752 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16757 clutter_actor_iter_prev (ClutterActorIter *iter,
16758 ClutterActor **child)
16760 RealActorIter *ri = (RealActorIter *) iter;
16762 g_return_val_if_fail (iter != NULL, FALSE);
16763 g_return_val_if_fail (ri->root != NULL, FALSE);
16764 #ifndef G_DISABLE_ASSERT
16765 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16768 if (ri->current == NULL)
16769 ri->current = ri->root->priv->last_child;
16771 ri->current = ri->current->priv->prev_sibling;
16774 *child = ri->current;
16776 return ri->current != NULL;
16780 * clutter_actor_iter_remove:
16781 * @iter: a #ClutterActorIter
16783 * Safely removes the #ClutterActor currently pointer to by the iterator
16786 * This function can only be called after clutter_actor_iter_next() or
16787 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16788 * than once for the same actor.
16790 * This function will call clutter_actor_remove_child() internally.
16795 clutter_actor_iter_remove (ClutterActorIter *iter)
16797 RealActorIter *ri = (RealActorIter *) iter;
16800 g_return_if_fail (iter != NULL);
16801 g_return_if_fail (ri->root != NULL);
16802 #ifndef G_DISABLE_ASSERT
16803 g_return_if_fail (ri->age == ri->root->priv->age);
16805 g_return_if_fail (ri->current != NULL);
16811 ri->current = cur->priv->prev_sibling;
16813 clutter_actor_remove_child_internal (ri->root, cur,
16814 REMOVE_CHILD_DEFAULT_FLAGS);
16821 * clutter_actor_iter_destroy:
16822 * @iter: a #ClutterActorIter
16824 * Safely destroys the #ClutterActor currently pointer to by the iterator
16827 * This function can only be called after clutter_actor_iter_next() or
16828 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16829 * than once for the same actor.
16831 * This function will call clutter_actor_destroy() internally.
16836 clutter_actor_iter_destroy (ClutterActorIter *iter)
16838 RealActorIter *ri = (RealActorIter *) iter;
16841 g_return_if_fail (iter != NULL);
16842 g_return_if_fail (ri->root != NULL);
16843 #ifndef G_DISABLE_ASSERT
16844 g_return_if_fail (ri->age == ri->root->priv->age);
16846 g_return_if_fail (ri->current != NULL);
16852 ri->current = cur->priv->prev_sibling;
16854 clutter_actor_destroy (cur);
16860 static const ClutterAnimationInfo default_animation_info = {
16861 NULL, /* transitions */
16863 NULL, /* cur_state */
16867 clutter_animation_info_free (gpointer data)
16871 ClutterAnimationInfo *info = data;
16873 if (info->transitions != NULL)
16874 g_hash_table_unref (info->transitions);
16876 if (info->states != NULL)
16877 g_array_unref (info->states);
16879 g_slice_free (ClutterAnimationInfo, info);
16883 const ClutterAnimationInfo *
16884 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16886 const ClutterAnimationInfo *res;
16887 GObject *obj = G_OBJECT (self);
16889 res = g_object_get_qdata (obj, quark_actor_animation_info);
16893 return &default_animation_info;
16896 ClutterAnimationInfo *
16897 _clutter_actor_get_animation_info (ClutterActor *self)
16899 GObject *obj = G_OBJECT (self);
16900 ClutterAnimationInfo *res;
16902 res = g_object_get_qdata (obj, quark_actor_animation_info);
16905 res = g_slice_new (ClutterAnimationInfo);
16907 *res = default_animation_info;
16909 g_object_set_qdata_full (obj, quark_actor_animation_info,
16911 clutter_animation_info_free);
16917 ClutterTransition *
16918 _clutter_actor_get_transition (ClutterActor *actor,
16921 const ClutterAnimationInfo *info;
16923 info = _clutter_actor_get_animation_info_or_defaults (actor);
16925 if (info->transitions == NULL)
16928 return g_hash_table_lookup (info->transitions, pspec->name);
16931 typedef struct _TransitionClosure
16933 ClutterActor *actor;
16934 ClutterTransition *transition;
16936 gulong completed_id;
16937 } TransitionClosure;
16940 transition_closure_free (gpointer data)
16942 if (G_LIKELY (data != NULL))
16944 TransitionClosure *clos = data;
16946 g_signal_handler_disconnect (clos->transition, clos->completed_id);
16947 g_free (clos->name);
16949 g_slice_free (TransitionClosure, clos);
16954 on_transition_completed (ClutterTransition *transition,
16955 TransitionClosure *clos)
16957 ClutterAnimationInfo *info;
16959 info = _clutter_actor_get_animation_info (clos->actor);
16961 /* this will take care of cleaning clos for us */
16962 g_hash_table_remove (info->transitions, clos->name);
16966 _clutter_actor_update_transition (ClutterActor *actor,
16970 TransitionClosure *clos;
16971 ClutterInterval *interval;
16972 const ClutterAnimationInfo *info;
16975 GValue initial = G_VALUE_INIT;
16976 GValue final = G_VALUE_INIT;
16977 char *error = NULL;
16979 info = _clutter_actor_get_animation_info_or_defaults (actor);
16981 if (info->transitions == NULL)
16984 clos = g_hash_table_lookup (info->transitions, pspec->name);
16988 va_start (var_args, pspec);
16990 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16992 g_value_init (&initial, ptype);
16993 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16997 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17000 g_critical ("%s: %s", G_STRLOC, error);
17005 interval = clutter_transition_get_interval (clos->transition);
17006 clutter_interval_set_initial_value (interval, &initial);
17007 clutter_interval_set_final_value (interval, &final);
17009 clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
17012 g_value_unset (&initial);
17013 g_value_unset (&final);
17019 * _clutter_actor_create_transition:
17020 * @actor: a #ClutterActor
17021 * @pspec: the property used for the transition
17022 * @...: initial and final state
17024 * Creates a #ClutterTransition for the property represented by @pspec.
17026 * Return value: a #ClutterTransition
17028 ClutterTransition *
17029 _clutter_actor_create_transition (ClutterActor *actor,
17033 ClutterAnimationInfo *info;
17034 ClutterTransition *res = NULL;
17035 gboolean call_restore = FALSE;
17036 TransitionClosure *clos;
17039 info = _clutter_actor_get_animation_info (actor);
17041 if (info->states == NULL)
17043 clutter_actor_save_easing_state (actor);
17044 call_restore = TRUE;
17047 if (info->transitions == NULL)
17048 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17050 transition_closure_free);
17052 va_start (var_args, pspec);
17054 clos = g_hash_table_lookup (info->transitions, pspec->name);
17057 ClutterInterval *interval;
17058 GValue initial = G_VALUE_INIT;
17059 GValue final = G_VALUE_INIT;
17063 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17065 G_VALUE_COLLECT_INIT (&initial, ptype,
17070 g_critical ("%s: %s", G_STRLOC, error);
17075 G_VALUE_COLLECT_INIT (&final, ptype,
17081 g_critical ("%s: %s", G_STRLOC, error);
17082 g_value_unset (&initial);
17087 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17089 g_value_unset (&initial);
17090 g_value_unset (&final);
17092 res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17095 clutter_transition_set_interval (res, interval);
17096 clutter_transition_set_remove_on_complete (res, TRUE);
17098 clutter_actor_add_transition (actor, pspec->name, res);
17101 res = clos->transition;
17105 clutter_actor_restore_easing_state (actor);
17113 * clutter_actor_add_transition:
17114 * @self: a #ClutterActor
17115 * @name: the name of the transition to add
17116 * @transition: the #ClutterTransition to add
17118 * Adds a @transition to the #ClutterActor's list of animations.
17120 * The @name string is a per-actor unique identifier of the @transition: only
17121 * one #ClutterTransition can be associated to the specified @name.
17123 * The @transition will be given the easing duration, mode, and delay
17124 * associated to the actor's current easing state; it is possible to modify
17125 * these values after calling clutter_actor_add_transition().
17127 * This function is usually called implicitly when modifying an animatable
17133 clutter_actor_add_transition (ClutterActor *self,
17135 ClutterTransition *transition)
17137 ClutterTimeline *timeline;
17138 TransitionClosure *clos;
17139 ClutterAnimationInfo *info;
17141 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17142 g_return_if_fail (name != NULL);
17143 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17145 info = _clutter_actor_get_animation_info (self);
17147 if (info->cur_state == NULL)
17149 g_warning ("No easing state is defined for the actor '%s'; you "
17150 "must call clutter_actor_save_easing_state() before "
17151 "calling clutter_actor_add_transition().",
17152 _clutter_actor_get_debug_name (self));
17156 if (info->transitions == NULL)
17157 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17159 transition_closure_free);
17161 if (g_hash_table_lookup (info->transitions, name) != NULL)
17163 g_warning ("A transition with name '%s' already exists for "
17166 _clutter_actor_get_debug_name (self));
17170 timeline = CLUTTER_TIMELINE (transition);
17172 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17173 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17174 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17176 clos = g_slice_new (TransitionClosure);
17177 clos->actor = self;
17178 clos->transition = transition;
17179 clos->name = g_strdup (name);
17180 clos->completed_id = g_signal_connect (timeline, "completed",
17181 G_CALLBACK (on_transition_completed),
17184 g_hash_table_insert (info->transitions, clos->name, clos);
17188 * clutter_actor_remove_transition:
17189 * @self: a #ClutterActor
17190 * @name: the name of the transition to remove
17192 * Removes the transition stored inside a #ClutterActor using @name
17198 clutter_actor_remove_transition (ClutterActor *self,
17201 const ClutterAnimationInfo *info;
17203 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17204 g_return_if_fail (name != NULL);
17206 info = _clutter_actor_get_animation_info_or_defaults (self);
17208 if (info->transitions == NULL)
17211 g_hash_table_remove (info->transitions, name);
17215 * clutter_actor_remove_all_transitions:
17216 * @self: a #ClutterActor
17218 * Removes all transitions associated to @self.
17223 clutter_actor_remove_all_transitions (ClutterActor *self)
17225 const ClutterAnimationInfo *info;
17227 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17229 info = _clutter_actor_get_animation_info_or_defaults (self);
17230 if (info->transitions == NULL)
17233 g_hash_table_remove_all (info->transitions);
17237 * clutter_actor_set_easing_duration:
17238 * @self: a #ClutterActor
17239 * @msecs: the duration of the easing, or %NULL
17241 * Sets the duration of the tweening for animatable properties
17242 * of @self for the current easing state.
17247 clutter_actor_set_easing_duration (ClutterActor *self,
17250 ClutterAnimationInfo *info;
17252 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17254 info = _clutter_actor_get_animation_info (self);
17256 if (info->cur_state == NULL)
17258 g_warning ("You must call clutter_actor_save_easing_state() prior "
17259 "to calling clutter_actor_set_easing_duration().");
17263 if (info->cur_state->easing_duration != msecs)
17264 info->cur_state->easing_duration = msecs;
17268 * clutter_actor_get_easing_duration:
17269 * @self: a #ClutterActor
17271 * Retrieves the duration of the tweening for animatable
17272 * properties of @self for the current easing state.
17274 * Return value: the duration of the tweening, in milliseconds
17279 clutter_actor_get_easing_duration (ClutterActor *self)
17281 const ClutterAnimationInfo *info;
17283 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17285 info = _clutter_actor_get_animation_info_or_defaults (self);
17287 if (info->cur_state != NULL)
17288 return info->cur_state->easing_duration;
17294 * clutter_actor_set_easing_mode:
17295 * @self: a #ClutterActor
17296 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17298 * Sets the easing mode for the tweening of animatable properties
17304 clutter_actor_set_easing_mode (ClutterActor *self,
17305 ClutterAnimationMode mode)
17307 ClutterAnimationInfo *info;
17309 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17310 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17311 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17313 info = _clutter_actor_get_animation_info (self);
17315 if (info->cur_state == NULL)
17317 g_warning ("You must call clutter_actor_save_easing_state() prior "
17318 "to calling clutter_actor_set_easing_mode().");
17322 if (info->cur_state->easing_mode != mode)
17323 info->cur_state->easing_mode = mode;
17327 * clutter_actor_get_easing_mode:
17328 * @self: a #ClutterActor
17330 * Retrieves the easing mode for the tweening of animatable properties
17331 * of @self for the current easing state.
17333 * Return value: an easing mode
17337 ClutterAnimationMode
17338 clutter_actor_get_easing_mode (ClutterActor *self)
17340 const ClutterAnimationInfo *info;
17342 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17344 info = _clutter_actor_get_animation_info_or_defaults (self);
17346 if (info->cur_state != NULL)
17347 return info->cur_state->easing_mode;
17349 return CLUTTER_EASE_OUT_CUBIC;
17353 * clutter_actor_set_easing_delay:
17354 * @self: a #ClutterActor
17355 * @msecs: the delay before the start of the tweening, in milliseconds
17357 * Sets the delay that should be applied before tweening animatable
17363 clutter_actor_set_easing_delay (ClutterActor *self,
17366 ClutterAnimationInfo *info;
17368 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17370 info = _clutter_actor_get_animation_info (self);
17372 if (info->cur_state == NULL)
17374 g_warning ("You must call clutter_actor_save_easing_state() prior "
17375 "to calling clutter_actor_set_easing_delay().");
17379 if (info->cur_state->easing_delay != msecs)
17380 info->cur_state->easing_delay = msecs;
17384 * clutter_actor_get_easing_delay:
17385 * @self: a #ClutterActor
17387 * Retrieves the delay that should be applied when tweening animatable
17390 * Return value: a delay, in milliseconds
17395 clutter_actor_get_easing_delay (ClutterActor *self)
17397 const ClutterAnimationInfo *info;
17399 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17401 info = _clutter_actor_get_animation_info_or_defaults (self);
17403 if (info->cur_state != NULL)
17404 return info->cur_state->easing_delay;
17410 * clutter_actor_get_transition:
17411 * @self: a #ClutterActor
17412 * @name: the name of the transition
17414 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17415 * transition @name.
17417 * Transitions created for animatable properties use the name of the
17418 * property itself, for instance the code below:
17421 * clutter_actor_set_easing_duration (actor, 1000);
17422 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17424 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17425 * g_signal_connect (transition, "completed",
17426 * G_CALLBACK (on_transition_complete),
17430 * will call the <function>on_transition_complete</function> callback when
17431 * the transition is complete.
17433 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17434 * was found to match the passed name; the returned instance is owned
17435 * by Clutter and it should not be freed
17439 ClutterTransition *
17440 clutter_actor_get_transition (ClutterActor *self,
17443 TransitionClosure *clos;
17444 const ClutterAnimationInfo *info;
17446 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17447 g_return_val_if_fail (name != NULL, NULL);
17449 info = _clutter_actor_get_animation_info_or_defaults (self);
17451 if (info->transitions == NULL)
17454 clos = g_hash_table_lookup (info->transitions, name);
17458 return clos->transition;
17462 * clutter_actor_save_easing_state:
17463 * @self: a #ClutterActor
17465 * Saves the current easing state for animatable properties, and creates
17466 * a new state with the default values for easing mode and duration.
17471 clutter_actor_save_easing_state (ClutterActor *self)
17473 ClutterAnimationInfo *info;
17476 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17478 info = _clutter_actor_get_animation_info (self);
17480 if (info->states == NULL)
17481 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17483 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17484 new_state.easing_duration = 250;
17485 new_state.easing_delay = 0;
17487 g_array_append_val (info->states, new_state);
17489 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17493 * clutter_actor_restore_easing_state:
17494 * @self: a #ClutterActor
17496 * Restores the easing state as it was prior to a call to
17497 * clutter_actor_save_easing_state().
17502 clutter_actor_restore_easing_state (ClutterActor *self)
17504 ClutterAnimationInfo *info;
17506 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17508 info = _clutter_actor_get_animation_info (self);
17510 if (info->states == NULL)
17512 g_critical ("The function clutter_actor_restore_easing_state() has "
17513 "called without a previous call to "
17514 "clutter_actor_save_easing_state().");
17518 g_array_remove_index (info->states, info->states->len - 1);
17520 if (info->states->len > 0)
17521 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17524 g_array_unref (info->states);
17525 info->states = NULL;
17530 * clutter_actor_set_content:
17531 * @self: a #ClutterActor
17532 * @content: (allow-none): a #ClutterContent, or %NULL
17534 * Sets the contents of a #ClutterActor.
17539 clutter_actor_set_content (ClutterActor *self,
17540 ClutterContent *content)
17542 ClutterActorPrivate *priv;
17544 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17545 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17549 if (priv->content != NULL)
17551 _clutter_content_detached (priv->content, self);
17552 g_object_unref (priv->content);
17555 priv->content = content;
17557 if (priv->content != NULL)
17559 g_object_ref (priv->content);
17560 _clutter_content_attached (priv->content, self);
17563 /* given that the content is always painted within the allocation,
17564 * we only need to queue a redraw here
17566 clutter_actor_queue_redraw (self);
17568 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17570 /* if the content gravity is not resize-fill, and the new content has a
17571 * different preferred size than the previous one, then the content box
17572 * may have been changed. since we compute that lazily, we just notify
17573 * here, and let whomever watches :content-box do whatever they need to
17576 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17577 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17581 * clutter_actor_get_content:
17582 * @self: a #ClutterActor
17584 * Retrieves the contents of @self.
17586 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17587 * or %NULL if none was set
17592 clutter_actor_get_content (ClutterActor *self)
17594 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17596 return self->priv->content;
17600 * clutter_actor_set_content_gravity:
17601 * @self: a #ClutterActor
17602 * @gravity: the #ClutterContentGravity
17604 * Sets the gravity of the #ClutterContent used by @self.
17606 * See the description of the #ClutterActor:content-gravity property for
17607 * more information.
17612 clutter_actor_set_content_gravity (ClutterActor *self,
17613 ClutterContentGravity gravity)
17615 ClutterActorPrivate *priv;
17617 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17621 if (priv->content_gravity == gravity)
17624 priv->content_gravity = gravity;
17626 clutter_actor_queue_redraw (self);
17628 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17629 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17633 * clutter_actor_get_content_gravity:
17634 * @self: a #ClutterActor
17636 * Retrieves the content gravity as set using
17637 * clutter_actor_get_content_gravity().
17639 * Return value: the content gravity
17643 ClutterContentGravity
17644 clutter_actor_get_content_gravity (ClutterActor *self)
17646 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17647 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17649 return self->priv->content_gravity;
17653 * clutter_actor_get_content_box:
17654 * @self: a #ClutterActor
17655 * @box: (out caller-allocates): the return location for the bounding
17656 * box for the #ClutterContent
17658 * Retrieves the bounding box for the #ClutterContent of @self.
17660 * The bounding box is relative to the actor's allocation.
17662 * If no #ClutterContent is set for @self, or if @self has not been
17663 * allocated yet, then the result is undefined.
17665 * The content box is guaranteed to be, at most, as big as the allocation
17666 * of the #ClutterActor.
17668 * If the #ClutterContent used by the actor has a preferred size, then
17669 * it is possible to modify the content box by using the
17670 * #ClutterActor:content-gravity property.
17675 clutter_actor_get_content_box (ClutterActor *self,
17676 ClutterActorBox *box)
17678 ClutterActorPrivate *priv;
17679 gfloat content_w, content_h;
17680 gfloat alloc_w, alloc_h;
17682 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17683 g_return_if_fail (box != NULL);
17689 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17690 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17692 if (priv->content == NULL)
17695 /* no need to do any more work */
17696 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17699 /* if the content does not have a preferred size then there is
17700 * no point in computing the content box
17702 if (!clutter_content_get_preferred_size (priv->content,
17710 switch (priv->content_gravity)
17712 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17713 box->x2 = box->x1 + MIN (content_w, alloc_w);
17714 box->y2 = box->y1 + MIN (content_h, alloc_h);
17717 case CLUTTER_CONTENT_GRAVITY_TOP:
17718 if (alloc_w > content_w)
17720 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17721 box->x2 = box->x1 + content_w;
17723 box->y2 = box->y1 + MIN (content_h, alloc_h);
17726 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17727 if (alloc_w > content_w)
17729 box->x1 += (alloc_w - content_w);
17730 box->x2 = box->x1 + content_w;
17732 box->y2 = box->y1 + MIN (content_h, alloc_h);
17735 case CLUTTER_CONTENT_GRAVITY_LEFT:
17736 box->x2 = box->x1 + MIN (content_w, alloc_w);
17737 if (alloc_h > content_h)
17739 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17740 box->y2 = box->y1 + content_h;
17744 case CLUTTER_CONTENT_GRAVITY_CENTER:
17745 if (alloc_w > content_w)
17747 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17748 box->x2 = box->x1 + content_w;
17750 if (alloc_h > content_h)
17752 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17753 box->y2 = box->y1 + content_h;
17757 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17758 if (alloc_w > content_w)
17760 box->x1 += (alloc_w - content_w);
17761 box->x2 = box->x1 + content_w;
17763 if (alloc_h > content_h)
17765 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17766 box->y2 = box->y1 + content_h;
17770 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17771 box->x2 = box->x1 + MIN (content_w, alloc_w);
17772 if (alloc_h > content_h)
17774 box->y1 += (alloc_h - content_h);
17775 box->y2 = box->y1 + content_h;
17779 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17780 if (alloc_w > content_w)
17782 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17783 box->x2 = box->x1 + content_w;
17785 if (alloc_h > content_h)
17787 box->y1 += (alloc_h - content_h);
17788 box->y2 = box->y1 + content_h;
17792 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17793 if (alloc_w > content_w)
17795 box->x1 += (alloc_w - content_w);
17796 box->x2 = box->x1 + content_w;
17798 if (alloc_h > content_h)
17800 box->y1 += (alloc_h - content_h);
17801 box->y2 = box->y1 + content_h;
17805 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17806 g_assert_not_reached ();
17809 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17811 double r_c = content_w / content_h;
17812 double r_a = alloc_w / alloc_h;
17821 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17822 box->y2 = box->y1 + (alloc_w * r_c);
17829 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17830 box->x2 = box->x1 + (alloc_h * r_c);
17840 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17841 box->x2 = box->x1 + (alloc_h * r_c);
17848 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17849 box->y2 = box->y1 + (alloc_w * r_c);
17858 * clutter_actor_set_content_scaling_filters:
17859 * @self: a #ClutterActor
17860 * @min_filter: the minification filter for the content
17861 * @mag_filter: the magnification filter for the content
17863 * Sets the minification and magnification filter to be applied when
17864 * scaling the #ClutterActor:content of a #ClutterActor.
17866 * The #ClutterActor:minification-filter will be used when reducing
17867 * the size of the content; the #ClutterActor:magnification-filter
17868 * will be used when increasing the size of the content.
17873 clutter_actor_set_content_scaling_filters (ClutterActor *self,
17874 ClutterScalingFilter min_filter,
17875 ClutterScalingFilter mag_filter)
17877 ClutterActorPrivate *priv;
17881 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17884 obj = G_OBJECT (self);
17886 g_object_freeze_notify (obj);
17890 if (priv->min_filter != min_filter)
17892 priv->min_filter = min_filter;
17895 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17898 if (priv->mag_filter != mag_filter)
17900 priv->mag_filter = mag_filter;
17903 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17907 clutter_actor_queue_redraw (self);
17909 g_object_thaw_notify (obj);
17913 * clutter_actor_get_content_scaling_filters:
17914 * @self: a #ClutterActor
17915 * @min_filter: (out) (allow-none): return location for the minification
17917 * @mag_filter: (out) (allow-none): return location for the magnification
17920 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
17925 clutter_actor_get_content_scaling_filters (ClutterActor *self,
17926 ClutterScalingFilter *min_filter,
17927 ClutterScalingFilter *mag_filter)
17929 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17931 if (min_filter != NULL)
17932 *min_filter = self->priv->min_filter;
17934 if (mag_filter != NULL)
17935 *mag_filter = self->priv->mag_filter;