de2c119b1977bc79b91f35d3db88e40c42fda0ed
[glsdk/gstreamer0-10.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  * SECTION:gstchildproxy
23  * @short_description: Interface for multi child elements.
24  * @see_also: #GstBin
25  *
26  * This interface abstracts handling of property sets for child elements.
27  * Imagine elements such as mixers or polyphonic generators. They all have
28  * multiple #GstPads or some kind of voice objects. The element acts as a parent
29  * for those child objects. Each child has the same properties.
30  *
31  * By implementing this interface the child properties can be accessed from the
32  * parent element by using gst_child_proxy_get() and gst_child_proxy_set().
33  *
34  * Property names are written as "child-name::property-name". The whole naming
35  * scheme is recursive. Thus "child1::child2::property" is valid too, if
36  * "child1" also implements the #GstChildProxy interface.
37  */
39 #include "gst_private.h"
41 #include "gstchildproxy.h"
42 #include "gstmarshal.h"
43 #include <gobject/gvaluecollector.h>
45 /* signals */
46 enum
47 {
48   CHILD_ADDED,
49   CHILD_REMOVED,
50   LAST_SIGNAL
51 };
53 static guint signals[LAST_SIGNAL] = { 0 };
55 /**
56  * gst_child_proxy_get_child_by_name:
57  * @parent: the parent object to get the child from
58  * @name: the childs name
59  *
60  * Looks up a child element by the given name.
61  *
62  * Implementors can use #GstObject together with gst_object_get_name() 
63  *
64  * Returns: the child object or %NULL if not found
65  */
66 GstObject *
67 gst_child_proxy_get_child_by_name (GstChildProxy * parent, const gchar * name)
68 {
69   guint count, i;
70   GstObject *object;
71   const gchar *object_name;
73   g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), NULL);
74   g_return_val_if_fail (name != NULL, NULL);
76   count = gst_child_proxy_get_children_count (parent);
77   for (i = 0; i < count; i++) {
78     object = gst_child_proxy_get_child_by_index (parent, i);
79     object_name = gst_object_get_name (object);
80     if (object_name == NULL) {
81       g_warning ("child %u of parent %s has no name", i,
82           GST_OBJECT_NAME (parent));
83       continue;
84     }
85     if (g_str_equal (object_name, name))
86       return object;
87   }
88   return NULL;
89 }
91 /**
92  * gst_child_proxy_get_child_by_index:
93  * @parent: the parent object to get the child from
94  * @index: the childs position in the child list
95  *
96  * Fetches a child by its number.
97  *
98  * Returns: the child object or %NULL if not found (index too high)
99  */
100 GstObject *
101 gst_child_proxy_get_child_by_index (GstChildProxy * parent, guint index)
103   g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), NULL);
105   return (GST_CHILD_PROXY_GET_INTERFACE (parent)->get_child_by_index (parent,
106           index));
109 /**
110  * gst_child_proxy_get_children_count:
111  * @parent: the parent object
112  *
113  * Gets the number of child objects this parent contains.
114  *
115  * Returns: the number of child objects
116  */
117 guint
118 gst_child_proxy_get_children_count (GstChildProxy * parent)
120   g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), 0);
122   return (GST_CHILD_PROXY_GET_INTERFACE (parent)->get_children_count (parent));
125 /**
126  * gst_child_proxy_lookup:
127  * @object: object to lookup the property in
128  * @name: name of the property to look up
129  * @target: pointer to a #GstObject that takes the real object to set property on
130  * @pspec: pointer to take the #GParamSpec describing the property
131  *
132  * Looks up which object and #GParamSpec would be effected by the given @name.
133  *
134  * Returns: TRUE if @target and @pspec could be found. FALSE otherwise. In that 
135  * case the values for @pspec and @target are not modified
136  */
137 gboolean
138 gst_child_proxy_lookup (GstObject * object, const gchar * name,
139     GstObject ** target, GParamSpec ** pspec)
141   gboolean res = FALSE;
142   gchar **names, **current;
144   g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
145   g_return_val_if_fail (name != NULL, FALSE);
147   current = names = g_strsplit (name, "::", -1);
148   while (current[1]) {
149     if (!GST_IS_CHILD_PROXY (object)) {
150       GST_INFO
151           ("object %s is not a parent, so you cannot request a child by name %s",
152           GST_OBJECT_NAME (object), current[0]);
153       break;
154     }
155     object =
156         gst_child_proxy_get_child_by_name (GST_CHILD_PROXY (object),
157         current[0]);
158     if (!object) {
159       GST_INFO ("no such object %s", current[0]);
160       break;
161     }
162     current++;
163   };
164   if (current[1] == NULL) {
165     GParamSpec *spec =
166         g_object_class_find_property (G_OBJECT_GET_CLASS (object), current[0]);
167     if (spec == NULL) {
168       GST_INFO ("no param spec named %s", current[0]);
169     } else {
170       if (pspec)
171         *pspec = spec;
172       if (target)
173         *target = object;
174       res = TRUE;
175     }
176   }
177   g_strfreev (names);
178   return res;
181 /**
182  * gst_child_proxy_get_property:
183  * @object: object to query
184  * @name: name of the property
185  * @value: an uninitialized #GValue that should take the result. 
186  *
187  * Gets a single property using the GstChildProxy mechanism.
188  * You are responsible for for freeing it by calling g_value_unset()
189  */
190 void
191 gst_child_proxy_get_property (GstObject * object, const gchar * name,
192     GValue * value)
194   GParamSpec *pspec;
195   GstObject *target;
197   g_return_if_fail (GST_IS_OBJECT (object));
198   g_return_if_fail (name != NULL);
199   g_return_if_fail (!G_IS_VALUE (value));
201   if (!gst_child_proxy_lookup (object, name, &target, &pspec)) {
202     g_warning ("cannot get property %s from object %s", name,
203         GST_OBJECT_NAME (object));
204     return;
205   }
206   g_object_get_property (G_OBJECT (target), pspec->name, value);
209 /**
210  * gst_child_proxy_get_valist:
211  * @object: the object to query
212  * @first_property_name: name of the first property to get
213  * @var_args: return location for the first property, followed optionally by more name/return location pairs, followed by NULL
214  *
215  * Gets properties of the parent object and its children.
216  */
217 void
218 gst_child_proxy_get_valist (GstObject * object,
219     const gchar * first_property_name, va_list var_args)
221   const gchar *name;
222   gchar *error = NULL;
223   GValue value = { 0, };
225   g_return_if_fail (G_IS_OBJECT (object));
227   g_object_ref (object);
229   name = first_property_name;
231   /* iterate over pairs */
232   while (name) {
233     gst_child_proxy_get_property (object, name, &value);
234     G_VALUE_LCOPY (&value, var_args, 0, &error);
235     if (error) {
236       g_warning ("error copying value: %s", error);
237       return;
238     }
239     g_value_unset (&value);
240     name = va_arg (var_args, gchar *);
241   }
243   g_object_unref (object);
246 /**
247  * gst_child_proxy_get:
248  * @object: the parent object
249  * @first_property_name: name of the first property to get
250  * @...: return location for the first property, followed optionally by more name/return location pairs, followed by NULL
251  *
252  * Gets properties of the parent object and its children.
253  */
254 void
255 gst_child_proxy_get (GstObject * object, const gchar * first_property_name, ...)
257   va_list var_args;
259   g_return_if_fail (GST_IS_OBJECT (object));
261   va_start (var_args, first_property_name);
262   gst_child_proxy_get_valist (object, first_property_name, var_args);
263   va_end (var_args);
266 /**
267  * gst_child_proxy_set_property:
268  * @object: the parent object
269  * @name: name of the property to set
270  * @value: new #GValue for the property
271  *
272  * Sets a single property using the GstChildProxy mechanism.
273  */
274 void
275 gst_child_proxy_set_property (GstObject * object, const gchar * name,
276     const GValue * value)
278   GParamSpec *pspec;
279   GstObject *target;
281   g_return_if_fail (GST_IS_OBJECT (object));
282   g_return_if_fail (name != NULL);
283   g_return_if_fail (!G_IS_VALUE (value));
285   if (!gst_child_proxy_lookup (object, name, &target, &pspec)) {
286     g_warning ("cannot set property %s on object %s", name,
287         GST_OBJECT_NAME (object));
288     return;
289   }
290   g_object_set_property (G_OBJECT (target), pspec->name, value);
293 /**
294  * gst_child_proxy_set_valist:
295  * @object: the parent object
296  * @first_property_name: name of the first property to set
297  * @var_args: value for the first property, followed optionally by more name/value pairs, followed by NULL
298  *
299  * Sets properties of the parent object and its children.
300  */
301 void
302 gst_child_proxy_set_valist (GstObject * object,
303     const gchar * first_property_name, va_list var_args)
305   const gchar *name;
306   gchar *error = NULL;
307   GValue value = { 0, };
309   g_return_if_fail (G_IS_OBJECT (object));
311   g_object_ref (object);
313   name = first_property_name;
315   /* iterate over pairs */
316   while (name) {
317     GParamSpec *pspec;
318     GstObject *target;
320     if (!gst_child_proxy_lookup (object, name, &target, &pspec)) {
321       g_warning ("no such property %s in object %s", name,
322           GST_OBJECT_NAME (object));
323       g_object_unref (object);
324     }
325     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
326     G_VALUE_COLLECT (&value, var_args, G_VALUE_NOCOPY_CONTENTS, &error);
327     if (error) {
328       g_warning ("error copying value: %s", error);
329       g_object_unref (object);
330       return;
331     }
332     g_object_set_property (G_OBJECT (target), pspec->name, &value);
333     g_value_unset (&value);
334     name = va_arg (var_args, gchar *);
335   }
337   g_object_unref (object);
340 /**
341  * gst_child_proxy_set:
342  * @object: the parent object
343  * @first_property_name: name of the first property to set
344  * @...: value for the first property, followed optionally by more name/value pairs, followed by NULL
345  *
346  * Sets properties of the parent object and its children.
347  */
348 void
349 gst_child_proxy_set (GstObject * object, const gchar * first_property_name, ...)
351   va_list var_args;
353   g_return_if_fail (GST_IS_OBJECT (object));
355   va_start (var_args, first_property_name);
356   gst_child_proxy_set_valist (object, first_property_name, var_args);
357   va_end (var_args);
360 /**
361  * gst_child_proxy_child_added:
362  * @object: the parent object
363  * @child: the newly added child
364  * 
365  * Emits the "child-added" signal.
366  */
367 void
368 gst_child_proxy_child_added (GstObject * object, GstObject * child)
370   g_signal_emit (G_OBJECT (object), signals[CHILD_ADDED], 0, child);
373 /**
374  * gst_child_proxy_child_removed:
375  * @object: the parent object
376  * @child: the newly added child
377  * 
378  * Emits the "child-removed" signal.
379  */
380 void
381 gst_child_proxy_child_removed (GstObject * object, GstObject * child)
383   g_signal_emit (G_OBJECT (object), signals[CHILD_REMOVED], 0, child);
386 /* gobject methods */
388 static void
389 gst_child_proxy_base_init (gpointer g_class)
391   static gboolean initialized = FALSE;
393   if (!initialized) {
394     /* create interface signals and properties here. */
395     signals[CHILD_ADDED] =
396         g_signal_new ("child-added", G_TYPE_FROM_CLASS (g_class),
397         G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstChildProxyInterface,
398             child_added), NULL, NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
399         G_TYPE_OBJECT);
401     signals[CHILD_REMOVED] =
402         g_signal_new ("child-removed", G_TYPE_FROM_CLASS (g_class),
403         G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstChildProxyInterface,
404             child_removed), NULL, NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE,
405         1, G_TYPE_OBJECT);
407     initialized = TRUE;
408   }
411 GType
412 gst_child_proxy_get_type (void)
414   static GType type = 0;
416   if (type == 0) {
417     static const GTypeInfo info = {
418       sizeof (GstChildProxyInterface),
419       gst_child_proxy_base_init,        /* base_init */
420       NULL,                     /* base_finalize */
421       NULL,                     /* class_init */
422       NULL,                     /* class_finalize */
423       NULL,                     /* class_data */
424       0,
425       0,                        /* n_preallocs */
426       NULL                      /* instance_init */
427     };
428     type = g_type_register_static (G_TYPE_INTERFACE, "GstChildProxy", &info, 0);
430     g_type_interface_add_prerequisite (type, GST_TYPE_OBJECT);
431   }
432   return type;