2 * Copyright (C) 2005 Stefan Kost <ensonic@users.sf.net>
4 * gstchildproxy.c: interface for multi child elements
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.
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.
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.
23 * SECTION:gstchildproxy
24 * @short_description: Interface for multi child elements.
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
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().
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.
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.
49 #include "gst_private.h"
51 #include "gstchildproxy.h"
52 #include "gstmarshal.h"
53 #include <gobject/gvaluecollector.h>
63 static guint signals[LAST_SIGNAL] = { 0 };
66 * gst_child_proxy_get_child_by_name:
67 * @parent: the parent object to get the child from
68 * @name: the childs name
70 * Looks up a child element by the given name.
72 * Implementors can use #GstObject together with gst_object_get_name()
74 * Returns: the child object or %NULL if not found. Unref after usage.
79 gst_child_proxy_get_child_by_name (GstChildProxy * parent, const gchar * name)
82 GstObject *object, *result;
85 g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), NULL);
86 g_return_val_if_fail (name != NULL, NULL);
90 count = gst_child_proxy_get_children_count (parent);
91 for (i = 0; i < count; i++) {
94 if (!(object = gst_child_proxy_get_child_by_index (parent, i)))
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));
103 eq = g_str_equal (object_name, name);
104 g_free (object_name);
111 gst_object_unref (object);
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
121 * Fetches a child by its number.
123 * Returns: the child object or %NULL if not found (index too high). Unref
129 gst_child_proxy_get_child_by_index (GstChildProxy * parent, guint index)
131 g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), NULL);
133 return (GST_CHILD_PROXY_GET_INTERFACE (parent)->get_child_by_index (parent,
138 * gst_child_proxy_get_children_count:
139 * @parent: the parent object
141 * Gets the number of child objects this parent contains.
143 * Returns: the number of child objects
148 gst_child_proxy_get_children_count (GstChildProxy * parent)
150 g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), 0);
152 return (GST_CHILD_PROXY_GET_INTERFACE (parent)->get_children_count (parent));
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
162 * Looks up which object and #GParamSpec would be effected by the given @name.
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
171 gst_child_proxy_lookup (GstObject * object, const gchar * name,
172 GstObject ** target, GParamSpec ** pspec)
174 gboolean res = FALSE;
175 gchar **names, **current;
177 g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
178 g_return_val_if_fail (name != NULL, FALSE);
180 gst_object_ref (object);
182 current = names = g_strsplit (name, "::", -1);
186 if (!GST_IS_CHILD_PROXY (object)) {
188 ("object %s is not a parent, so you cannot request a child by name %s",
189 GST_OBJECT_NAME (object), current[0]);
192 next = gst_child_proxy_get_child_by_name (GST_CHILD_PROXY (object),
195 GST_INFO ("no such object %s", current[0]);
198 gst_object_unref (object);
202 if (current[1] == NULL) {
204 g_object_class_find_property (G_OBJECT_GET_CLASS (object), current[0]);
206 GST_INFO ("no param spec named %s", current[0]);
211 gst_object_ref (object);
217 gst_object_unref (object);
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.
228 * Gets a single property using the GstChildProxy mechanism.
229 * You are responsible for for freeing it by calling g_value_unset()
232 gst_child_proxy_get_property (GstObject * object, const gchar * name,
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));
242 if (!gst_child_proxy_lookup (object, name, &target, &pspec))
245 g_object_get_property (G_OBJECT (target), pspec->name, value);
246 gst_object_unref (target);
252 g_warning ("no property %s in object %s", name, GST_OBJECT_NAME (object));
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
263 * Gets properties of the parent object and its children.
266 gst_child_proxy_get_valist (GstObject * object,
267 const gchar * first_property_name, va_list var_args)
271 GValue value = { 0, };
275 g_return_if_fail (G_IS_OBJECT (object));
277 name = first_property_name;
279 /* iterate over pairs */
281 if (!gst_child_proxy_lookup (object, name, &target, &pspec))
284 g_value_init (&value, pspec->value_type);
285 g_object_get_property (G_OBJECT (target), pspec->name, &value);
286 gst_object_unref (target);
288 G_VALUE_LCOPY (&value, var_args, 0, &error);
291 g_value_unset (&value);
292 name = va_arg (var_args, gchar *);
298 g_warning ("no property %s in object %s", name, GST_OBJECT_NAME (object));
303 g_warning ("error copying value %s in object %s: %s", pspec->name,
304 GST_OBJECT_NAME (object), error);
305 g_value_unset (&value);
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
316 * Gets properties of the parent object and its children.
319 gst_child_proxy_get (GstObject * object, const gchar * first_property_name, ...)
323 g_return_if_fail (GST_IS_OBJECT (object));
325 va_start (var_args, first_property_name);
326 gst_child_proxy_get_valist (object, first_property_name, var_args);
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
336 * Sets a single property using the GstChildProxy mechanism.
339 gst_child_proxy_set_property (GstObject * object, const gchar * name,
340 const GValue * value)
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));
349 if (!gst_child_proxy_lookup (object, name, &target, &pspec))
352 g_object_set_property (G_OBJECT (target), pspec->name, value);
353 gst_object_unref (target);
358 g_warning ("cannot set property %s on object %s", name,
359 GST_OBJECT_NAME (object));
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
370 * Sets properties of the parent object and its children.
373 gst_child_proxy_set_valist (GstObject * object,
374 const gchar * first_property_name, va_list var_args)
378 GValue value = { 0, };
382 g_return_if_fail (G_IS_OBJECT (object));
384 name = first_property_name;
386 /* iterate over pairs */
388 if (!gst_child_proxy_lookup (object, name, &target, &pspec))
391 #ifndef G_VALUE_COLLECT_INIT
392 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
393 G_VALUE_COLLECT (&value, var_args, G_VALUE_NOCOPY_CONTENTS, &error);
395 G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args,
396 G_VALUE_NOCOPY_CONTENTS, &error);
401 g_object_set_property (G_OBJECT (target), pspec->name, &value);
402 gst_object_unref (target);
404 g_value_unset (&value);
405 name = va_arg (var_args, gchar *);
411 g_warning ("no property %s in object %s", name, GST_OBJECT_NAME (object));
416 g_warning ("error copying value %s in object %s: %s", pspec->name,
417 GST_OBJECT_NAME (object), error);
418 g_value_unset (&value);
419 gst_object_unref (target);
425 * gst_child_proxy_set:
426 * @object: the parent object
427 * @first_property_name: name of the first property to set
428 * @...: value for the first property, followed optionally by more name/value pairs, followed by NULL
430 * Sets properties of the parent object and its children.
433 gst_child_proxy_set (GstObject * object, const gchar * first_property_name, ...)
437 g_return_if_fail (GST_IS_OBJECT (object));
439 va_start (var_args, first_property_name);
440 gst_child_proxy_set_valist (object, first_property_name, var_args);
445 * gst_child_proxy_child_added:
446 * @object: the parent object
447 * @child: the newly added child
449 * Emits the "child-added" signal.
452 gst_child_proxy_child_added (GstObject * object, GstObject * child)
454 g_signal_emit (G_OBJECT (object), signals[CHILD_ADDED], 0, child);
458 * gst_child_proxy_child_removed:
459 * @object: the parent object
460 * @child: the removed child
462 * Emits the "child-removed" signal.
465 gst_child_proxy_child_removed (GstObject * object, GstObject * child)
467 g_signal_emit (G_OBJECT (object), signals[CHILD_REMOVED], 0, child);
470 /* gobject methods */
473 gst_child_proxy_base_init (gpointer g_class)
475 static gboolean initialized = FALSE;
478 /* create interface signals and properties here. */
480 * GstChildProxy::child-added:
481 * @child_proxy: the #GstChildProxy
482 * @object: the #GObject that was added
484 * Will be emitted after the @object was added to the @child_proxy.
486 /* FIXME 0.11: use GST_TYPE_OBJECT as GstChildProxy only
487 * supports GstObjects */
488 signals[CHILD_ADDED] =
489 g_signal_new ("child-added", G_TYPE_FROM_CLASS (g_class),
490 G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstChildProxyInterface,
491 child_added), NULL, NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
495 * GstChildProxy::child-removed:
496 * @child_proxy: the #GstChildProxy
497 * @object: the #GObject that was removed
499 * Will be emitted after the @object was removed from the @child_proxy.
501 /* FIXME 0.11: use GST_TYPE_OBJECT as GstChildProxy only
502 * supports GstObjects */
503 signals[CHILD_REMOVED] =
504 g_signal_new ("child-removed", G_TYPE_FROM_CLASS (g_class),
505 G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstChildProxyInterface,
506 child_removed), NULL, NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE,
514 gst_child_proxy_get_type (void)
516 static volatile gsize type = 0;
518 if (g_once_init_enter (&type)) {
520 static const GTypeInfo info = {
521 sizeof (GstChildProxyInterface),
522 gst_child_proxy_base_init, /* base_init */
523 NULL, /* base_finalize */
524 NULL, /* class_init */
525 NULL, /* class_finalize */
526 NULL, /* class_data */
529 NULL /* instance_init */
533 g_type_register_static (G_TYPE_INTERFACE, "GstChildProxy", &info, 0);
535 g_type_interface_add_prerequisite (_type, GST_TYPE_OBJECT);
536 g_once_init_leave (&type, (gsize) _type);