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