This is a megapatch with the following changes:
[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   LAST_SIGNAL
31 };
32
33 enum {
34   ARG_0,
35   /* FILL ME */
36 };
37
38
39 static void             gst_object_class_init           (GstObjectClass *klass);
40 static void             gst_object_init                 (GstObject *object);
41
42 static GtkObjectClass *parent_class = NULL;
43 static guint gst_object_signals[LAST_SIGNAL] = { 0 };
44
45 GtkType
46 gst_object_get_type (void)
47 {
48   static GtkType object_type = 0;
49
50   if (!object_type) {
51     static const GtkTypeInfo object_info = {
52       "GstObject",
53       sizeof(GstObject),
54       sizeof(GstObjectClass),
55       (GtkClassInitFunc)gst_object_class_init,
56       (GtkObjectInitFunc)gst_object_init,
57       (GtkArgSetFunc)NULL,
58       (GtkArgGetFunc)NULL,
59       (GtkClassInitFunc)NULL,
60     };
61     object_type = gtk_type_unique(gtk_object_get_type(),&object_info);
62   }
63   return object_type;
64 }
65
66 static void
67 gst_object_class_init (GstObjectClass *klass)
68 {
69   GtkObjectClass *gtkobject_class;
70
71   gtkobject_class = (GtkObjectClass*) klass;
72
73   parent_class = gtk_type_class (gtk_object_get_type ());
74
75   gst_object_signals[PARENT_SET] =
76     gtk_signal_new ("parent_set", GTK_RUN_LAST, gtkobject_class->type,
77                     GTK_SIGNAL_OFFSET (GstObjectClass, parent_set),
78                     gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
79                     GST_TYPE_OBJECT);
80   gtk_object_class_add_signals (gtkobject_class, gst_object_signals, LAST_SIGNAL);
81
82   klass->path_string_separator = "/";
83 }
84
85 static void
86 gst_object_init (GstObject *object)
87 {
88   object->lock = g_mutex_new();
89 #ifdef HAVE_ATOMIC_H
90   atomic_set(&(object->refcount),1);
91 #else
92   object->refcount++;
93 #endif
94   object->parent = NULL;
95 }
96
97 /**
98  * gst_object_new:
99  *
100  * Create a new, empty object.  Not very useful, should never be used.
101  *
102  * Returns: new object
103  */
104 GstObject*
105 gst_object_new (void)
106 {
107   return GST_OBJECT (gtk_type_new (gst_object_get_type ()));
108 }
109
110 /**
111  * gst_object_set_name:
112  * @object: GstObject to set the name of
113  * @name: new name of object
114  *
115  * Set the name of the object.
116  */
117 void
118 gst_object_set_name (GstObject *object, const gchar *name)
119 {
120   g_return_if_fail (object != NULL);
121   g_return_if_fail (GST_IS_OBJECT (object));
122   g_return_if_fail (name != NULL);
123
124   if (object->name != NULL)
125     g_free (object->name);
126
127   object->name = g_strdup (name);
128 }
129
130 /**
131  * gst_object_get_name:
132  * @object: GstObject to get the name of
133  *
134  * Get the name of the object.
135  *
136  * Returns: name of the object
137  */
138 const gchar*
139 gst_object_get_name (GstObject *object)
140 {
141   g_return_val_if_fail (object != NULL, NULL);
142   g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
143
144   return object->name;
145 }
146
147 /**
148  * gst_object_set_parent:
149  * @object: GstObject to set parent of
150  * @parent: new parent of object
151  *
152  * Set the parent of the object.  The object's reference count is
153  * incremented.
154  * signals the parent-set signal
155  */
156 void
157 gst_object_set_parent (GstObject *object, GstObject *parent)
158 {
159   g_return_if_fail (object != NULL);
160   g_return_if_fail (GST_IS_OBJECT (object));
161   g_return_if_fail (parent != NULL);
162   g_return_if_fail (GST_IS_OBJECT (parent));
163   g_return_if_fail (object != parent);
164
165   if (object->parent != NULL) {
166     GST_ERROR_OBJECT (object,object->parent, "object's parent is already set, must unparent first");
167     return;
168   }
169
170   gst_object_ref (object);
171   gst_object_sink (object);
172   object->parent = parent;
173
174   gtk_signal_emit (GTK_OBJECT (object), gst_object_signals[PARENT_SET], parent);
175 }
176
177 /**
178  * gst_object_get_parent:
179  * @object: GstObject to get parent of
180  *
181  * Return the parent of the object.
182  *
183  * Returns: parent of the object
184  */
185 GstObject*
186 gst_object_get_parent (GstObject *object)
187 {
188   g_return_val_if_fail (object != NULL, NULL);
189   g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
190
191   return object->parent;
192 }
193
194 /**
195  * gst_object_unparent:
196  * @object: GstObject to unparent
197  *
198  * Clear the parent of the object, removing the associated reference.
199  */
200 void
201 gst_object_unparent (GstObject *object)
202 {
203   g_return_if_fail (object != NULL);
204   g_return_if_fail (GST_IS_OBJECT(object));
205   if (object->parent == NULL)
206     return;
207
208   object->parent = NULL;
209   gst_object_unref (object);
210 }
211
212 /**
213  * gst_object_ref:
214  * @object: GstObject to reference
215  *
216  * Increments the refence count on the object.
217  */
218 #ifndef gst_object_ref
219 void
220 gst_object_ref (GstObject *object)
221 {
222   g_return_if_fail (object != NULL);
223   g_return_if_fail (GST_IS_OBJECT (object));
224
225 #ifdef HAVE_ATOMIC_H
226   g_return_if_fail (atomic_read (&(object->refcount)) > 0);
227   atomic_inc (&(object->refcount))
228 #else
229   g_return_if_fail (object->refcount > 0);
230   GST_LOCK (object);
231   object->refcount++;
232   GST_UNLOCK (object);
233 #endif
234 }
235 #endif /* gst_object_ref */
236
237 /**
238  * gst_object_unref:
239  * @object: GstObject to unreference
240  *
241  * Decrements the refence count on the object.  If reference count hits
242  * zero, destroy the object.
243  */
244 #ifndef gst_object_unref
245 void
246 gst_object_unref (GstObject *object)
247 {
248   int reftest;
249
250   g_return_if_fail (object != NULL);
251   g_return_if_fail (GST_IS_OBJECT (object));
252
253 #ifdef HAVE_ATOMIC_H
254   g_return_if_fail (atomic_read (&(object->refcount)) > 0);
255   reftest = atomic_dec_and_test (&(object->refcount))
256 #else
257   g_return_if_fail (object->refcount > 0);
258   GST_LOCK (object);
259   object->refcount--;
260   reftest = (object->refcount == 0);
261   GST_UNLOCK (object);
262 #endif
263
264   /* if we ended up with the refcount at zero */
265   if (reftest) {
266     /* get the count to 1 for gtk_object_destroy() */
267 #ifdef HAVE_ATOMIC_H
268     atomic_set (&(object->refcount),1);
269 #else
270     object->refcount = 1;
271 #endif
272     /* destroy it */
273     gtk_object_destroy (GTK_OBJECT (object));
274     /* drop the refcount back to zero */
275 #ifdef HAVE_ATOMIC_H
276     atomic_set (&(object->refcount),0);
277 #else
278     object->refcount = 0;
279 #endif
280     /* finalize the object */
281     // FIXME this is an evil hack that should be killed
282 // FIXMEFIXMEFIXMEFIXME
283 //    gtk_object_finalize(GTK_OBJECT(object));
284   }
285 }
286 #endif /* gst_object_unref */
287
288 /**
289  * gst_object_sink:
290  * @object: GstObject to sink
291  *
292  * Removes floating reference on an object.  Any newly created object has
293  * a refcount of 1 and is FLOATING.  This function should be used when
294  * creating a new object to symbolically 'take ownership of' the object.
295  */
296 #ifndef gst_object_sink
297 void
298 gst_object_sink (GstObject *object)
299 {
300   g_return_if_fail (object != NULL);
301   g_return_if_fail (GST_IS_OBJECT (object));
302
303   if (GTK_OBJECT_FLOATING (object)) {
304     GTK_OBJECT_UNSET_FLAGS (object, GTK_FLOATING);
305     gst_object_unref (object);
306   }
307 }
308 #endif /* gst_object_sink */
309
310 xmlNodePtr
311 gst_object_save_thyself (GstObject *object, xmlNodePtr parent)
312 {
313   GstObjectClass *oclass;
314
315   g_return_val_if_fail (object != NULL, parent);
316   g_return_val_if_fail (GST_IS_OBJECT (object), parent);
317   g_return_val_if_fail (parent != NULL, parent);
318
319   oclass = GST_OBJECT_CLASS (GTK_OBJECT (object)->klass);
320
321   if (oclass->save_thyself)
322     oclass->save_thyself (object, parent);
323
324   return parent;
325 }
326
327 void
328 gst_object_load_thyself (xmlNodePtr self, GstObject *parent)
329 {
330   g_print ("gstobject: load thyself\n");
331 }
332
333 /**
334  * gst_object_get_path_string:
335  * @object: GstObject to get the path from
336  *
337  * Generates a string describing the path of the object in
338  * the object hierarchy. Usefull for debugging
339  *
340  * Returns: a string describing the path of the object
341  */
342 gchar*
343 gst_object_get_path_string (GstObject *object)
344 {
345   GSList *parentage = NULL;
346   GSList *parents;
347   void *parent;
348   gchar *prevpath, *path = "";
349   const char *component;
350   gchar *separator = "";
351   gboolean free_component;
352
353   parentage = g_slist_prepend (NULL, object);
354
355   // first walk the object hierarchy to build a list of the parents
356   do {
357     if (GST_IS_OBJECT (object)) {
358       parent = gst_object_get_parent (object);
359     } else {
360       parentage = g_slist_prepend (parentage, NULL);
361       parent = NULL;
362     }
363
364     if (parent != NULL) {
365       parentage = g_slist_prepend (parentage, parent);
366     }
367
368     object = parent;
369   } while (object != NULL);
370
371   // then walk the parent list and print them out
372   parents = parentage;
373   while (parents) {
374     if (GST_IS_OBJECT (parents->data)) {
375       GstObjectClass *oclass = GST_OBJECT_CLASS (GTK_OBJECT (parents->data));
376
377       component = GST_OBJECT_NAME (parents->data);
378       separator = oclass->path_string_separator;
379       free_component = FALSE;
380     } else {
381       component = g_strdup_printf("%p",parents->data);
382       separator = "/";
383       free_component = TRUE;
384     }
385
386     prevpath = path;
387     path = g_strjoin (separator, prevpath, component, NULL);
388     g_free(prevpath);
389     if (free_component)
390       g_free((gchar *)component);
391
392     parents = g_slist_next(parents);
393   }
394
395   g_slist_free (parentage);
396
397   return path;
398 }
399