Index: docs/gst/gstreamer-sections.txt
===================================================================
RCS file: /cvs/gstreamer/gstreamer/docs/gst/gstreamer-sections.txt,v
retrieving revision 1.130.2.4
diff -u -3 -p -r1.130.2.4 gstreamer-sections.txt
--- docs/gst/gstreamer-sections.txt	8 Apr 2005 12:11:35 -0000	1.130.2.4
+++ docs/gst/gstreamer-sections.txt	12 Apr 2005 00:04:40 -0000
@@ -1114,6 +1114,32 @@ gst_pad_template_flags_get_type
 </SECTION>
 
 <SECTION>
+<FILE>gstparent</FILE>
+<TITLE>GstParent</TITLE>
+gst_parent_get_children_count
+gst_parent_get_child_by_name
+gst_parent_get_child_by_index
+gst_parent_lookup
+gst_parent_get_property
+gst_parent_get_valist
+gst_parent_get
+gst_parent_set_property
+gst_parent_set_valist
+gst_parent_set
+<SUBSECTION Standard>
+GstParent
+GstParentClass
+GST_PARENT
+GST_IS_PARENT
+GST_IS_PARENT_CLASS
+GST_PARENT_CLASS
+GST_PARENT_GET_CLASS
+GST_TYPE_PARENT
+<SUBSECTION Private>
+gst_parent_get_type
+</SECTION>
+
+<SECTION>
 <FILE>gstparse</FILE>
 <TITLE>GstParse</TITLE>
 gst_parse_error_quark
Index: gst/Makefile.am
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/Makefile.am,v
retrieving revision 1.164.4.2
diff -u -3 -p -r1.164.4.2 Makefile.am
--- gst/Makefile.am	8 Apr 2005 12:11:35 -0000	1.164.4.2
+++ gst/Makefile.am	12 Apr 2005 00:04:40 -0000
@@ -100,6 +100,7 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES
 	gstinterface.c		\
 	gstmemchunk.c		\
 	gstpad.c		\
+	gstparent.c		\
 	gstpipeline.c		\
 	gstplugin.c		\
 	gstpluginfeature.c	\
@@ -174,6 +175,7 @@ gst_headers =			\
 	gstmacros.h		\
 	gstmemchunk.h		\
 	gstpad.h		\
+	gstparent.h		\
 	gstpipeline.h		\
 	gstplugin.h		\
 	gstpluginfeature.h	\
Index: gst/gst.h
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gst.h,v
retrieving revision 1.73
diff -u -3 -p -r1.73 gst.h
--- gst/gst.h	21 Jan 2005 17:52:50 -0000	1.73
+++ gst/gst.h	12 Apr 2005 00:04:41 -0000
@@ -45,6 +45,7 @@
 #include <gst/gstmarshal.h>
 #include <gst/gstobject.h>
 #include <gst/gstpad.h>
+#include <gst/gstparent.h>
 #include <gst/gstpipeline.h>
 #include <gst/gstplugin.h>
 #include <gst/gstscheduler.h>
Index: gst/gstbin.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gstbin.c,v
retrieving revision 1.210
diff -u -3 -p -r1.210 gstbin.c
--- gst/gstbin.c	31 Jan 2005 23:21:52 -0000	1.210
+++ gst/gstbin.c	12 Apr 2005 00:04:41 -0000
@@ -33,6 +33,7 @@
 #include "gstscheduler.h"
 #include "gstindex.h"
 #include "gstutils.h"
+#include "gstparent.h"
 
 GST_DEBUG_CATEGORY_STATIC (bin_debug);
 #define GST_CAT_DEFAULT bin_debug
@@ -97,6 +98,7 @@ enum
 static void gst_bin_base_init (gpointer g_class);
 static void gst_bin_class_init (GstBinClass * klass);
 static void gst_bin_init (GstBin * bin);
+static void gst_bin_parent_init (gpointer g_iface, gpointer iface_data);
 
 static GstElementClass *parent_class = NULL;
 static guint gst_bin_signals[LAST_SIGNAL] = { 0 };
@@ -123,9 +125,18 @@ gst_bin_get_type (void)
       NULL
     };
 
+    static const GInterfaceInfo parent_info = {
+      gst_bin_parent_init,
+      NULL,
+      NULL
+    };
+
     _gst_bin_type =
         g_type_register_static (GST_TYPE_ELEMENT, "GstBin", &bin_info, 0);
 
+    g_type_add_interface_static (_gst_bin_type, GST_TYPE_PARENT,
+	&parent_info);
+
     GST_DEBUG_CATEGORY_INIT (bin_debug, "bin", GST_DEBUG_BOLD,
         "debugging info for the 'bin' container element");
   }
@@ -213,6 +224,26 @@ gst_bin_init (GstBin * bin)
   bin->children = NULL;
 }
 
+static GstObject *
+gst_bin_parent_get_child_by_index (GstParent * parent, guint index)
+{
+  return g_list_nth (GST_BIN (parent)->children, index)->data;
+}
+
+guint 
+gst_bin_parent_get_children_count (GstParent * parent)
+{
+  return GST_BIN (parent)->numchildren;
+}
+
+static void 
+gst_bin_parent_init (gpointer g_iface, gpointer iface_data)
+{
+  GstParentInterface *iface = g_iface;
+  
+  iface->get_children_count = gst_bin_parent_get_children_count;
+  iface->get_child_by_index = gst_bin_parent_get_child_by_index;
+}
 /**
  * gst_bin_new:
  * @name: name of new bin
Index: gst/parse/grammar.y
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/parse/grammar.y,v
retrieving revision 1.53.4.1
diff -u -3 -p -r1.53.4.1 grammar.y
--- gst/parse/grammar.y	25 Mar 2005 19:52:11 -0000	1.53.4.1
+++ gst/parse/grammar.y	12 Apr 2005 00:04:41 -0000
@@ -14,6 +14,7 @@
 #include "../gsterror.h"
 #include "../gsturi.h"
 #include "../gstvalue.h"
+#include "../gstparent.h"
 #include "types.h"
 
 /* All error messages in this file are user-visible and need to be translated.
@@ -236,6 +237,7 @@ gst_parse_element_set (gchar *value, Gst
   gchar *pos = value;
   GValue v = { 0, }; 
   GValue v2 = { 0, };
+  GstObject *target;
   /* parse the string, so the property name is null-terminated an pos points
      to the beginning of the value */
   while (!g_ascii_isspace (*pos) && (*pos != '=')) pos++; 
@@ -253,11 +255,11 @@ gst_parse_element_set (gchar *value, Gst
     pos[strlen (pos) - 1] = '\0';
   }
   gst_parse_unescape (pos); 
-  if ((pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (element), value))) { 
+  if (gst_parent_lookup (GST_OBJECT (element), value, &target, &pspec)) { 
     g_value_init (&v, G_PARAM_SPEC_VALUE_TYPE(pspec)); 
     if (!gst_value_deserialize (&v, pos))
       goto error;
-    g_object_set_property (G_OBJECT (element), value, &v); 
+    g_object_set_property (G_OBJECT (target), pspec->name, &v); 
   } else { 
     SET_ERROR (((graph_t *) graph)->error, GST_PARSE_ERROR_NO_SUCH_PROPERTY, _("no property \"%s\" in element \"%s\""), value, GST_ELEMENT_NAME (element)); 
   }
--- /dev/null	2005-04-02 20:43:11.669530008 +0200
+++ gst/gstparent.c	2005-04-12 00:27:09.339792064 +0200
@@ -0,0 +1,367 @@
+/* GStreamer
+ * Copyright (C) 2005 Stefan Kost <ensonic@users.sf.net>
+ *
+ * gstparent.c: interface for multi child elements
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gst_private.h"
+
+#include "gstparent.h"
+#include <gobject/gvaluecollector.h>
+
+/* Parent signals */
+/*
+enum
+{
+  CHILD_ADDED,
+  CHILD_REMOVED,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+*/
+
+/**
+ * gst_parent_get_child_by_name:
+ * @parent: the parent object to get the child from
+ * @name: the childs name
+ *
+ * Looks up a child element by the given name.
+ *
+ * Implementors can use #GstObject together with gst_object_get_name() 
+ *
+ * Returns: the child object or %NULL if not found
+ */
+GstObject *
+gst_parent_get_child_by_name (GstParent * parent, const gchar * name)
+{
+  guint count, i;
+  GstObject *object;
+  const gchar *object_name;
+  
+  g_return_val_if_fail (GST_IS_PARENT (parent), NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+
+  count = gst_parent_get_children_count (parent);
+  for (i = 0; i < count; i++) {
+    object = gst_parent_get_child_by_index (parent, i);
+    object_name = gst_object_get_name (object);
+    if (object_name == NULL) {
+      g_warning ("child %u of parent %s has no name", i, GST_OBJECT_NAME (parent));
+      continue;
+    }
+    if (g_str_equal (object_name, name))
+      return object;
+  }
+  return NULL;
+}
+
+/**
+ * gst_parent_get_child_by_index:
+ * @parent: the parent object to get the child from
+ * @index: the childs position in the child list
+ *
+ * Fetches a child by its number.
+ *
+ * Returns: the child object or %NULL if not found (index too high)
+ */
+GstObject *
+gst_parent_get_child_by_index (GstParent * parent, guint index)
+{
+  g_return_val_if_fail (GST_IS_PARENT (parent), NULL);
+
+  return (GST_PARENT_GET_INTERFACE (parent)->get_child_by_index (parent, index));
+}
+
+/**
+ * gst_parent_get_children_count:
+ * @parent: the parent object
+ *
+ * Gets the number of child objects this parent contains.
+ *
+ * Returns: the number of child objects
+ */
+guint
+gst_parent_get_children_count (GstParent * parent)
+{
+  g_return_val_if_fail (GST_IS_PARENT (parent), 0);
+
+  return (GST_PARENT_GET_INTERFACE (parent)->get_children_count (parent));
+}
+
+/**
+ * gst_parent_lookup:
+ * @object: object to lookup the property in
+ * @name: name of the property to look up
+ * @target: pointer to a #GstObject that takes the real object to set property on
+ * @pspec: pointer to take the #GParamSpec describing the property
+ *
+ * Looks up which object and #GParamSpec would be effected by the given @name.
+ *
+ * Returns: TRUE if @target and @pspec could be found. FALSE otherwise. In that 
+ * case the values for @pspec and @target are not modified
+ */
+gboolean
+gst_parent_lookup (GstObject * object, const gchar *name, 
+    GstObject **target, GParamSpec **pspec)
+{
+  gchar **names, **current;
+  
+  g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
+  g_return_val_if_fail (name != NULL, FALSE);
+
+  current = names = g_strsplit (name, "::", -1);
+  while (current[1]) {
+      if (!GST_IS_PARENT (object)) {
+	GST_INFO ("object %s is not a parent, so you cannot request a child by name %s",
+	    GST_OBJECT_NAME (object), current[0]);
+	break;
+      }
+      object = gst_parent_get_child_by_name (GST_PARENT (object), current[0]);
+      if (!object) {
+	GST_INFO ("no such object %s", current[0]);
+	break;
+      }
+      current++;
+  };
+  if (current[1] == NULL) {
+    GParamSpec *spec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), current[0]);
+    if (spec == NULL) {
+      GST_INFO ("no param spec named %s", current[0]);
+      g_strfreev (names);
+      return FALSE;
+    }
+    if (pspec)
+      *pspec = spec;
+    if (target)
+      *target = object;
+    g_strfreev (names);
+    return TRUE;
+  } else {
+    g_strfreev (names);
+    return FALSE;
+  }
+}
+
+/**
+ * gst_parent_get_property:
+ * @object: object to query
+ * @name: name of the property
+ * @value: an uninitialized GValue that should take the result. 
+ * You are responsible for for freeing it by calling g_value_unset()
+ * Gets a single property using the GstParent mechanism.
+ */
+void
+gst_parent_get_property (GstObject *object, const gchar *name, GValue *value)
+{
+  GParamSpec *pspec;
+  GstObject *target;
+
+  g_return_if_fail (GST_IS_OBJECT (object));
+  g_return_if_fail (name != NULL);
+  g_return_if_fail (!G_IS_VALUE (value));
+
+  if (!gst_parent_lookup (object, name, &target, &pspec)) {
+    g_warning ("cannot get property %s from object %s", name, 
+	GST_OBJECT_NAME (object));
+    return;
+  }
+  g_object_get_property (G_OBJECT (target), pspec->name, value);
+}
+
+/**
+ * gst_parent_get_valist:
+ * @object: the object to query
+ * @first_property_name: name of the first property to get
+ * @var_args: return location for the first property, followed optionally by more name/return location pairs, followed by NULL
+ * Gets properties of the parent object and its children.
+ */
+void
+gst_parent_get_valist (GstObject * object, const gchar * first_property_name,
+    va_list var_args)
+{
+  const gchar *name;
+  gchar *error = NULL;
+  GValue value;
+
+  g_return_if_fail (G_IS_OBJECT (object));
+
+  g_object_ref (object);
+
+  name = first_property_name;
+
+  /* iterate over pairs */
+  while (name) {
+    gst_parent_get_property (object, name, &value);
+    G_VALUE_LCOPY (&value, var_args, 0, &error);
+    if (error) {
+      g_warning ("error copying value: %s", error);
+      return;
+    }
+    g_value_unset (&value);
+    name = va_arg (var_args, gchar *);
+  }
+
+  g_object_unref (object);
+}
+
+/**
+ * gst_parent_get:
+ * @object: the parent object
+ * @first_property_name: name of the first property to get
+ * @...: return location for the first property, followed optionally by more name/return location pairs, followed by NULL
+ * Gets properties of the parent object and its children.
+ */
+void
+gst_parent_get (GstObject * object, const gchar * first_property_name, ...)
+{
+  va_list var_args;
+
+  g_return_if_fail (GST_IS_OBJECT (object));
+
+  va_start (var_args, first_property_name);
+  gst_parent_get_valist (object, first_property_name, var_args);
+  va_end (var_args);
+}
+
+void
+gst_parent_set_property (GstObject * object, const gchar *name, const GValue *value)
+{
+  GParamSpec *pspec;
+  GstObject *target;
+
+  g_return_if_fail (GST_IS_OBJECT (object));
+  g_return_if_fail (name != NULL);
+  g_return_if_fail (!G_IS_VALUE (value));
+
+  if (!gst_parent_lookup (object, name, &target, &pspec)) {
+    g_warning ("cannot set property %s on object %s", name, 
+	GST_OBJECT_NAME (object));
+    return;
+  }
+  g_object_set_property (G_OBJECT (target), pspec->name, value);
+}
+
+/**
+ * gst_parent_set_valist:
+ * @parent: the parent object
+ * @first_property_name: name of the first property to set
+ * @var_args: value for the first property, followed optionally by more name/value pairs, followed by NULL
+ * Sets properties of the parent object and its children.
+ */
+void
+gst_parent_set_valist (GstObject *object, const gchar * first_property_name,
+    va_list var_args)
+{
+  const gchar *name;
+  gchar *error = NULL;
+  GValue value;
+
+  g_return_if_fail (G_IS_OBJECT (object));
+
+  g_object_ref (object);
+
+  name = first_property_name;
+
+  /* iterate over pairs */
+  while (name) {
+    GParamSpec *pspec;
+    GstObject *target;
+    if (!gst_parent_lookup (object, name, &target, &pspec)) {
+      g_warning ("no such property %s in object %s", name, GST_OBJECT_NAME (object));
+      g_object_unref (object);
+    }
+    g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+    G_VALUE_COLLECT (&value, var_args, G_VALUE_NOCOPY_CONTENTS, &error);
+    if (error) {
+      g_warning ("error copying value: %s", error);
+      g_object_unref (object);
+      return;
+    }
+    g_object_set_property (G_OBJECT (target), pspec->name, &value);
+    g_value_unset (&value);
+    name = va_arg (var_args, gchar *);
+  }
+
+  g_object_unref (object);
+}
+
+/**
+ * gst_parent_set:
+ * @object: the parent object
+ * @first_property_name: name of the first property to set
+ * @...: value for the first property, followed optionally by more name/value pairs, followed by NULL
+ * Sets properties of the parent object and its children.
+ */
+void
+gst_parent_set (GstObject * object, const gchar * first_property_name, ...)
+{
+  va_list var_args;
+
+  g_return_if_fail (GST_IS_OBJECT (object));
+
+  va_start (var_args, first_property_name);
+  gst_parent_set_valist (object, first_property_name, var_args);
+  va_end (var_args);
+}
+
+static void
+gst_parent_base_init (gpointer g_class)
+{
+  static gboolean initialized = FALSE;
+
+  if (!initialized) {
+    /* create interface signals and properties here. */
+    /*
+       signals[CHILD_ADDED] =
+       g_signal_new ("child-added", G_TYPE_FROM_CLASS (g_class),
+       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstParentInterface, child_added), NULL,
+       NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
+       signals[CHILD_REMOVED] =
+       g_signal_new ("child-removed", G_TYPE_FROM_CLASS (g_class),
+       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstParentInterface, child_removed), NULL,
+       NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT);
+     */
+    initialized = TRUE;
+  }
+}
+
+GType
+gst_parent_get_type (void)
+{
+  static GType type = 0;
+
+  if (type == 0) {
+    static const GTypeInfo info = {
+      sizeof (GstParentInterface),
+      gst_parent_base_init,     /* base_init */
+      NULL,                     /* base_finalize */
+      NULL,                     /* class_init */
+      NULL,                     /* class_finalize */
+      NULL,                     /* class_data */
+      0,
+      0,                        /* n_preallocs */
+      NULL                      /* instance_init */
+    };
+    type = g_type_register_static (G_TYPE_INTERFACE, "GstParent", &info, 0);
+
+    g_type_interface_add_prerequisite (type, GST_TYPE_OBJECT);
+  }
+  return type;
+}
--- /dev/null	2005-04-02 20:43:11.669530008 +0200
+++ gst/gstparent.h	2005-04-11 22:44:05.899817824 +0200
@@ -0,0 +1,72 @@
+/* GStreamer
+ * Copyright (C) 2005 Stefan Kost <ensonic@users.sf.net>
+ *
+ * gstparent.h: interface header for multi child elements
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_PARENT_H__
+#define __GST_PARENT_H__
+
+#include <glib-object.h>
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+
+#define GST_TYPE_PARENT			(gst_parent_get_type ())
+#define GST_PARENT(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PARENT, GstParent))
+#define GST_IS_PARENT(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PARENT))
+#define GST_PARENT_GET_INTERFACE(obj)	(G_TYPE_INSTANCE_GET_INTERFACE ((obj), GST_TYPE_PARENT, GstParentInterface))
+
+typedef struct _GstParent GstParent;    /* dummy object */
+typedef struct _GstParentInterface GstParentInterface;
+
+struct _GstParentInterface
+{
+  GTypeInterface parent;
+
+  /* methods */
+  GstObject *(*get_child_by_index) (GstParent * parent, guint index);
+  guint (*get_children_count) (GstParent * parent);
+  /* signals */
+  void (*child_added) (GstParent * parent, GstObject * child);
+  void (*child_removed) (GstParent * parent, GstObject * child);
+};
+
+GType gst_parent_get_type (void);
+
+GstObject *gst_parent_get_child_by_name (GstParent * parent, const gchar * name);
+GstObject *gst_parent_get_child_by_index (GstParent * parent, guint index);
+guint gst_parent_get_children_count (GstParent * parent);
+
+gboolean gst_parent_lookup (GstObject *object, const gchar *name, GstObject **target, GParamSpec **spec);
+void gst_parent_get_property (GstObject * object, const gchar *name, GValue *result);
+void gst_parent_get_valist (GstObject * object,
+    const gchar * first_property_name, va_list var_args);
+void gst_parent_get (GstObject * object, const gchar * first_property_name,
+    ...);
+void gst_parent_set_property (GstObject * object, const gchar *name, const GValue *value);
+void gst_parent_set_valist (GstObject* object,
+    const gchar * first_property_name, va_list var_args);
+void gst_parent_set (GstObject * object, const gchar * first_property_name,
+    ...);
+
+
+G_END_DECLS
+
+#endif /* __GST_PARENT_H__ */
