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