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