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