1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Copyright (C) 2012 Intel Corporation
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20  *
21  * Author: Emmanuele Bassi <ebassi@linux.intel.com>
22  */
23 
24 /**
25  * SECTION:clutter-transition-group
26  * @Title: ClutterTransitionGroup
27  * @Short_Description: Group transitions together
28  *
29  * The #ClutterTransitionGroup allows running multiple #ClutterTransition
30  * instances concurrently.
31  *
32  * The transitions inside a group will run within the boundaries of the
33  * group; for instance, if a transition has a duration of 10 seconds, and
34  * the group that contains it has a duration of 5 seconds, only the first
35  * 5 seconds of the transition will be played.
36  *
37  * #ClutterTransitionGroup is available since Clutter 1.12
38  */
39 
40 #include "clutter-build-config.h"
41 
42 #include "clutter-transition-group.h"
43 
44 #include "clutter-debug.h"
45 #include "clutter-private.h"
46 #include "clutter-timeline-private.h"
47 
48 struct _ClutterTransitionGroupPrivate
49 {
50   GHashTable *transitions;
51 };
52 
G_DEFINE_TYPE_WITH_PRIVATE(ClutterTransitionGroup,clutter_transition_group,CLUTTER_TYPE_TRANSITION)53 G_DEFINE_TYPE_WITH_PRIVATE (ClutterTransitionGroup, clutter_transition_group, CLUTTER_TYPE_TRANSITION)
54 
55 static void
56 clutter_transition_group_new_frame (ClutterTimeline *timeline,
57                                     gint             elapsed)
58 {
59   ClutterTransitionGroupPrivate *priv;
60   GHashTableIter iter;
61   gpointer element;
62   gint64 msecs;
63 
64   priv = CLUTTER_TRANSITION_GROUP (timeline)->priv;
65 
66   /* get the time elapsed since the last ::new-frame... */
67   msecs = clutter_timeline_get_delta (timeline);
68 
69   g_hash_table_iter_init (&iter, priv->transitions);
70   while (g_hash_table_iter_next (&iter, &element, NULL))
71     {
72       ClutterTimeline *t = element;
73 
74       /* ... and advance every timeline */
75       clutter_timeline_set_direction (t, clutter_timeline_get_direction (timeline));
76       clutter_timeline_set_duration (t, clutter_timeline_get_duration (timeline));
77 
78       _clutter_timeline_advance (t, msecs);
79     }
80 }
81 
82 static void
clutter_transition_group_attached(ClutterTransition * transition,ClutterAnimatable * animatable)83 clutter_transition_group_attached (ClutterTransition *transition,
84                                    ClutterAnimatable *animatable)
85 {
86   ClutterTransitionGroupPrivate *priv;
87   GHashTableIter iter;
88   gpointer element;
89 
90   priv = CLUTTER_TRANSITION_GROUP (transition)->priv;
91 
92   g_hash_table_iter_init (&iter, priv->transitions);
93   while (g_hash_table_iter_next (&iter, &element, NULL))
94     {
95       ClutterTransition *t = element;
96 
97       clutter_transition_set_animatable (t, animatable);
98     }
99 }
100 
101 static void
clutter_transition_group_detached(ClutterTransition * transition,ClutterAnimatable * animatable)102 clutter_transition_group_detached (ClutterTransition *transition,
103                                    ClutterAnimatable *animatable)
104 {
105   ClutterTransitionGroupPrivate *priv;
106   GHashTableIter iter;
107   gpointer element;
108 
109   priv = CLUTTER_TRANSITION_GROUP (transition)->priv;
110 
111   g_hash_table_iter_init (&iter, priv->transitions);
112   while (g_hash_table_iter_next (&iter, &element, NULL))
113     {
114       ClutterTransition *t = element;
115 
116       clutter_transition_set_animatable (t, NULL);
117     }
118 }
119 
120 static void
clutter_transition_group_started(ClutterTimeline * timeline)121 clutter_transition_group_started (ClutterTimeline *timeline)
122 {
123   ClutterTransitionGroupPrivate *priv;
124   GHashTableIter iter;
125   gpointer element;
126 
127   priv = CLUTTER_TRANSITION_GROUP (timeline)->priv;
128 
129   g_hash_table_iter_init (&iter, priv->transitions);
130   while (g_hash_table_iter_next (&iter, &element, NULL))
131     {
132       ClutterTransition *t = element;
133 
134       g_signal_emit_by_name (t, "started");
135     }
136 }
137 
138 static void
clutter_transition_group_finalize(GObject * gobject)139 clutter_transition_group_finalize (GObject *gobject)
140 {
141   ClutterTransitionGroupPrivate *priv;
142 
143   priv = CLUTTER_TRANSITION_GROUP (gobject)->priv;
144 
145   g_hash_table_unref (priv->transitions);
146 
147   G_OBJECT_CLASS (clutter_transition_group_parent_class)->finalize (gobject);
148 }
149 
150 static void
clutter_transition_group_class_init(ClutterTransitionGroupClass * klass)151 clutter_transition_group_class_init (ClutterTransitionGroupClass *klass)
152 {
153   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
154   ClutterTimelineClass *timeline_class = CLUTTER_TIMELINE_CLASS (klass);
155   ClutterTransitionClass *transition_class = CLUTTER_TRANSITION_CLASS (klass);
156 
157   gobject_class->finalize = clutter_transition_group_finalize;
158 
159   timeline_class->started = clutter_transition_group_started;
160   timeline_class->new_frame = clutter_transition_group_new_frame;
161 
162   transition_class->attached = clutter_transition_group_attached;
163   transition_class->detached = clutter_transition_group_detached;
164 }
165 
166 static void
clutter_transition_group_init(ClutterTransitionGroup * self)167 clutter_transition_group_init (ClutterTransitionGroup *self)
168 {
169   self->priv = clutter_transition_group_get_instance_private (self);
170   self->priv->transitions =
171     g_hash_table_new_full (NULL, NULL, (GDestroyNotify) g_object_unref, NULL);
172 }
173 
174 /**
175  * clutter_transition_group_new:
176  *
177  * Creates a new #ClutterTransitionGroup instance.
178  *
179  * Return value: the newly created #ClutterTransitionGroup. Use
180  *   g_object_unref() when done to deallocate the resources it
181  *   uses
182  *
183  * Since: 1.12
184  */
185 ClutterTransition *
clutter_transition_group_new(void)186 clutter_transition_group_new (void)
187 {
188   return g_object_new (CLUTTER_TYPE_TRANSITION_GROUP, NULL);
189 }
190 
191 /**
192  * clutter_transition_group_add_transition:
193  * @group: a #ClutterTransitionGroup
194  * @transition: a #ClutterTransition
195  *
196  * Adds @transition to @group.
197  *
198  * This function acquires a reference on @transition that will be released
199  * when calling clutter_transition_group_remove_transition().
200  *
201  * Since: 1.12
202  */
203 void
clutter_transition_group_add_transition(ClutterTransitionGroup * group,ClutterTransition * transition)204 clutter_transition_group_add_transition (ClutterTransitionGroup *group,
205                                          ClutterTransition      *transition)
206 {
207   g_return_if_fail (CLUTTER_IS_TRANSITION_GROUP (group));
208   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
209 
210   g_hash_table_add (group->priv->transitions, g_object_ref (transition));
211 }
212 
213 /**
214  * clutter_transition_group_remove_transition:
215  * @group: a #ClutterTransitionGroup
216  * @transition: a #ClutterTransition
217  *
218  * Removes @transition from @group.
219  *
220  * This function releases the reference acquired on @transition when
221  * calling clutter_transition_group_add_transition().
222  *
223  * Since: 1.12
224  */
225 void
clutter_transition_group_remove_transition(ClutterTransitionGroup * group,ClutterTransition * transition)226 clutter_transition_group_remove_transition (ClutterTransitionGroup *group,
227                                             ClutterTransition      *transition)
228 {
229   g_return_if_fail (CLUTTER_IS_TRANSITION_GROUP (group));
230 
231   g_hash_table_remove (group->priv->transitions, transition);
232 }
233 
234 /**
235  * clutter_transition_group_remove_all:
236  * @group: a #ClutterTransitionGroup
237  *
238  * Removes all transitions from @group.
239  *
240  * This function releases the reference acquired when calling
241  * clutter_transition_group_add_transition().
242  *
243  * Since: 1.12
244  */
245 void
clutter_transition_group_remove_all(ClutterTransitionGroup * group)246 clutter_transition_group_remove_all (ClutterTransitionGroup *group)
247 {
248   g_return_if_fail (CLUTTER_IS_TRANSITION_GROUP (group));
249 
250   g_hash_table_remove_all (group->priv->transitions);
251 }
252