b25f2bd8f3634e8daf8c951e1c49a9718b39d06d
[platform/upstream/gstreamer.git] / gst / gstobject.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstobject.c: Fundamental class used for all of GStreamer
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "gst_private.h"
24
25 #include "gstobject.h"
26 #include "gstmarshal.h"
27 #include "gstinfo.h"
28
29 #ifndef GST_DISABLE_TRACE
30 #include "gsttrace.h"
31 #endif
32
33 /* Object signals and args */
34 enum
35 {
36   PARENT_SET,
37   PARENT_UNSET,
38 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
39   OBJECT_SAVED,
40 #endif
41   DEEP_NOTIFY,
42   LAST_SIGNAL
43 };
44
45 enum
46 {
47   ARG_0,
48   ARG_NAME
49       /* FILL ME */
50 };
51
52 enum
53 {
54   SO_OBJECT_LOADED,
55   SO_LAST_SIGNAL
56 };
57
58 GType _gst_object_type = 0;
59 static GHashTable *object_name_counts = NULL;
60
61 G_LOCK_DEFINE_STATIC (object_name_mutex);
62
63 typedef struct _GstSignalObject GstSignalObject;
64 typedef struct _GstSignalObjectClass GstSignalObjectClass;
65
66 static GType gst_signal_object_get_type (void);
67 static void gst_signal_object_class_init (GstSignalObjectClass * klass);
68 static void gst_signal_object_init (GstSignalObject * object);
69
70 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
71 static guint gst_signal_object_signals[SO_LAST_SIGNAL] = { 0 };
72 #endif
73
74 static void gst_object_class_init (GstObjectClass * klass);
75 static void gst_object_init (GstObject * object);
76
77 #ifndef GST_DISABLE_TRACE
78 static GObject *gst_object_constructor (GType type,
79     guint n_construct_properties, GObjectConstructParam * construct_params);
80 #endif
81
82 static void gst_object_set_property (GObject * object, guint prop_id,
83     const GValue * value, GParamSpec * pspec);
84 static void gst_object_get_property (GObject * object, guint prop_id,
85     GValue * value, GParamSpec * pspec);
86 static void gst_object_dispatch_properties_changed (GObject * object,
87     guint n_pspecs, GParamSpec ** pspecs);
88
89 static void gst_object_dispose (GObject * object);
90 static void gst_object_finalize (GObject * object);
91
92 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
93 static void gst_object_real_restore_thyself (GstObject * object,
94     xmlNodePtr self);
95 #endif
96
97 static GObjectClass *parent_class = NULL;
98 static guint gst_object_signals[LAST_SIGNAL] = { 0 };
99
100 GType
101 gst_object_get_type (void)
102 {
103   if (!_gst_object_type) {
104     static const GTypeInfo object_info = {
105       sizeof (GstObjectClass),
106       NULL,
107       NULL,
108       (GClassInitFunc) gst_object_class_init,
109       NULL,
110       NULL,
111       sizeof (GstObject),
112       32,
113       (GInstanceInitFunc) gst_object_init,
114       NULL
115     };
116     _gst_object_type =
117         g_type_register_static (G_TYPE_OBJECT, "GstObject", &object_info,
118         G_TYPE_FLAG_ABSTRACT);
119   }
120   return _gst_object_type;
121 }
122
123 static void
124 gst_object_class_init (GstObjectClass * klass)
125 {
126   GObjectClass *gobject_class;
127
128   gobject_class = (GObjectClass *) klass;
129
130   parent_class = g_type_class_ref (G_TYPE_OBJECT);
131
132   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_object_set_property);
133   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_object_get_property);
134
135   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NAME,
136       g_param_spec_string ("name", "Name", "The name of the object",
137           NULL, G_PARAM_READWRITE));
138
139   gst_object_signals[PARENT_SET] =
140       g_signal_new ("parent-set", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
141       G_STRUCT_OFFSET (GstObjectClass, parent_set), NULL, NULL,
142       g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT);
143   gst_object_signals[PARENT_UNSET] =
144       g_signal_new ("parent-unset", G_TYPE_FROM_CLASS (klass),
145       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstObjectClass, parent_unset), NULL,
146       NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT);
147 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
148   /* FIXME This should be the GType of xmlNodePtr instead of G_TYPE_POINTER */
149   gst_object_signals[OBJECT_SAVED] =
150       g_signal_new ("object-saved", G_TYPE_FROM_CLASS (klass),
151       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstObjectClass, object_saved), NULL,
152       NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
153
154   klass->restore_thyself = gst_object_real_restore_thyself;
155 #endif
156   gst_object_signals[DEEP_NOTIFY] =
157       g_signal_new ("deep-notify", G_TYPE_FROM_CLASS (klass),
158       G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED |
159       G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET (GstObjectClass, deep_notify), NULL,
160       NULL, gst_marshal_VOID__OBJECT_PARAM, G_TYPE_NONE, 2, G_TYPE_OBJECT,
161       G_TYPE_PARAM);
162
163   klass->path_string_separator = "/";
164
165   klass->signal_object = g_object_new (gst_signal_object_get_type (), NULL);
166
167   /* see the comments at gst_object_dispatch_properties_changed */
168   gobject_class->dispatch_properties_changed
169       = GST_DEBUG_FUNCPTR (gst_object_dispatch_properties_changed);
170
171   gobject_class->dispose = gst_object_dispose;
172   gobject_class->finalize = gst_object_finalize;
173 #ifndef GST_DISABLE_TRACE
174   gobject_class->constructor = gst_object_constructor;
175 #endif
176 }
177
178 static void
179 gst_object_init (GstObject * object)
180 {
181   object->lock = g_mutex_new ();
182   object->parent = NULL;
183   object->name = NULL;
184
185   object->flags = 0;
186   GST_FLAG_SET (object, GST_FLOATING);
187 }
188
189 #ifndef GST_DISABLE_TRACE
190 static GObject *
191 gst_object_constructor (GType type, guint n_construct_properties,
192     GObjectConstructParam * construct_params)
193 {
194   const gchar *name;
195   GstAllocTrace *trace;
196   GObject *obj =
197       G_OBJECT_CLASS (parent_class)->constructor (type, n_construct_properties,
198       construct_params);
199
200   name = g_type_name (type);
201
202   trace = gst_alloc_trace_get (name);
203   if (!trace) {
204     trace = gst_alloc_trace_register (name);
205   }
206   gst_alloc_trace_new (trace, obj);
207
208   return obj;
209 }
210 #endif
211 /**
212  * gst_object_ref:
213  * @object: GstObject to reference
214  *
215  * Increments the refence count on the object.
216  *
217  * Returns: A pointer to the object
218  */
219 GstObject *
220 gst_object_ref (GstObject * object)
221 {
222   g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
223
224   GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "ref %d->%d",
225       G_OBJECT (object)->ref_count, G_OBJECT (object)->ref_count + 1);
226
227   g_object_ref (G_OBJECT (object));
228   return object;
229 }
230
231 /**
232  * gst_object_unref:
233  * @object: GstObject to unreference
234  *
235  * Decrements the refence count on the object.  If reference count hits
236  * zero, destroy the object.
237  */
238 void
239 gst_object_unref (GstObject * object)
240 {
241   g_return_if_fail (GST_IS_OBJECT (object));
242   g_return_if_fail (G_OBJECT (object)->ref_count > 0);
243
244   GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unref %d->%d",
245       G_OBJECT (object)->ref_count, G_OBJECT (object)->ref_count - 1);
246
247   g_object_unref (G_OBJECT (object));
248 }
249
250 /**
251  * gst_object_sink:
252  * @object: GstObject to sink
253  *
254  * Removes floating reference on an object.  Any newly created object has
255  * a refcount of 1 and is FLOATING.  This function should be used when
256  * creating a new object to symbolically 'take ownership' of the object.
257  * Use #gst_object_set_parent to have this done for you.
258  */
259 void
260 gst_object_sink (GstObject * object)
261 {
262   g_return_if_fail (object != NULL);
263   g_return_if_fail (GST_IS_OBJECT (object));
264
265   GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "sink");
266
267   if (GST_OBJECT_FLOATING (object)) {
268     GST_FLAG_UNSET (object, GST_FLOATING);
269     gst_object_unref (object);
270   }
271 }
272
273 /**
274  * gst_object_replace:
275  * @oldobj: pointer to place of old GstObject
276  * @newobj: new GstObject
277  *
278  * Unrefs the object pointer to by oldobj, refs the newobj and
279  * puts the newobj in *oldobj.
280  */
281 void
282 gst_object_replace (GstObject ** oldobj, GstObject * newobj)
283 {
284   g_return_if_fail (oldobj != NULL);
285   g_return_if_fail (*oldobj == NULL || GST_IS_OBJECT (*oldobj));
286   g_return_if_fail (newobj == NULL || GST_IS_OBJECT (newobj));
287
288   GST_CAT_LOG (GST_CAT_REFCOUNTING, "replace %s %s",
289       *oldobj ? GST_STR_NULL (GST_OBJECT_NAME (*oldobj)) : "(NONE)",
290       newobj ? GST_STR_NULL (GST_OBJECT_NAME (newobj)) : "(NONE)");
291
292   if (*oldobj != newobj) {
293     if (newobj)
294       gst_object_ref (newobj);
295     if (*oldobj)
296       gst_object_unref (*oldobj);
297
298     *oldobj = newobj;
299   }
300 }
301
302 static void
303 gst_object_dispose (GObject * object)
304 {
305   GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
306
307   GST_FLAG_SET (GST_OBJECT (object), GST_DESTROYED);
308   GST_OBJECT_PARENT (object) = NULL;
309
310   parent_class->dispose (object);
311 }
312
313 /* finalize is called when the object has to free its resources */
314 static void
315 gst_object_finalize (GObject * object)
316 {
317   GstObject *gstobject = GST_OBJECT (object);
318
319   GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "finalize");
320
321   g_signal_handlers_destroy (object);
322
323   g_free (gstobject->name);
324
325   g_mutex_free (gstobject->lock);
326
327 #ifndef GST_DISABLE_TRACE
328   {
329     const gchar *name;
330     GstAllocTrace *trace;
331
332     name = g_type_name (G_OBJECT_TYPE (object));
333     trace = gst_alloc_trace_get (name);
334     g_assert (trace);
335     gst_alloc_trace_free (trace, object);
336   }
337 #endif
338
339   parent_class->finalize (object);
340 }
341
342 /* Changing a GObject property of a GstObject will result in "deep_notify"
343  * signals being emitted by the object itself, as well as in each parent
344  * object. This is so that an application can connect a listener to the
345  * top-level bin to catch property-change notifications for all contained
346  * elements. */
347 static void
348 gst_object_dispatch_properties_changed (GObject * object,
349     guint n_pspecs, GParamSpec ** pspecs)
350 {
351   GstObject *gst_object;
352   guint i;
353
354   /* do the standard dispatching */
355   G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object, n_pspecs,
356       pspecs);
357
358   /* now let the parent dispatch those, too */
359   gst_object = GST_OBJECT_PARENT (object);
360   while (gst_object) {
361     /* need own category? */
362     for (i = 0; i < n_pspecs; i++) {
363       GST_CAT_LOG (GST_CAT_EVENT, "deep notification from %s to %s (%s)",
364           GST_OBJECT_NAME (object), GST_OBJECT_NAME (gst_object),
365           pspecs[i]->name);
366       g_signal_emit (gst_object, gst_object_signals[DEEP_NOTIFY],
367           g_quark_from_string (pspecs[i]->name), (GstObject *) object,
368           pspecs[i]);
369     }
370
371     gst_object = GST_OBJECT_PARENT (gst_object);
372   }
373 }
374
375 /** 
376  * gst_object_default_deep_notify:
377  * @object: the #GObject that signalled the notify.
378  * @orig: a #GstObject that initiated the notify.
379  * @pspec: a #GParamSpec of the property.
380  * @excluded_props: a set of user-specified properties to exclude or
381  *  NULL to show all changes.
382  *
383  * Adds a default deep_notify signal callback to an
384  * element. The user data should contain a pointer to an array of
385  * strings that should be excluded from the notify.
386  * The default handler will print the new value of the property 
387  * using g_print.
388  */
389 void
390 gst_object_default_deep_notify (GObject * object, GstObject * orig,
391     GParamSpec * pspec, gchar ** excluded_props)
392 {
393   GValue value = { 0, };        /* the important thing is that value.type = 0 */
394   gchar *str = 0;
395   gchar *name = NULL;
396
397   if (pspec->flags & G_PARAM_READABLE) {
398     /* let's not print these out for excluded properties... */
399     while (excluded_props != NULL && *excluded_props != NULL) {
400       if (strcmp (pspec->name, *excluded_props) == 0)
401         return;
402       excluded_props++;
403     }
404     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
405     g_object_get_property (G_OBJECT (orig), pspec->name, &value);
406
407     if (G_IS_PARAM_SPEC_ENUM (pspec)) {
408       GEnumValue *enum_value;
409
410       enum_value =
411           g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (pspec->value_type)),
412           g_value_get_enum (&value));
413
414       str = g_strdup_printf ("%s (%d)", enum_value->value_nick,
415           enum_value->value);
416     } else {
417       str = g_strdup_value_contents (&value);
418     }
419     name = gst_object_get_path_string (orig);
420     g_print ("%s: %s = %s\n", name, pspec->name, str);
421     g_free (name);
422     g_free (str);
423     g_value_unset (&value);
424   } else {
425     name = gst_object_get_path_string (orig);
426     g_warning ("Parameter %s not readable in %s.", pspec->name, name);
427     g_free (name);
428   }
429 }
430
431 static void
432 gst_object_set_name_default (GstObject * object)
433 {
434   gint count;
435   gchar *name, *tmp;
436   const gchar *type_name;
437
438   type_name = G_OBJECT_TYPE_NAME (object);
439
440   /* to ensure guaranteed uniqueness across threads, only one thread
441    * may ever assign a name */
442   G_LOCK (object_name_mutex);
443
444   if (!object_name_counts) {
445     object_name_counts = g_hash_table_new_full (g_str_hash, g_str_equal,
446         g_free, NULL);
447   }
448
449   count = GPOINTER_TO_INT (g_hash_table_lookup (object_name_counts, type_name));
450   g_hash_table_insert (object_name_counts, g_strdup (type_name),
451       GINT_TO_POINTER (count + 1));
452
453   G_UNLOCK (object_name_mutex);
454
455   /* GstFooSink -> foosinkN */
456   if (strncmp (type_name, "Gst", 3) == 0)
457     type_name += 3;
458   tmp = g_strdup_printf ("%s%d", type_name, count);
459   name = g_ascii_strdown (tmp, strlen (tmp));
460   g_free (tmp);
461
462   gst_object_set_name (object, name);
463   g_free (name);
464 }
465
466 /**
467  * gst_object_set_name:
468  * @object: GstObject to set the name of
469  * @name: new name of object
470  *
471  * Sets the name of the object, or gives the element a guaranteed unique
472  * name (if @name is NULL).
473  */
474 void
475 gst_object_set_name (GstObject * object, const gchar * name)
476 {
477   g_return_if_fail (object != NULL);
478   g_return_if_fail (GST_IS_OBJECT (object));
479
480   if (object->name != NULL)
481     g_free (object->name);
482
483   if (name != NULL)
484     object->name = g_strdup (name);
485   else
486     gst_object_set_name_default (object);
487 }
488
489 /**
490  * gst_object_get_name:
491  * @object: GstObject to get the name of
492  *
493  * Get the name of the object.
494  *
495  * Returns: name of the object
496  */
497 const gchar *
498 gst_object_get_name (GstObject * object)
499 {
500   g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
501
502   return object->name;
503 }
504
505 /**
506  * gst_object_set_parent:
507  * @object: GstObject to set parent of
508  * @parent: new parent of object
509  *
510  * Sets the parent of @object. The object's reference count will be incremented,
511  * and any floating reference will be removed (see gst_object_sink()).
512  *
513  * Causes the parent-set signal to be emitted.
514  */
515 void
516 gst_object_set_parent (GstObject * object, GstObject * parent)
517 {
518   g_return_if_fail (object != NULL);
519   g_return_if_fail (GST_IS_OBJECT (object));
520   g_return_if_fail (parent != NULL);
521   g_return_if_fail (GST_IS_OBJECT (parent));
522   g_return_if_fail (object != parent);
523   g_return_if_fail (object->parent == NULL);
524
525   gst_object_ref (object);
526   gst_object_sink (object);
527   object->parent = parent;
528
529   g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_SET], 0, parent);
530 }
531
532 /**
533  * gst_object_get_parent:
534  * @object: GstObject to get parent of
535  *
536  * Returns the parent of @object.
537  *
538  * Returns: parent of the object
539  */
540 GstObject *
541 gst_object_get_parent (GstObject * object)
542 {
543   g_return_val_if_fail (object != NULL, NULL);
544   g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
545
546   return object->parent;
547 }
548
549 /**
550  * gst_object_unparent:
551  * @object: GstObject to unparent
552  *
553  * Clear the parent of @object, removing the associated reference.
554  */
555 void
556 gst_object_unparent (GstObject * object)
557 {
558   g_return_if_fail (object != NULL);
559   g_return_if_fail (GST_IS_OBJECT (object));
560   if (object->parent == NULL)
561     return;
562
563   GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unparent");
564
565   g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_UNSET], 0,
566       object->parent);
567
568   object->parent = NULL;
569   gst_object_unref (object);
570 }
571
572 /**
573  * gst_object_check_uniqueness:
574  * @list: a list of #GstObject to check through
575  * @name: the name to search for
576  *
577  * Checks to see if there is any object named @name in @list.
578  *
579  * Returns: TRUE if the name does not appear in the list, FALSE if it does.
580  */
581 gboolean
582 gst_object_check_uniqueness (GList * list, const gchar * name)
583 {
584   g_return_val_if_fail (name != NULL, FALSE);
585
586   while (list) {
587     GstObject *child = GST_OBJECT (list->data);
588
589     list = g_list_next (list);
590
591     if (strcmp (GST_OBJECT_NAME (child), name) == 0)
592       return FALSE;
593   }
594
595   return TRUE;
596 }
597
598
599 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
600 /**
601  * gst_object_save_thyself:
602  * @object: GstObject to save
603  * @parent: The parent XML node to save the object into
604  *
605  * Saves the given object into the parent XML node.
606  *
607  * Returns: the new xmlNodePtr with the saved object
608  */
609 xmlNodePtr
610 gst_object_save_thyself (GstObject * object, xmlNodePtr parent)
611 {
612   GstObjectClass *oclass;
613
614   g_return_val_if_fail (object != NULL, parent);
615   g_return_val_if_fail (GST_IS_OBJECT (object), parent);
616   g_return_val_if_fail (parent != NULL, parent);
617
618   oclass = GST_OBJECT_GET_CLASS (object);
619
620   if (oclass->save_thyself)
621     oclass->save_thyself (object, parent);
622
623   g_signal_emit (G_OBJECT (object), gst_object_signals[OBJECT_SAVED], 0,
624       parent);
625
626   return parent;
627 }
628
629 /**
630  * gst_object_restore_thyself:
631  * @object: GstObject to load into
632  * @self: The XML node to load the object from
633  *
634  * Restores the given object with the data from the parent XML node.
635  */
636 void
637 gst_object_restore_thyself (GstObject * object, xmlNodePtr self)
638 {
639   GstObjectClass *oclass;
640
641   g_return_if_fail (object != NULL);
642   g_return_if_fail (GST_IS_OBJECT (object));
643   g_return_if_fail (self != NULL);
644
645   oclass = GST_OBJECT_GET_CLASS (object);
646
647   if (oclass->restore_thyself)
648     oclass->restore_thyself (object, self);
649 }
650
651 static void
652 gst_object_real_restore_thyself (GstObject * object, xmlNodePtr self)
653 {
654   g_return_if_fail (object != NULL);
655   g_return_if_fail (GST_IS_OBJECT (object));
656   g_return_if_fail (self != NULL);
657
658   gst_class_signal_emit_by_name (object, "object_loaded", self);
659 }
660 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */
661
662 static void
663 gst_object_set_property (GObject * object, guint prop_id,
664     const GValue * value, GParamSpec * pspec)
665 {
666   GstObject *gstobject;
667
668   /* it's not null if we got it, but it might not be ours */
669   g_return_if_fail (GST_IS_OBJECT (object));
670
671   gstobject = GST_OBJECT (object);
672
673   switch (prop_id) {
674     case ARG_NAME:
675       gst_object_set_name (gstobject, g_value_get_string (value));
676       break;
677     default:
678       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
679       break;
680   }
681 }
682
683 static void
684 gst_object_get_property (GObject * object, guint prop_id,
685     GValue * value, GParamSpec * pspec)
686 {
687   GstObject *gstobject;
688
689   /* it's not null if we got it, but it might not be ours */
690   g_return_if_fail (GST_IS_OBJECT (object));
691
692   gstobject = GST_OBJECT (object);
693
694   switch (prop_id) {
695     case ARG_NAME:
696       g_value_set_string (value, (gchar *) GST_OBJECT_NAME (gstobject));
697       break;
698     default:
699       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
700       break;
701   }
702 }
703
704 /**
705  * gst_object_get_path_string:
706  * @object: GstObject to get the path from
707  *
708  * Generates a string describing the path of the object in
709  * the object hierarchy. Only useful (or used) for debugging.
710  *
711  * Returns: a string describing the path of the object
712  */
713 gchar *
714 gst_object_get_path_string (GstObject * object)
715 {
716   GSList *parentage = NULL;
717   GSList *parents;
718   void *parent;
719   gchar *prevpath, *path;
720   const char *component;
721   gchar *separator = "";
722   gboolean free_component;
723
724   parentage = g_slist_prepend (NULL, object);
725
726   path = g_strdup ("");
727
728   /* first walk the object hierarchy to build a list of the parents */
729   do {
730     if (GST_IS_OBJECT (object)) {
731       parent = gst_object_get_parent (object);
732     } else {
733       parentage = g_slist_prepend (parentage, NULL);
734       parent = NULL;
735     }
736
737     if (parent != NULL) {
738       parentage = g_slist_prepend (parentage, parent);
739     }
740
741     object = parent;
742   } while (object != NULL);
743
744   /* then walk the parent list and print them out */
745   parents = parentage;
746   while (parents) {
747     if (GST_IS_OBJECT (parents->data)) {
748       GstObjectClass *oclass = GST_OBJECT_GET_CLASS (parents->data);
749
750       component = gst_object_get_name (parents->data);
751       separator = oclass->path_string_separator;
752       free_component = FALSE;
753     } else {
754       component = g_strdup_printf ("%p", parents->data);
755       separator = "/";
756       free_component = TRUE;
757     }
758
759     prevpath = path;
760     path = g_strjoin (separator, prevpath, component, NULL);
761     g_free (prevpath);
762     if (free_component)
763       g_free ((gchar *) component);
764
765     parents = g_slist_next (parents);
766   }
767
768   g_slist_free (parentage);
769
770   return path;
771 }
772
773
774
775 struct _GstSignalObject
776 {
777   GObject object;
778 };
779
780 struct _GstSignalObjectClass
781 {
782   GObjectClass parent_class;
783
784   /* signals */
785 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
786   void (*object_loaded) (GstSignalObject * object, GstObject * new,
787       xmlNodePtr self);
788 #endif                          /* GST_DISABLE_LOADSAVE_REGISTRY */
789 };
790
791 static GType
792 gst_signal_object_get_type (void)
793 {
794   static GType signal_object_type = 0;
795
796   if (!signal_object_type) {
797     static const GTypeInfo signal_object_info = {
798       sizeof (GstSignalObjectClass),
799       NULL,
800       NULL,
801       (GClassInitFunc) gst_signal_object_class_init,
802       NULL,
803       NULL,
804       sizeof (GstSignalObject),
805       16,
806       (GInstanceInitFunc) gst_signal_object_init,
807       NULL
808     };
809     signal_object_type =
810         g_type_register_static (G_TYPE_OBJECT, "GstSignalObject",
811         &signal_object_info, 0);
812   }
813   return signal_object_type;
814 }
815
816 static void
817 gst_signal_object_class_init (GstSignalObjectClass * klass)
818 {
819   GObjectClass *gobject_class;
820
821   gobject_class = (GObjectClass *) klass;
822
823   parent_class = g_type_class_ref (G_TYPE_OBJECT);
824
825 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
826   gst_signal_object_signals[SO_OBJECT_LOADED] =
827       g_signal_new ("object-loaded", G_TYPE_FROM_CLASS (klass),
828       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstSignalObjectClass, object_loaded),
829       NULL, NULL, gst_marshal_VOID__OBJECT_POINTER, G_TYPE_NONE, 2,
830       G_TYPE_OBJECT, G_TYPE_POINTER);
831 #endif
832 }
833
834 static void
835 gst_signal_object_init (GstSignalObject * object)
836 {
837 }
838
839 /**
840  * gst_class_signal_connect
841  * @klass: the GstObjectClass to attach the signal to
842  * @name: the name of the signal to attach to
843  * @func: the signal function
844  * @func_data: a pointer to user data
845  *
846  * Connect to a class signal.
847  *
848  * Returns: the signal id.
849  */
850 guint
851 gst_class_signal_connect (GstObjectClass * klass,
852     const gchar * name, gpointer func, gpointer func_data)
853 {
854   return g_signal_connect (klass->signal_object, name, func, func_data);
855 }
856
857 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
858 /**
859  * gst_class_signal_emit_by_name:
860  * @object: the object that sends the signal
861  * @name: the name of the signal to emit
862  * @self: data for the signal
863  *
864  * emits the named class signal.
865  */
866 void
867 gst_class_signal_emit_by_name (GstObject * object,
868     const gchar * name, xmlNodePtr self)
869 {
870   GstObjectClass *oclass;
871
872   oclass = GST_OBJECT_GET_CLASS (object);
873
874   g_signal_emit_by_name (oclass->signal_object, name, object, self);
875 }
876
877 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */