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