gstreamer_core/gst/gstchildproxy.c
changeset 0 0e761a78d257
child 8 4a7fac7dd34a
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     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 /**
       
    23  * SECTION:gstchildproxy
       
    24  * @short_description: Interface for multi child elements.
       
    25  * @see_also: #GstBin
       
    26  *
       
    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
       
    32  * objects.
       
    33  *
       
    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().
       
    36  *
       
    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.
       
    40  */
       
    41 /* FIXME-0.11:
       
    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.
       
    47  */
       
    48 
       
    49 #include "gst_private.h"
       
    50 
       
    51 #include "gstchildproxy.h"
       
    52 #include "gstmarshal.h"
       
    53 #include <gobject/gvaluecollector.h>
       
    54 
       
    55 /* signals */
       
    56 enum
       
    57 {
       
    58   CHILD_ADDED,
       
    59   CHILD_REMOVED,
       
    60   LAST_SIGNAL
       
    61 };
       
    62 
       
    63 static guint signals[LAST_SIGNAL] = { 0 };
       
    64 
       
    65 /**
       
    66  * gst_child_proxy_get_child_by_name:
       
    67  * @parent: the parent object to get the child from
       
    68  * @name: the childs name
       
    69  *
       
    70  * Looks up a child element by the given name.
       
    71  *
       
    72  * Implementors can use #GstObject together with gst_object_get_name()
       
    73  *
       
    74  * Returns: the child object or %NULL if not found. Unref after usage.
       
    75  *
       
    76  * MT safe.
       
    77  */
       
    78 #ifdef __SYMBIAN32__
       
    79 EXPORT_C
       
    80 #endif
       
    81 
       
    82 GstObject *
       
    83 gst_child_proxy_get_child_by_name (GstChildProxy * parent, const gchar * name)
       
    84 {
       
    85   guint count, i;
       
    86   GstObject *object, *result;
       
    87   gchar *object_name;
       
    88 
       
    89   g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), NULL);
       
    90   g_return_val_if_fail (name != NULL, NULL);
       
    91 
       
    92   result = NULL;
       
    93 
       
    94   count = gst_child_proxy_get_children_count (parent);
       
    95   for (i = 0; i < count; i++) {
       
    96     gboolean eq;
       
    97 
       
    98     if (!(object = gst_child_proxy_get_child_by_index (parent, i)))
       
    99       continue;
       
   100 
       
   101     object_name = gst_object_get_name (object);
       
   102     if (object_name == NULL) {
       
   103       g_warning ("child %u of parent %s has no name", i,
       
   104           GST_OBJECT_NAME (parent));
       
   105       goto next;
       
   106     }
       
   107     eq = g_str_equal (object_name, name);
       
   108     g_free (object_name);
       
   109 
       
   110     if (eq) {
       
   111       result = object;
       
   112       break;
       
   113     }
       
   114   next:
       
   115     gst_object_unref (object);
       
   116   }
       
   117   return result;
       
   118 }
       
   119 
       
   120 /**
       
   121  * gst_child_proxy_get_child_by_index:
       
   122  * @parent: the parent object to get the child from
       
   123  * @index: the childs position in the child list
       
   124  *
       
   125  * Fetches a child by its number.
       
   126  *
       
   127  * Returns: the child object or %NULL if not found (index too high). Unref
       
   128  * after usage.
       
   129  *
       
   130  * MT safe.
       
   131  */
       
   132 #ifdef __SYMBIAN32__
       
   133 EXPORT_C
       
   134 #endif
       
   135 
       
   136 GstObject *
       
   137 gst_child_proxy_get_child_by_index (GstChildProxy * parent, guint index)
       
   138 {
       
   139   g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), NULL);
       
   140 
       
   141   return (GST_CHILD_PROXY_GET_INTERFACE (parent)->get_child_by_index (parent,
       
   142           index));
       
   143 }
       
   144 
       
   145 /**
       
   146  * gst_child_proxy_get_children_count:
       
   147  * @parent: the parent object
       
   148  *
       
   149  * Gets the number of child objects this parent contains.
       
   150  *
       
   151  * Returns: the number of child objects
       
   152  *
       
   153  * MT safe.
       
   154  */
       
   155 #ifdef __SYMBIAN32__
       
   156 EXPORT_C
       
   157 #endif
       
   158 
       
   159 guint
       
   160 gst_child_proxy_get_children_count (GstChildProxy * parent)
       
   161 {
       
   162   g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), 0);
       
   163 
       
   164   return (GST_CHILD_PROXY_GET_INTERFACE (parent)->get_children_count (parent));
       
   165 }
       
   166 
       
   167 /**
       
   168  * gst_child_proxy_lookup:
       
   169  * @object: object to lookup the property in
       
   170  * @name: name of the property to look up
       
   171  * @target: pointer to a #GstObject that takes the real object to set property on
       
   172  * @pspec: pointer to take the #GParamSpec describing the property
       
   173  *
       
   174  * Looks up which object and #GParamSpec would be effected by the given @name.
       
   175  *
       
   176  * Returns: TRUE if @target and @pspec could be found. FALSE otherwise. In that
       
   177  * case the values for @pspec and @target are not modified. Unref @target after
       
   178  * usage.
       
   179  *
       
   180  * MT safe.
       
   181  */
       
   182 #ifdef __SYMBIAN32__
       
   183 EXPORT_C
       
   184 #endif
       
   185 
       
   186 gboolean
       
   187 gst_child_proxy_lookup (GstObject * object, const gchar * name,
       
   188     GstObject ** target, GParamSpec ** pspec)
       
   189 {
       
   190   gboolean res = FALSE;
       
   191   gchar **names, **current;
       
   192 
       
   193   g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
       
   194   g_return_val_if_fail (name != NULL, FALSE);
       
   195 
       
   196   gst_object_ref (object);
       
   197 
       
   198   current = names = g_strsplit (name, "::", -1);
       
   199   while (current[1]) {
       
   200     GstObject *next;
       
   201 
       
   202     if (!GST_IS_CHILD_PROXY (object)) {
       
   203       GST_INFO
       
   204           ("object %s is not a parent, so you cannot request a child by name %s",
       
   205           GST_OBJECT_NAME (object), current[0]);
       
   206       break;
       
   207     }
       
   208     next = gst_child_proxy_get_child_by_name (GST_CHILD_PROXY (object),
       
   209         current[0]);
       
   210     if (!next) {
       
   211       GST_INFO ("no such object %s", current[0]);
       
   212       break;
       
   213     }
       
   214     gst_object_unref (object);
       
   215     object = next;
       
   216     current++;
       
   217   };
       
   218   if (current[1] == NULL) {
       
   219     GParamSpec *spec =
       
   220         g_object_class_find_property (G_OBJECT_GET_CLASS (object), current[0]);
       
   221     if (spec == NULL) {
       
   222       GST_INFO ("no param spec named %s", current[0]);
       
   223     } else {
       
   224       if (pspec)
       
   225         *pspec = spec;
       
   226       if (target) {
       
   227         gst_object_ref (object);
       
   228         *target = object;
       
   229       }
       
   230       res = TRUE;
       
   231     }
       
   232   }
       
   233   gst_object_unref (object);
       
   234   g_strfreev (names);
       
   235   return res;
       
   236 }
       
   237 
       
   238 /**
       
   239  * gst_child_proxy_get_property:
       
   240  * @object: object to query
       
   241  * @name: name of the property
       
   242  * @value: a #GValue that should take the result.
       
   243  *
       
   244  * Gets a single property using the GstChildProxy mechanism.
       
   245  * You are responsible for for freeing it by calling g_value_unset()
       
   246  */
       
   247 #ifdef __SYMBIAN32__
       
   248 EXPORT_C
       
   249 #endif
       
   250 
       
   251 void
       
   252 gst_child_proxy_get_property (GstObject * object, const gchar * name,
       
   253     GValue * value)
       
   254 {
       
   255   GParamSpec *pspec;
       
   256   GstObject *target;
       
   257 
       
   258   g_return_if_fail (GST_IS_OBJECT (object));
       
   259   g_return_if_fail (name != NULL);
       
   260   g_return_if_fail (G_IS_VALUE (value));
       
   261 
       
   262   if (!gst_child_proxy_lookup (object, name, &target, &pspec))
       
   263     goto not_found;
       
   264 
       
   265   g_object_get_property (G_OBJECT (target), pspec->name, value);
       
   266   gst_object_unref (target);
       
   267 
       
   268   return;
       
   269 
       
   270 not_found:
       
   271   {
       
   272     g_warning ("cannot get property %s from object %s", name,
       
   273         GST_OBJECT_NAME (object));
       
   274     return;
       
   275   }
       
   276 }
       
   277 
       
   278 /**
       
   279  * gst_child_proxy_get_valist:
       
   280  * @object: the object to query
       
   281  * @first_property_name: name of the first property to get
       
   282  * @var_args: return location for the first property, followed optionally by more name/return location pairs, followed by NULL
       
   283  *
       
   284  * Gets properties of the parent object and its children.
       
   285  */
       
   286 #ifdef __SYMBIAN32__
       
   287 EXPORT_C
       
   288 #endif
       
   289 
       
   290 void
       
   291 gst_child_proxy_get_valist (GstObject * object,
       
   292     const gchar * first_property_name, va_list var_args)
       
   293 {
       
   294   const gchar *name;
       
   295   gchar *error = NULL;
       
   296   GValue value = { 0, };
       
   297 
       
   298   g_return_if_fail (G_IS_OBJECT (object));
       
   299 
       
   300   name = first_property_name;
       
   301 
       
   302   /* iterate over pairs */
       
   303   while (name) {
       
   304     gst_child_proxy_get_property (object, name, &value);
       
   305     G_VALUE_LCOPY (&value, var_args, 0, &error);
       
   306     if (error) {
       
   307       g_warning ("error copying value: %s", error);
       
   308       return;
       
   309     }
       
   310     g_value_unset (&value);
       
   311     name = va_arg (var_args, gchar *);
       
   312   }
       
   313 }
       
   314 
       
   315 /**
       
   316  * gst_child_proxy_get:
       
   317  * @object: the parent object
       
   318  * @first_property_name: name of the first property to get
       
   319  * @...: return location for the first property, followed optionally by more name/return location pairs, followed by NULL
       
   320  *
       
   321  * Gets properties of the parent object and its children.
       
   322  */
       
   323 #ifdef __SYMBIAN32__
       
   324 EXPORT_C
       
   325 #endif
       
   326 
       
   327 void
       
   328 gst_child_proxy_get (GstObject * object, const gchar * first_property_name, ...)
       
   329 {
       
   330   va_list var_args;
       
   331 
       
   332   g_return_if_fail (GST_IS_OBJECT (object));
       
   333 
       
   334   va_start (var_args, first_property_name);
       
   335   gst_child_proxy_get_valist (object, first_property_name, var_args);
       
   336   va_end (var_args);
       
   337 }
       
   338 
       
   339 /**
       
   340  * gst_child_proxy_set_property:
       
   341  * @object: the parent object
       
   342  * @name: name of the property to set
       
   343  * @value: new #GValue for the property
       
   344  *
       
   345  * Sets a single property using the GstChildProxy mechanism.
       
   346  */
       
   347 #ifdef __SYMBIAN32__
       
   348 EXPORT_C
       
   349 #endif
       
   350 
       
   351 void
       
   352 gst_child_proxy_set_property (GstObject * object, const gchar * name,
       
   353     const GValue * value)
       
   354 {
       
   355   GParamSpec *pspec;
       
   356   GstObject *target;
       
   357 
       
   358   g_return_if_fail (GST_IS_OBJECT (object));
       
   359   g_return_if_fail (name != NULL);
       
   360   g_return_if_fail (G_IS_VALUE (value));
       
   361 
       
   362   if (!gst_child_proxy_lookup (object, name, &target, &pspec))
       
   363     goto not_found;
       
   364 
       
   365   g_object_set_property (G_OBJECT (target), pspec->name, value);
       
   366   gst_object_unref (target);
       
   367   return;
       
   368 
       
   369 not_found:
       
   370   {
       
   371     g_warning ("cannot set property %s on object %s", name,
       
   372         GST_OBJECT_NAME (object));
       
   373     return;
       
   374   }
       
   375 }
       
   376 
       
   377 /**
       
   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
       
   382  *
       
   383  * Sets properties of the parent object and its children.
       
   384  */
       
   385 #ifdef __SYMBIAN32__
       
   386 EXPORT_C
       
   387 #endif
       
   388 
       
   389 void
       
   390 gst_child_proxy_set_valist (GstObject * object,
       
   391     const gchar * first_property_name, va_list var_args)
       
   392 {
       
   393   const gchar *name;
       
   394   gchar *error = NULL;
       
   395   GValue value = { 0, };
       
   396 
       
   397   g_return_if_fail (G_IS_OBJECT (object));
       
   398 
       
   399   name = first_property_name;
       
   400 
       
   401   /* iterate over pairs */
       
   402   while (name) {
       
   403     GParamSpec *pspec;
       
   404     GstObject *target;
       
   405 
       
   406     if (!gst_child_proxy_lookup (object, name, &target, &pspec)) {
       
   407       g_warning ("no such property %s in object %s", name,
       
   408           GST_OBJECT_NAME (object));
       
   409       continue;
       
   410     }
       
   411     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
       
   412     G_VALUE_COLLECT (&value, var_args, G_VALUE_NOCOPY_CONTENTS, &error);
       
   413     if (error) {
       
   414       g_warning ("error copying value: %s", error);
       
   415       gst_object_unref (target);
       
   416       return;
       
   417     }
       
   418     g_object_set_property (G_OBJECT (target), pspec->name, &value);
       
   419     gst_object_unref (target);
       
   420 
       
   421     g_value_unset (&value);
       
   422     name = va_arg (var_args, gchar *);
       
   423   }
       
   424 }
       
   425 
       
   426 /**
       
   427  * gst_child_proxy_set:
       
   428  * @object: the parent object
       
   429  * @first_property_name: name of the first property to set
       
   430  * @...: value for the first property, followed optionally by more name/value pairs, followed by NULL
       
   431  *
       
   432  * Sets properties of the parent object and its children.
       
   433  */
       
   434 #ifdef __SYMBIAN32__
       
   435 EXPORT_C
       
   436 #endif
       
   437 
       
   438 void
       
   439 gst_child_proxy_set (GstObject * object, const gchar * first_property_name, ...)
       
   440 {
       
   441   va_list var_args;
       
   442 
       
   443   g_return_if_fail (GST_IS_OBJECT (object));
       
   444 
       
   445   va_start (var_args, first_property_name);
       
   446   gst_child_proxy_set_valist (object, first_property_name, var_args);
       
   447   va_end (var_args);
       
   448 }
       
   449 
       
   450 /**
       
   451  * gst_child_proxy_child_added:
       
   452  * @object: the parent object
       
   453  * @child: the newly added child
       
   454  *
       
   455  * Emits the "child-added" signal.
       
   456  */
       
   457 #ifdef __SYMBIAN32__
       
   458 EXPORT_C
       
   459 #endif
       
   460 
       
   461 void
       
   462 gst_child_proxy_child_added (GstObject * object, GstObject * child)
       
   463 {
       
   464   g_signal_emit (G_OBJECT (object), signals[CHILD_ADDED], 0, child);
       
   465 }
       
   466 
       
   467 /**
       
   468  * gst_child_proxy_child_removed:
       
   469  * @object: the parent object
       
   470  * @child: the newly added child
       
   471  *
       
   472  * Emits the "child-removed" signal.
       
   473  */
       
   474 #ifdef __SYMBIAN32__
       
   475 EXPORT_C
       
   476 #endif
       
   477 
       
   478 void
       
   479 gst_child_proxy_child_removed (GstObject * object, GstObject * child)
       
   480 {
       
   481   g_signal_emit (G_OBJECT (object), signals[CHILD_REMOVED], 0, child);
       
   482 }
       
   483 
       
   484 /* gobject methods */
       
   485 
       
   486 static void
       
   487 gst_child_proxy_base_init (gpointer g_class)
       
   488 {
       
   489   static gboolean initialized = FALSE;
       
   490 
       
   491   if (!initialized) {
       
   492     /* create interface signals and properties here. */
       
   493         /**
       
   494 	 * GstChildProxy::child-added:
       
   495 	 * @child_proxy: the #GstChildProxy
       
   496 	 * @object: the #GObject that was added
       
   497 	 *
       
   498 	 * Will be emitted after the @object was added to the @child_proxy.
       
   499 	 */
       
   500     signals[CHILD_ADDED] =
       
   501         g_signal_new ("child-added", G_TYPE_FROM_CLASS (g_class),
       
   502         G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstChildProxyInterface,
       
   503             child_added), NULL, NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
       
   504         G_TYPE_OBJECT);
       
   505 
       
   506         /**
       
   507 	 * GstChildProxy::child-removed:
       
   508 	 * @child_proxy: the #GstChildProxy
       
   509 	 * @object: the #GObject that was removed
       
   510 	 *
       
   511 	 * Will be emitted after the @object was removed from the @child_proxy.
       
   512 	 */
       
   513     signals[CHILD_REMOVED] =
       
   514         g_signal_new ("child-removed", G_TYPE_FROM_CLASS (g_class),
       
   515         G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstChildProxyInterface,
       
   516             child_removed), NULL, NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE,
       
   517         1, G_TYPE_OBJECT);
       
   518 
       
   519     initialized = TRUE;
       
   520   }
       
   521 }
       
   522 #ifdef __SYMBIAN32__
       
   523 EXPORT_C
       
   524 #endif
       
   525 
       
   526 
       
   527 GType
       
   528 gst_child_proxy_get_type (void)
       
   529 {
       
   530   static GType type = 0;
       
   531 
       
   532   if (G_UNLIKELY (type == 0)) {
       
   533     static const GTypeInfo info = {
       
   534       sizeof (GstChildProxyInterface),
       
   535       gst_child_proxy_base_init,        /* base_init */
       
   536       NULL,                     /* base_finalize */
       
   537       NULL,                     /* class_init */
       
   538       NULL,                     /* class_finalize */
       
   539       NULL,                     /* class_data */
       
   540       0,
       
   541       0,                        /* n_preallocs */
       
   542       NULL                      /* instance_init */
       
   543     };
       
   544     type = g_type_register_static (G_TYPE_INTERFACE, "GstChildProxy", &info, 0);
       
   545 
       
   546     g_type_interface_add_prerequisite (type, GST_TYPE_OBJECT);
       
   547   }
       
   548   return type;
       
   549 }