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., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
23 * SECTION:gstchildproxy
24 * @title: GstChildProxy
25 * @short_description: Interface for multi child elements.
28 * This interface abstracts handling of property sets for elements with
29 * children. Imagine elements such as mixers or polyphonic generators. They all
30 * have multiple #GstPad or some kind of voice objects. Another use case are
31 * container elements like #GstBin.
32 * The element implementing the interface acts as a parent for those child
35 * By implementing this interface the child properties can be accessed from the
36 * parent element by using gst_child_proxy_get() and gst_child_proxy_set().
38 * Property names are written as "child-name::property-name". The whole naming
39 * scheme is recursive. Thus "child1::child2::property" is valid too, if
40 * "child1" and "child2" implement the #GstChildProxy interface.
43 #include "gst_private.h"
45 #include "gstchildproxy.h"
46 #include <gobject/gvaluecollector.h>
56 static guint signals[LAST_SIGNAL] = { 0 };
59 gst_child_proxy_default_get_child_by_name (GstChildProxy * parent,
63 GObject *object, *result;
66 g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), NULL);
67 g_return_val_if_fail (name != NULL, NULL);
71 count = gst_child_proxy_get_children_count (parent);
72 for (i = 0; i < count; i++) {
75 if (!(object = gst_child_proxy_get_child_by_index (parent, i)))
78 if (!GST_IS_OBJECT (object)) {
81 object_name = gst_object_get_name (GST_OBJECT_CAST (object));
82 if (object_name == NULL) {
83 g_warning ("child %u of parent %s has no name", i,
84 GST_OBJECT_NAME (parent));
87 eq = g_str_equal (object_name, name);
95 g_object_unref (object);
102 * gst_child_proxy_get_child_by_name:
103 * @parent: the parent object to get the child from
104 * @name: the child's name
106 * Looks up a child element by the given name.
108 * This virtual method has a default implementation that uses #GstObject
109 * together with gst_object_get_name(). If the interface is to be used with
110 * #GObjects, this methods needs to be overridden.
112 * Returns: (transfer full) (nullable): the child object or %NULL if
113 * not found. Unref after usage.
118 gst_child_proxy_get_child_by_name (GstChildProxy * parent, const gchar * name)
120 GstChildProxyInterface *iface;
122 g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), 0);
124 iface = GST_CHILD_PROXY_GET_INTERFACE (parent);
126 if (iface->get_child_by_name != NULL)
127 return iface->get_child_by_name (parent, name);
133 * gst_child_proxy_get_child_by_index:
134 * @parent: the parent object to get the child from
135 * @index: the child's position in the child list
137 * Fetches a child by its number.
139 * Returns: (transfer full) (nullable): the child object or %NULL if
140 * not found (index too high). Unref after usage.
145 gst_child_proxy_get_child_by_index (GstChildProxy * parent, guint index)
147 GstChildProxyInterface *iface;
149 g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), NULL);
151 iface = GST_CHILD_PROXY_GET_INTERFACE (parent);
153 if (iface->get_child_by_index != NULL)
154 return iface->get_child_by_index (parent, index);
160 * gst_child_proxy_get_children_count:
161 * @parent: the parent object
163 * Gets the number of child objects this parent contains.
165 * Returns: the number of child objects
170 gst_child_proxy_get_children_count (GstChildProxy * parent)
172 GstChildProxyInterface *iface;
174 g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), 0);
176 iface = GST_CHILD_PROXY_GET_INTERFACE (parent);
178 if (iface->get_children_count != NULL)
179 return iface->get_children_count (parent);
185 * gst_child_proxy_lookup:
186 * @object: child proxy object to lookup the property in
187 * @name: name of the property to look up
188 * @target: (out) (allow-none) (transfer full): pointer to a #GObject that
189 * takes the real object to set property on
190 * @pspec: (out) (allow-none) (transfer none): pointer to take the #GParamSpec
191 * describing the property
193 * Looks up which object and #GParamSpec would be effected by the given @name.
197 * Returns: %TRUE if @target and @pspec could be found. %FALSE otherwise. In that
198 * case the values for @pspec and @target are not modified. Unref @target after
199 * usage. For plain GObjects @target is the same as @object.
202 gst_child_proxy_lookup (GstChildProxy * object, const gchar * name,
203 GObject ** target, GParamSpec ** pspec)
206 gboolean res = FALSE;
207 gchar **names, **current;
209 g_return_val_if_fail (GST_IS_CHILD_PROXY (object), FALSE);
210 g_return_val_if_fail (name != NULL, FALSE);
212 obj = G_OBJECT (g_object_ref (object));
214 current = names = g_strsplit (name, "::", -1);
215 /* find the owner of the property */
219 if (!GST_IS_CHILD_PROXY (obj)) {
221 ("object %s is not a parent, so you cannot request a child by name %s",
222 (GST_IS_OBJECT (obj) ? GST_OBJECT_NAME (obj) : ""), current[0]);
225 next = gst_child_proxy_get_child_by_name (GST_CHILD_PROXY (obj),
228 GST_INFO ("no such object %s", current[0]);
231 g_object_unref (obj);
237 if (current[1] == NULL) {
239 g_object_class_find_property (G_OBJECT_GET_CLASS (obj), current[0]);
241 GST_INFO ("no param spec named %s", current[0]);
252 g_object_unref (obj);
258 * gst_child_proxy_get_property:
259 * @object: object to query
260 * @name: name of the property
261 * @value: (out caller-allocates): a #GValue that should take the result.
263 * Gets a single property using the GstChildProxy mechanism.
264 * You are responsible for freeing it by calling g_value_unset()
267 gst_child_proxy_get_property (GstChildProxy * object, const gchar * name,
273 g_return_if_fail (GST_IS_CHILD_PROXY (object));
274 g_return_if_fail (name != NULL);
275 g_return_if_fail (G_IS_VALUE (value));
277 if (!gst_child_proxy_lookup (object, name, &target, &pspec))
280 g_object_get_property (target, pspec->name, value);
281 g_object_unref (target);
287 g_warning ("no property %s in object %s", name,
288 (GST_IS_OBJECT (object) ? GST_OBJECT_NAME (object) : ""));
294 * gst_child_proxy_get_valist:
295 * @object: the object to query
296 * @first_property_name: name of the first property to get
297 * @var_args: return location for the first property, followed optionally by more name/return location pairs, followed by %NULL
299 * Gets properties of the parent object and its children.
302 gst_child_proxy_get_valist (GstChildProxy * object,
303 const gchar * first_property_name, va_list var_args)
307 GValue value = { 0, };
311 g_return_if_fail (GST_IS_CHILD_PROXY (object));
313 name = first_property_name;
315 /* iterate over pairs */
317 if (!gst_child_proxy_lookup (object, name, &target, &pspec))
320 g_value_init (&value, pspec->value_type);
321 g_object_get_property (target, pspec->name, &value);
322 g_object_unref (target);
324 G_VALUE_LCOPY (&value, var_args, 0, &error);
327 g_value_unset (&value);
328 name = va_arg (var_args, gchar *);
334 g_warning ("no property %s in object %s", name,
335 (GST_IS_OBJECT (object) ? GST_OBJECT_NAME (object) : ""));
340 g_warning ("error copying value %s in object %s: %s", pspec->name,
341 (GST_IS_OBJECT (object) ? GST_OBJECT_NAME (object) : ""), error);
342 g_value_unset (&value);
348 * gst_child_proxy_get:
349 * @object: the parent object
350 * @first_property_name: name of the first property to get
351 * @...: return location for the first property, followed optionally by more name/return location pairs, followed by %NULL
353 * Gets properties of the parent object and its children.
356 gst_child_proxy_get (GstChildProxy * object, const gchar * first_property_name,
361 g_return_if_fail (GST_IS_CHILD_PROXY (object));
363 va_start (var_args, first_property_name);
364 gst_child_proxy_get_valist (object, first_property_name, var_args);
369 * gst_child_proxy_set_property:
370 * @object: the parent object
371 * @name: name of the property to set
372 * @value: new #GValue for the property
374 * Sets a single property using the GstChildProxy mechanism.
377 gst_child_proxy_set_property (GstChildProxy * object, const gchar * name,
378 const GValue * value)
383 g_return_if_fail (GST_IS_CHILD_PROXY (object));
384 g_return_if_fail (name != NULL);
385 g_return_if_fail (G_IS_VALUE (value));
387 if (!gst_child_proxy_lookup (object, name, &target, &pspec))
390 g_object_set_property (target, pspec->name, value);
391 g_object_unref (target);
396 g_warning ("cannot set property %s on object %s", name,
397 (GST_IS_OBJECT (object) ? GST_OBJECT_NAME (object) : ""));
403 * gst_child_proxy_set_valist:
404 * @object: the parent object
405 * @first_property_name: name of the first property to set
406 * @var_args: value for the first property, followed optionally by more name/value pairs, followed by %NULL
408 * Sets properties of the parent object and its children.
411 gst_child_proxy_set_valist (GstChildProxy * object,
412 const gchar * first_property_name, va_list var_args)
416 GValue value = { 0, };
420 g_return_if_fail (GST_IS_CHILD_PROXY (object));
422 name = first_property_name;
424 /* iterate over pairs */
426 if (!gst_child_proxy_lookup (object, name, &target, &pspec))
429 G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args,
430 G_VALUE_NOCOPY_CONTENTS, &error);
435 g_object_set_property (target, pspec->name, &value);
436 g_object_unref (target);
438 g_value_unset (&value);
439 name = va_arg (var_args, gchar *);
445 g_warning ("no property %s in object %s", name,
446 (GST_IS_OBJECT (object) ? GST_OBJECT_NAME (object) : ""));
451 g_warning ("error copying value %s in object %s: %s", pspec->name,
452 (GST_IS_OBJECT (object) ? GST_OBJECT_NAME (object) : ""), error);
453 g_value_unset (&value);
454 g_object_unref (target);
460 * gst_child_proxy_set:
461 * @object: the parent object
462 * @first_property_name: name of the first property to set
463 * @...: value for the first property, followed optionally by more name/value pairs, followed by %NULL
465 * Sets properties of the parent object and its children.
468 gst_child_proxy_set (GstChildProxy * object, const gchar * first_property_name,
473 g_return_if_fail (GST_IS_CHILD_PROXY (object));
475 va_start (var_args, first_property_name);
476 gst_child_proxy_set_valist (object, first_property_name, var_args);
481 * gst_child_proxy_child_added:
482 * @parent: the parent object
483 * @child: the newly added child
484 * @name: the name of the new child
486 * Emits the "child-added" signal.
489 gst_child_proxy_child_added (GstChildProxy * parent, GObject * child,
492 g_signal_emit (parent, signals[CHILD_ADDED], 0, child, name);
496 * gst_child_proxy_child_removed:
497 * @parent: the parent object
498 * @child: the removed child
499 * @name: the name of the old child
501 * Emits the "child-removed" signal.
504 gst_child_proxy_child_removed (GstChildProxy * parent, GObject * child,
507 g_signal_emit (parent, signals[CHILD_REMOVED], 0, child, name);
510 /* gobject methods */
513 gst_child_proxy_class_init (gpointer g_class, gpointer class_data)
515 GstChildProxyInterface *iface = (GstChildProxyInterface *) g_class;
517 iface->get_child_by_name = gst_child_proxy_default_get_child_by_name;
521 gst_child_proxy_base_init (gpointer g_class)
523 static gboolean initialized = FALSE;
526 /* create interface signals and properties here. */
528 * GstChildProxy::child-added:
529 * @child_proxy: the #GstChildProxy
530 * @object: the #GObject that was added
531 * @name: the name of the new child
533 * Will be emitted after the @object was added to the @child_proxy.
535 signals[CHILD_ADDED] =
536 g_signal_new ("child-added", G_TYPE_FROM_CLASS (g_class),
537 G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstChildProxyInterface,
538 child_added), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE,
539 2, G_TYPE_OBJECT, G_TYPE_STRING);
542 * GstChildProxy::child-removed:
543 * @child_proxy: the #GstChildProxy
544 * @object: the #GObject that was removed
545 * @name: the name of the old child
547 * Will be emitted after the @object was removed from the @child_proxy.
549 signals[CHILD_REMOVED] =
550 g_signal_new ("child-removed", G_TYPE_FROM_CLASS (g_class),
551 G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstChildProxyInterface,
552 child_removed), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE,
553 2, G_TYPE_OBJECT, G_TYPE_STRING);
560 gst_child_proxy_get_type (void)
562 static volatile gsize type = 0;
564 if (g_once_init_enter (&type)) {
566 static const GTypeInfo info = {
567 sizeof (GstChildProxyInterface),
568 gst_child_proxy_base_init, /* base_init */
569 NULL, /* base_finalize */
570 gst_child_proxy_class_init, /* class_init */
571 NULL, /* class_finalize */
572 NULL, /* class_data */
575 NULL /* instance_init */
579 g_type_register_static (G_TYPE_INTERFACE, "GstChildProxy", &info, 0);
581 g_type_interface_add_prerequisite (_type, G_TYPE_OBJECT);
582 g_once_init_leave (&type, (gsize) _type);