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 #include "gst_private.h"
44 #include "gstchildproxy.h"
45 #include <gobject/gvaluecollector.h>
55 static guint signals[LAST_SIGNAL] = { 0 };
58 gst_child_proxy_default_get_child_by_name (GstChildProxy * parent,
62 GObject *object, *result;
65 g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), NULL);
66 g_return_val_if_fail (name != NULL, NULL);
70 count = gst_child_proxy_get_children_count (parent);
71 for (i = 0; i < count; i++) {
74 if (!(object = gst_child_proxy_get_child_by_index (parent, i)))
77 if (!GST_IS_OBJECT (object)) {
80 object_name = gst_object_get_name (GST_OBJECT_CAST (object));
81 if (object_name == NULL) {
82 g_warning ("child %u of parent %s has no name", i,
83 GST_OBJECT_NAME (parent));
86 eq = g_str_equal (object_name, name);
94 g_object_unref (object);
101 * gst_child_proxy_get_child_by_name:
102 * @parent: the parent object to get the child from
103 * @name: the childs name
105 * Looks up a child element by the given name.
107 * This virtual method has a default implementation that uses #GstObject
108 * together with gst_object_get_name(). If the interface is to be used with
109 * #GObjects, this methods needs to be overridden.
111 * Returns: (transfer full): the child object or %NULL if not found. Unref
117 gst_child_proxy_get_child_by_name (GstChildProxy * parent, const gchar * name)
119 g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), 0);
121 return (GST_CHILD_PROXY_GET_INTERFACE (parent)->get_child_by_name (parent,
126 * gst_child_proxy_get_child_by_index:
127 * @parent: the parent object to get the child from
128 * @index: the childs position in the child list
130 * Fetches a child by its number.
132 * Returns: (transfer full): the child object or %NULL if not found (index
133 * too high). Unref after usage.
138 gst_child_proxy_get_child_by_index (GstChildProxy * parent, guint index)
140 g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), NULL);
142 return (GST_CHILD_PROXY_GET_INTERFACE (parent)->get_child_by_index (parent,
147 * gst_child_proxy_get_children_count:
148 * @parent: the parent object
150 * Gets the number of child objects this parent contains.
152 * Returns: the number of child objects
157 gst_child_proxy_get_children_count (GstChildProxy * parent)
159 g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), 0);
161 return (GST_CHILD_PROXY_GET_INTERFACE (parent)->get_children_count (parent));
165 * gst_child_proxy_lookup:
166 * @object: object to lookup the property in
167 * @name: name of the property to look up
168 * @target: (out) (allow-none) (transfer full): pointer to a #GObject that
169 * takes the real object to set property on
170 * @pspec: (out) (allow-none) (transfer full): pointer to take the #GParamSpec
171 * describing the property
173 * Looks up which object and #GParamSpec would be effected by the given @name.
175 * Returns: TRUE if @target and @pspec could be found. FALSE otherwise. In that
176 * case the values for @pspec and @target are not modified. Unref @target after
182 gst_child_proxy_lookup (GObject * object, const gchar * name,
183 GObject ** target, GParamSpec ** pspec)
185 gboolean res = FALSE;
186 gchar **names, **current;
188 g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
189 g_return_val_if_fail (name != NULL, FALSE);
191 gst_object_ref (object);
193 current = names = g_strsplit (name, "::", -1);
197 if (!GST_IS_CHILD_PROXY (object)) {
199 ("object %s is not a parent, so you cannot request a child by name %s",
200 (GST_IS_OBJECT (object) ? GST_OBJECT_NAME (object) : ""), current[0]);
203 next = gst_child_proxy_get_child_by_name (GST_CHILD_PROXY (object),
206 GST_INFO ("no such object %s", current[0]);
209 gst_object_unref (object);
213 if (current[1] == NULL) {
215 g_object_class_find_property (G_OBJECT_GET_CLASS (object), current[0]);
217 GST_INFO ("no param spec named %s", current[0]);
222 gst_object_ref (object);
228 gst_object_unref (object);
234 * gst_child_proxy_get_property:
235 * @object: object to query
236 * @name: name of the property
237 * @value: (out caller-allocates): a #GValue that should take the result.
239 * Gets a single property using the GstChildProxy mechanism.
240 * You are responsible for freeing it by calling g_value_unset()
243 gst_child_proxy_get_property (GObject * object, const gchar * name,
249 g_return_if_fail (G_IS_OBJECT (object));
250 g_return_if_fail (name != NULL);
251 g_return_if_fail (G_IS_VALUE (value));
253 if (!gst_child_proxy_lookup (object, name, &target, &pspec))
256 g_object_get_property (G_OBJECT (target), pspec->name, value);
257 gst_object_unref (target);
263 g_warning ("no property %s in object %s", name,
264 (GST_IS_OBJECT (object) ? GST_OBJECT_NAME (object) : ""));
270 * gst_child_proxy_get_valist:
271 * @object: the object to query
272 * @first_property_name: name of the first property to get
273 * @var_args: return location for the first property, followed optionally by more name/return location pairs, followed by NULL
275 * Gets properties of the parent object and its children.
278 gst_child_proxy_get_valist (GObject * object,
279 const gchar * first_property_name, va_list var_args)
283 GValue value = { 0, };
287 g_return_if_fail (G_IS_OBJECT (object));
289 name = first_property_name;
291 /* iterate over pairs */
293 if (!gst_child_proxy_lookup (object, name, &target, &pspec))
296 g_value_init (&value, pspec->value_type);
297 g_object_get_property (G_OBJECT (target), pspec->name, &value);
298 gst_object_unref (target);
300 G_VALUE_LCOPY (&value, var_args, 0, &error);
303 g_value_unset (&value);
304 name = va_arg (var_args, gchar *);
310 g_warning ("no property %s in object %s", name,
311 (GST_IS_OBJECT (object) ? GST_OBJECT_NAME (object) : ""));
316 g_warning ("error copying value %s in object %s: %s", pspec->name,
317 (GST_IS_OBJECT (object) ? GST_OBJECT_NAME (object) : ""), error);
318 g_value_unset (&value);
324 * gst_child_proxy_get:
325 * @object: the parent object
326 * @first_property_name: name of the first property to get
327 * @...: return location for the first property, followed optionally by more name/return location pairs, followed by NULL
329 * Gets properties of the parent object and its children.
332 gst_child_proxy_get (GObject * object, const gchar * first_property_name, ...)
336 g_return_if_fail (G_IS_OBJECT (object));
338 va_start (var_args, first_property_name);
339 gst_child_proxy_get_valist (object, first_property_name, var_args);
344 * gst_child_proxy_set_property:
345 * @object: the parent object
346 * @name: name of the property to set
347 * @value: new #GValue for the property
349 * Sets a single property using the GstChildProxy mechanism.
352 gst_child_proxy_set_property (GObject * object, const gchar * name,
353 const GValue * value)
358 g_return_if_fail (G_IS_OBJECT (object));
359 g_return_if_fail (name != NULL);
360 g_return_if_fail (G_IS_VALUE (value));
362 if (!gst_child_proxy_lookup (object, name, &target, &pspec))
365 g_object_set_property (G_OBJECT (target), pspec->name, value);
366 gst_object_unref (target);
371 g_warning ("cannot set property %s on object %s", name,
372 (GST_IS_OBJECT (object) ? GST_OBJECT_NAME (object) : ""));
378 * gst_child_proxy_set_valist:
379 * @object: the parent object
380 * @first_property_name: name of the first property to set
381 * @var_args: value for the first property, followed optionally by more name/value pairs, followed by NULL
383 * Sets properties of the parent object and its children.
386 gst_child_proxy_set_valist (GObject * object,
387 const gchar * first_property_name, va_list var_args)
391 GValue value = { 0, };
395 g_return_if_fail (G_IS_OBJECT (object));
397 name = first_property_name;
399 /* iterate over pairs */
401 if (!gst_child_proxy_lookup (object, name, &target, &pspec))
404 G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args,
405 G_VALUE_NOCOPY_CONTENTS, &error);
410 g_object_set_property (G_OBJECT (target), pspec->name, &value);
411 gst_object_unref (target);
413 g_value_unset (&value);
414 name = va_arg (var_args, gchar *);
420 g_warning ("no property %s in object %s", name,
421 (GST_IS_OBJECT (object) ? GST_OBJECT_NAME (object) : ""));
426 g_warning ("error copying value %s in object %s: %s", pspec->name,
427 (GST_IS_OBJECT (object) ? GST_OBJECT_NAME (object) : ""), error);
428 g_value_unset (&value);
429 gst_object_unref (target);
435 * gst_child_proxy_set:
436 * @object: the parent object
437 * @first_property_name: name of the first property to set
438 * @...: value for the first property, followed optionally by more name/value pairs, followed by NULL
440 * Sets properties of the parent object and its children.
443 gst_child_proxy_set (GObject * object, const gchar * first_property_name, ...)
447 g_return_if_fail (G_IS_OBJECT (object));
449 va_start (var_args, first_property_name);
450 gst_child_proxy_set_valist (object, first_property_name, var_args);
455 * gst_child_proxy_child_added:
456 * @object: the parent object
457 * @child: the newly added child
458 * @name: the name of the new child
460 * Emits the "child-added" signal.
463 gst_child_proxy_child_added (GObject * object, GObject * child,
466 g_signal_emit (G_OBJECT (object), signals[CHILD_ADDED], 0, child, name);
470 * gst_child_proxy_child_removed:
471 * @object: the parent object
472 * @child: the removed child
473 * @name: the name of the old child
475 * Emits the "child-removed" signal.
478 gst_child_proxy_child_removed (GObject * object, GObject * child,
481 g_signal_emit (G_OBJECT (object), signals[CHILD_REMOVED], 0, child, name);
484 /* gobject methods */
487 gst_child_proxy_class_init (gpointer g_class, gpointer class_data)
489 GstChildProxyInterface *iface = (GstChildProxyInterface *) g_class;
491 iface->get_child_by_name = gst_child_proxy_default_get_child_by_name;
495 gst_child_proxy_base_init (gpointer g_class)
497 static gboolean initialized = FALSE;
500 /* create interface signals and properties here. */
502 * GstChildProxy::child-added:
503 * @child_proxy: the #GstChildProxy
504 * @object: the #GObject that was added
505 * @name: the name of the new child
507 * Will be emitted after the @object was added to the @child_proxy.
509 signals[CHILD_ADDED] =
510 g_signal_new ("child-added", G_TYPE_FROM_CLASS (g_class),
511 G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstChildProxyInterface,
512 child_added), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE,
513 2, G_TYPE_OBJECT, G_TYPE_STRING);
516 * GstChildProxy::child-removed:
517 * @child_proxy: the #GstChildProxy
518 * @object: the #GObject that was removed
519 * @name: the name of the old child
521 * Will be emitted after the @object was removed from the @child_proxy.
523 signals[CHILD_REMOVED] =
524 g_signal_new ("child-removed", G_TYPE_FROM_CLASS (g_class),
525 G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstChildProxyInterface,
526 child_removed), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE,
527 2, G_TYPE_OBJECT, G_TYPE_STRING);
534 gst_child_proxy_get_type (void)
536 static volatile gsize type = 0;
538 if (g_once_init_enter (&type)) {
540 static const GTypeInfo info = {
541 sizeof (GstChildProxyInterface),
542 gst_child_proxy_base_init, /* base_init */
543 NULL, /* base_finalize */
544 gst_child_proxy_class_init, /* class_init */
545 NULL, /* class_finalize */
546 NULL, /* class_data */
549 NULL /* instance_init */
553 g_type_register_static (G_TYPE_INTERFACE, "GstChildProxy", &info, 0);
555 g_type_interface_add_prerequisite (_type, G_TYPE_OBJECT);
556 g_once_init_leave (&type, (gsize) _type);