GESTimelineLayer: Fix reference handling of objects, add docs.
[platform/upstream/gstreamer.git] / ges / ges-timeline-layer.c
1 /* GStreamer Editing Services
2  * Copyright (C) 2009 Edward Hervey <bilboed@bilboed.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:ges-timeline-layer
22  * @short_description: Non-overlaping sequence of #GESTimelineObject
23  *
24  * Responsible for the ordering of the various contained TimelineObject(s)
25  */
26
27 #include "ges-internal.h"
28 #include "gesmarshal.h"
29 #include "ges-timeline-layer.h"
30 #include "ges.h"
31
32 G_DEFINE_TYPE (GESTimelineLayer, ges_timeline_layer, G_TYPE_OBJECT);
33
34 enum
35 {
36   OBJECT_ADDED,
37   OBJECT_REMOVED,
38   LAST_SIGNAL
39 };
40
41 static guint ges_timeline_layer_signals[LAST_SIGNAL] = { 0 };
42
43 static void
44 ges_timeline_layer_get_property (GObject * object, guint property_id,
45     GValue * value, GParamSpec * pspec)
46 {
47   switch (property_id) {
48     default:
49       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
50   }
51 }
52
53 static void
54 ges_timeline_layer_set_property (GObject * object, guint property_id,
55     const GValue * value, GParamSpec * pspec)
56 {
57   switch (property_id) {
58     default:
59       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
60   }
61 }
62
63 static void
64 ges_timeline_layer_dispose (GObject * object)
65 {
66   GESTimelineLayer *layer = GES_TIMELINE_LAYER (object);
67
68   if (layer->objects_start) {
69     g_slist_foreach (layer->objects_start, (GFunc) g_object_unref, NULL);
70     g_slist_free (layer->objects_start);
71     layer->objects_start = NULL;
72   }
73   G_OBJECT_CLASS (ges_timeline_layer_parent_class)->dispose (object);
74 }
75
76 static void
77 ges_timeline_layer_finalize (GObject * object)
78 {
79   G_OBJECT_CLASS (ges_timeline_layer_parent_class)->finalize (object);
80 }
81
82 static void
83 ges_timeline_layer_class_init (GESTimelineLayerClass * klass)
84 {
85   GObjectClass *object_class = G_OBJECT_CLASS (klass);
86
87   object_class->get_property = ges_timeline_layer_get_property;
88   object_class->set_property = ges_timeline_layer_set_property;
89   object_class->dispose = ges_timeline_layer_dispose;
90   object_class->finalize = ges_timeline_layer_finalize;
91
92   ges_timeline_layer_signals[OBJECT_ADDED] =
93       g_signal_new ("object-added", G_TYPE_FROM_CLASS (klass),
94       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESTimelineLayerClass, object_added),
95       NULL, NULL, ges_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
96       GES_TYPE_TIMELINE_OBJECT);
97
98   ges_timeline_layer_signals[OBJECT_REMOVED] =
99       g_signal_new ("object-removed", G_TYPE_FROM_CLASS (klass),
100       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESTimelineLayerClass,
101           object_removed), NULL, NULL, ges_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
102       GES_TYPE_TIMELINE_OBJECT);
103
104 }
105
106 static void
107 ges_timeline_layer_init (GESTimelineLayer * self)
108 {
109 }
110
111 GESTimelineLayer *
112 ges_timeline_layer_new (void)
113 {
114   return g_object_new (GES_TYPE_TIMELINE_LAYER, NULL);
115 }
116
117 void
118 ges_timeline_layer_set_timeline (GESTimelineLayer * layer,
119     GESTimeline * timeline)
120 {
121   GST_DEBUG ("layer:%p, timeline:%p", layer, timeline);
122
123   layer->timeline = timeline;
124 }
125
126 static gint
127 objects_start_compare (GESTimelineObject * a, GESTimelineObject * b)
128 {
129   if (a->start == b->start) {
130     if (a->priority < b->priority)
131       return -1;
132     if (a->priority > b->priority)
133       return 1;
134     return 0;
135   }
136   if (a->start < b->start)
137     return -1;
138   if (a->start > b->start)
139     return 1;
140   return 0;
141 }
142
143 /**
144  * ges_timeline_layer_add_object:
145  * @layer: a #GESTimelineLayer
146  * @object: the #GESTimelineObject to add.
147  *
148  * Adds the object to the layer. The layer will steal a reference to the
149  * provided object.
150  *
151  * Returns: TRUE if the object was properly added to the layer, or FALSE
152  * if the @layer refused to add the object.
153  */
154
155 gboolean
156 ges_timeline_layer_add_object (GESTimelineLayer * layer,
157     GESTimelineObject * object)
158 {
159   GST_DEBUG ("layer:%p, object:%p", layer, object);
160
161   if (G_UNLIKELY (object->layer)) {
162     GST_WARNING ("TimelineObject %p already belongs to another layer");
163     return FALSE;
164   }
165
166   /* Take a reference to the object and store it stored by start/priority */
167   layer->objects_start =
168       g_slist_insert_sorted (layer->objects_start, object,
169       (GCompareFunc) objects_start_compare);
170
171   /* Inform the object it's now in this layer */
172   ges_timeline_object_set_layer (object, layer);
173
174   /* emit 'object-added' */
175   g_signal_emit (layer, ges_timeline_layer_signals[OBJECT_ADDED], 0, object);
176
177   return TRUE;
178 }
179
180 /**
181  * ges_timeline_layer_remove_object:
182  * @layer: a #GESTimelineLayer
183  * @object: the #GESTimelineObject to remove
184  *
185  * Removes the given @object from the @layer. The reference stolen by the @layer
186  * when the object was added will be removed. If you wish to use the object after
187  * this function, make sure you take an extra reference to the object before
188  * calling this function.
189  *
190  * Returns: TRUE if the object was properly remove, else FALSE.
191  */
192 gboolean
193 ges_timeline_layer_remove_object (GESTimelineLayer * layer,
194     GESTimelineObject * object)
195 {
196   GST_DEBUG ("layer:%p, object:%p", layer, object);
197
198   if (G_UNLIKELY (object->layer != layer)) {
199     GST_WARNING ("TimelineObject doesn't belong to this layer");
200     return FALSE;
201   }
202
203   /* emit 'object-removed' */
204   g_signal_emit (layer, ges_timeline_layer_signals[OBJECT_REMOVED], 0, object);
205
206   /* inform the object it's no longer in a layer */
207   ges_timeline_object_set_layer (object, NULL);
208
209   /* Remove it from our list of controlled objects */
210   layer->objects_start = g_slist_remove (layer->objects_start, object);
211
212   /* Remove our reference to the object */
213   g_object_unref (object);
214
215   return TRUE;
216 }