gstreamer: remove unneeded casts
[platform/upstream/gstreamer.git] / gst / gstchildproxy.c
1 /* GStreamer
2  * Copyright (C) 2005 Stefan Kost <ensonic@users.sf.net>
3  *
4  * gstchildproxy.c: interface for multi child elements
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /**
23  * SECTION:gstchildproxy
24  * @short_description: Interface for multi child elements.
25  * @see_also: #GstBin
26  *
27  * This interface abstracts handling of property sets for elements with
28  * children. Imagine elements such as mixers or polyphonic generators. They all
29  * have multiple #GstPad or some kind of voice objects. Another use case are
30  * container elements like #GstBin.
31  * The element implementing the interface acts as a parent for those child
32  * objects.
33  *
34  * By implementing this interface the child properties can be accessed from the
35  * parent element by using gst_child_proxy_get() and gst_child_proxy_set().
36  *
37  * Property names are written as "child-name::property-name". The whole naming
38  * scheme is recursive. Thus "child1::child2::property" is valid too, if
39  * "child1" and "child2" implement the #GstChildProxy interface.
40  */
41 /* FIXME-0.11:
42  * it would be nice to make gst_child_proxy_get_child_by_name virtual too and
43  * use GObject instead of GstObject. We could eventually provide the current
44  * implementation as a default if children are GstObjects.
45  * This change would allow to propose the interface for inclusion with
46  * glib/gobject. IMHO this is useful for GtkContainer and compound widgets too.
47  */
48
49 #include "gst_private.h"
50
51 #include "gstchildproxy.h"
52 #include "gstmarshal.h"
53 #include <gobject/gvaluecollector.h>
54
55 /* signals */
56 enum
57 {
58   CHILD_ADDED,
59   CHILD_REMOVED,
60   LAST_SIGNAL
61 };
62
63 static guint signals[LAST_SIGNAL] = { 0 };
64
65 /**
66  * gst_child_proxy_get_child_by_name:
67  * @parent: the parent object to get the child from
68  * @name: the childs name
69  *
70  * Looks up a child element by the given name.
71  *
72  * Implementors can use #GstObject together with gst_object_get_name()
73  *
74  * Returns: the child object or %NULL if not found. Unref after usage.
75  *
76  * MT safe.
77  */
78 GstObject *
79 gst_child_proxy_get_child_by_name (GstChildProxy * parent, const gchar * name)
80 {
81   guint count, i;
82   GstObject *object, *result;
83   gchar *object_name;
84
85   g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), NULL);
86   g_return_val_if_fail (name != NULL, NULL);
87
88   result = NULL;
89
90   count = gst_child_proxy_get_children_count (parent);
91   for (i = 0; i < count; i++) {
92     gboolean eq;
93
94     if (!(object = gst_child_proxy_get_child_by_index (parent, i)))
95       continue;
96
97     object_name = gst_object_get_name (object);
98     if (object_name == NULL) {
99       g_warning ("child %u of parent %s has no name", i,
100           GST_OBJECT_NAME (parent));
101       goto next;
102     }
103     eq = g_str_equal (object_name, name);
104     g_free (object_name);
105
106     if (eq) {
107       result = object;
108       break;
109     }
110   next:
111     gst_object_unref (object);
112   }
113   return result;
114 }
115
116 /**
117  * gst_child_proxy_get_child_by_index:
118  * @parent: the parent object to get the child from
119  * @index: the childs position in the child list
120  *
121  * Fetches a child by its number.
122  *
123  * Returns: the child object or %NULL if not found (index too high). Unref
124  * after usage.
125  *
126  * MT safe.
127  */
128 GstObject *
129 gst_child_proxy_get_child_by_index (GstChildProxy * parent, guint index)
130 {
131   g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), NULL);
132
133   return (GST_CHILD_PROXY_GET_INTERFACE (parent)->get_child_by_index (parent,
134           index));
135 }
136
137 /**
138  * gst_child_proxy_get_children_count:
139  * @parent: the parent object
140  *
141  * Gets the number of child objects this parent contains.
142  *
143  * Returns: the number of child objects
144  *
145  * MT safe.
146  */
147 guint
148 gst_child_proxy_get_children_count (GstChildProxy * parent)
149 {
150   g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), 0);
151
152   return (GST_CHILD_PROXY_GET_INTERFACE (parent)->get_children_count (parent));
153 }
154
155 /**
156  * gst_child_proxy_lookup:
157  * @object: object to lookup the property in
158  * @name: name of the property to look up
159  * @target: pointer to a #GstObject that takes the real object to set property on
160  * @pspec: pointer to take the #GParamSpec describing the property
161  *
162  * Looks up which object and #GParamSpec would be effected by the given @name.
163  *
164  * Returns: TRUE if @target and @pspec could be found. FALSE otherwise. In that
165  * case the values for @pspec and @target are not modified. Unref @target after
166  * usage.
167  *
168  * MT safe.
169  */
170 gboolean
171 gst_child_proxy_lookup (GstObject * object, const gchar * name,
172     GstObject ** target, GParamSpec ** pspec)
173 {
174   gboolean res = FALSE;
175   gchar **names, **current;
176
177   g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
178   g_return_val_if_fail (name != NULL, FALSE);
179
180   gst_object_ref (object);
181
182   current = names = g_strsplit (name, "::", -1);
183   while (current[1]) {
184     GstObject *next;
185
186     if (!GST_IS_CHILD_PROXY (object)) {
187       GST_INFO
188           ("object %s is not a parent, so you cannot request a child by name %s",
189           GST_OBJECT_NAME (object), current[0]);
190       break;
191     }
192     next = gst_child_proxy_get_child_by_name (GST_CHILD_PROXY (object),
193         current[0]);
194     if (!next) {
195       GST_INFO ("no such object %s", current[0]);
196       break;
197     }
198     gst_object_unref (object);
199     object = next;
200     current++;
201   }
202   if (current[1] == NULL) {
203     GParamSpec *spec =
204         g_object_class_find_property (G_OBJECT_GET_CLASS (object), current[0]);
205     if (spec == NULL) {
206       GST_INFO ("no param spec named %s", current[0]);
207     } else {
208       if (pspec)
209         *pspec = spec;
210       if (target) {
211         gst_object_ref (object);
212         *target = object;
213       }
214       res = TRUE;
215     }
216   }
217   gst_object_unref (object);
218   g_strfreev (names);
219   return res;
220 }
221
222 /**
223  * gst_child_proxy_get_property:
224  * @object: object to query
225  * @name: name of the property
226  * @value: a #GValue that should take the result.
227  *
228  * Gets a single property using the GstChildProxy mechanism.
229  * You are responsible for for freeing it by calling g_value_unset()
230  */
231 void
232 gst_child_proxy_get_property (GstObject * object, const gchar * name,
233     GValue * value)
234 {
235   GParamSpec *pspec;
236   GstObject *target;
237
238   g_return_if_fail (GST_IS_OBJECT (object));
239   g_return_if_fail (name != NULL);
240   g_return_if_fail (G_IS_VALUE (value));
241
242   if (!gst_child_proxy_lookup (object, name, &target, &pspec))
243     goto not_found;
244
245   g_object_get_property (G_OBJECT (target), pspec->name, value);
246   gst_object_unref (target);
247
248   return;
249
250 not_found:
251   {
252     g_warning ("no property %s in object %s", name, GST_OBJECT_NAME (object));
253     return;
254   }
255 }
256
257 /**
258  * gst_child_proxy_get_valist:
259  * @object: the object to query
260  * @first_property_name: name of the first property to get
261  * @var_args: return location for the first property, followed optionally by more name/return location pairs, followed by NULL
262  *
263  * Gets properties of the parent object and its children.
264  */
265 void
266 gst_child_proxy_get_valist (GstObject * object,
267     const gchar * first_property_name, va_list var_args)
268 {
269   const gchar *name;
270   gchar *error = NULL;
271   GValue value = { 0, };
272   GParamSpec *pspec;
273   GstObject *target;
274
275   g_return_if_fail (G_IS_OBJECT (object));
276
277   name = first_property_name;
278
279   /* iterate over pairs */
280   while (name) {
281     if (!gst_child_proxy_lookup (object, name, &target, &pspec))
282       goto not_found;
283
284     g_value_init (&value, pspec->value_type);
285     g_object_get_property (G_OBJECT (target), pspec->name, &value);
286     gst_object_unref (target);
287
288     G_VALUE_LCOPY (&value, var_args, 0, &error);
289     if (error)
290       goto cant_copy;
291     g_value_unset (&value);
292     name = va_arg (var_args, gchar *);
293   }
294   return;
295
296 not_found:
297   {
298     g_warning ("no property %s in object %s", name, GST_OBJECT_NAME (object));
299     return;
300   }
301 cant_copy:
302   {
303     g_warning ("error copying value %s in object %s: %s", pspec->name,
304         GST_OBJECT_NAME (object), error);
305     g_value_unset (&value);
306     return;
307   }
308 }
309
310 /**
311  * gst_child_proxy_get:
312  * @object: the parent object
313  * @first_property_name: name of the first property to get
314  * @...: return location for the first property, followed optionally by more name/return location pairs, followed by NULL
315  *
316  * Gets properties of the parent object and its children.
317  */
318 void
319 gst_child_proxy_get (GstObject * object, const gchar * first_property_name, ...)
320 {
321   va_list var_args;
322
323   g_return_if_fail (GST_IS_OBJECT (object));
324
325   va_start (var_args, first_property_name);
326   gst_child_proxy_get_valist (object, first_property_name, var_args);
327   va_end (var_args);
328 }
329
330 /**
331  * gst_child_proxy_set_property:
332  * @object: the parent object
333  * @name: name of the property to set
334  * @value: new #GValue for the property
335  *
336  * Sets a single property using the GstChildProxy mechanism.
337  */
338 void
339 gst_child_proxy_set_property (GstObject * object, const gchar * name,
340     const GValue * value)
341 {
342   GParamSpec *pspec;
343   GstObject *target;
344
345   g_return_if_fail (GST_IS_OBJECT (object));
346   g_return_if_fail (name != NULL);
347   g_return_if_fail (G_IS_VALUE (value));
348
349   if (!gst_child_proxy_lookup (object, name, &target, &pspec))
350     goto not_found;
351
352   g_object_set_property (G_OBJECT (target), pspec->name, value);
353   gst_object_unref (target);
354   return;
355
356 not_found:
357   {
358     g_warning ("cannot set property %s on object %s", name,
359         GST_OBJECT_NAME (object));
360     return;
361   }
362 }
363
364 /**
365  * gst_child_proxy_set_valist:
366  * @object: the parent object
367  * @first_property_name: name of the first property to set
368  * @var_args: value for the first property, followed optionally by more name/value pairs, followed by NULL
369  *
370  * Sets properties of the parent object and its children.
371  */
372 void
373 gst_child_proxy_set_valist (GstObject * object,
374     const gchar * first_property_name, va_list var_args)
375 {
376   const gchar *name;
377   gchar *error = NULL;
378   GValue value = { 0, };
379   GParamSpec *pspec;
380   GstObject *target;
381
382   g_return_if_fail (G_IS_OBJECT (object));
383
384   name = first_property_name;
385
386   /* iterate over pairs */
387   while (name) {
388     if (!gst_child_proxy_lookup (object, name, &target, &pspec))
389       goto not_found;
390
391     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
392     G_VALUE_COLLECT (&value, var_args, G_VALUE_NOCOPY_CONTENTS, &error);
393     if (error)
394       goto cant_copy;
395
396     g_object_set_property (G_OBJECT (target), pspec->name, &value);
397     gst_object_unref (target);
398
399     g_value_unset (&value);
400     name = va_arg (var_args, gchar *);
401   }
402   return;
403
404 not_found:
405   {
406     g_warning ("no property %s in object %s", name, GST_OBJECT_NAME (object));
407     return;
408   }
409 cant_copy:
410   {
411     g_warning ("error copying value %s in object %s: %s", pspec->name,
412         GST_OBJECT_NAME (object), error);
413     g_value_unset (&value);
414     gst_object_unref (target);
415     return;
416   }
417 }
418
419 /**
420  * gst_child_proxy_set:
421  * @object: the parent object
422  * @first_property_name: name of the first property to set
423  * @...: value for the first property, followed optionally by more name/value pairs, followed by NULL
424  *
425  * Sets properties of the parent object and its children.
426  */
427 void
428 gst_child_proxy_set (GstObject * object, const gchar * first_property_name, ...)
429 {
430   va_list var_args;
431
432   g_return_if_fail (GST_IS_OBJECT (object));
433
434   va_start (var_args, first_property_name);
435   gst_child_proxy_set_valist (object, first_property_name, var_args);
436   va_end (var_args);
437 }
438
439 /**
440  * gst_child_proxy_child_added:
441  * @object: the parent object
442  * @child: the newly added child
443  *
444  * Emits the "child-added" signal.
445  */
446 void
447 gst_child_proxy_child_added (GstObject * object, GstObject * child)
448 {
449   g_signal_emit (G_OBJECT (object), signals[CHILD_ADDED], 0, child);
450 }
451
452 /**
453  * gst_child_proxy_child_removed:
454  * @object: the parent object
455  * @child: the removed child
456  *
457  * Emits the "child-removed" signal.
458  */
459 void
460 gst_child_proxy_child_removed (GstObject * object, GstObject * child)
461 {
462   g_signal_emit (G_OBJECT (object), signals[CHILD_REMOVED], 0, child);
463 }
464
465 /* gobject methods */
466
467 static void
468 gst_child_proxy_base_init (gpointer g_class)
469 {
470   static gboolean initialized = FALSE;
471
472   if (!initialized) {
473     /* create interface signals and properties here. */
474         /**
475          * GstChildProxy::child-added:
476          * @child_proxy: the #GstChildProxy
477          * @object: the #GObject that was added
478          *
479          * Will be emitted after the @object was added to the @child_proxy.
480          */
481     /* FIXME 0.11: use GST_TYPE_OBJECT as GstChildProxy only
482      * supports GstObjects */
483     signals[CHILD_ADDED] =
484         g_signal_new ("child-added", G_TYPE_FROM_CLASS (g_class),
485         G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstChildProxyInterface,
486             child_added), NULL, NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
487         G_TYPE_OBJECT);
488
489         /**
490          * GstChildProxy::child-removed:
491          * @child_proxy: the #GstChildProxy
492          * @object: the #GObject that was removed
493          *
494          * Will be emitted after the @object was removed from the @child_proxy.
495          */
496     /* FIXME 0.11: use GST_TYPE_OBJECT as GstChildProxy only
497      * supports GstObjects */
498     signals[CHILD_REMOVED] =
499         g_signal_new ("child-removed", G_TYPE_FROM_CLASS (g_class),
500         G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstChildProxyInterface,
501             child_removed), NULL, NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE,
502         1, G_TYPE_OBJECT);
503
504     initialized = TRUE;
505   }
506 }
507
508 GType
509 gst_child_proxy_get_type (void)
510 {
511   static volatile gsize type = 0;
512
513   if (g_once_init_enter (&type)) {
514     GType _type;
515     static const GTypeInfo info = {
516       sizeof (GstChildProxyInterface),
517       gst_child_proxy_base_init,        /* base_init */
518       NULL,                     /* base_finalize */
519       NULL,                     /* class_init */
520       NULL,                     /* class_finalize */
521       NULL,                     /* class_data */
522       0,
523       0,                        /* n_preallocs */
524       NULL                      /* instance_init */
525     };
526
527     _type =
528         g_type_register_static (G_TYPE_INTERFACE, "GstChildProxy", &info, 0);
529
530     g_type_interface_add_prerequisite (_type, GST_TYPE_OBJECT);
531     g_once_init_leave (&type, (gsize) _type);
532   }
533   return type;
534 }