"Initial commit to Gerrit"
[profile/ivi/cogl.git] / cogl / cogl-object.c
1 /*
2  * Cogl
3  *
4  * An object oriented GL/GLES Abstraction/Utility Layer
5  *
6  * Copyright (C) 2007,2008,2009,2010 Intel Corporation.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see
20  * <http://www.gnu.org/licenses/>.
21  *
22  * Authors:
23  *   Robert Bragg <robert@linux.intel.com>
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <glib.h>
31 #include <string.h>
32
33 #include "cogl-util.h"
34 #include "cogl-types.h"
35 #include "cogl-object-private.h"
36
37 void *
38 cogl_object_ref (void *object)
39 {
40   CoglObject *obj = object;
41
42   _COGL_RETURN_VAL_IF_FAIL (object != NULL, NULL);
43
44   obj->ref_count++;
45   return object;
46 }
47
48 CoglHandle
49 cogl_handle_ref (CoglHandle handle)
50 {
51   return cogl_object_ref (handle);
52 }
53
54 void
55 _cogl_object_default_unref (void *object)
56 {
57   CoglObject *obj = object;
58
59   _COGL_RETURN_IF_FAIL (object != NULL);
60   _COGL_RETURN_IF_FAIL (obj->ref_count > 0);
61
62   if (--obj->ref_count < 1)
63     {
64       void (*free_func)(void *obj);
65
66       if (obj->n_user_data_entries)
67         {
68           int i;
69           int count = MIN (obj->n_user_data_entries,
70                            COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES);
71
72           for (i = 0; i < count; i++)
73             {
74               CoglUserDataEntry *entry = &obj->user_data_entry[i];
75               if (entry->destroy)
76                 entry->destroy (entry->user_data, obj);
77             }
78
79           if (obj->user_data_array != NULL)
80             {
81               for (i = 0; i < obj->user_data_array->len; i++)
82                 {
83                   CoglUserDataEntry *entry =
84                     &g_array_index (obj->user_data_array,
85                                     CoglUserDataEntry, i);
86
87                   if (entry->destroy)
88                     entry->destroy (entry->user_data, obj);
89                 }
90               g_array_free (obj->user_data_array, TRUE);
91             }
92         }
93
94       COGL_OBJECT_DEBUG_FREE (obj);
95       free_func = obj->klass->virt_free;
96       free_func (obj);
97     }
98 }
99
100 void
101 cogl_object_unref (void *obj)
102 {
103   void (* unref_func) (void *) = ((CoglObject *) obj)->klass->virt_unref;
104   unref_func (obj);
105 }
106
107 void
108 cogl_handle_unref (CoglHandle handle)
109 {
110   cogl_object_unref (handle);
111 }
112
113 GType
114 cogl_handle_get_type (void)
115 {
116   static GType our_type = 0;
117
118   /* XXX: We are keeping the "CoglHandle" name for now incase it would
119    * break bindings to change to "CoglObject" */
120   if (G_UNLIKELY (our_type == 0))
121     our_type = g_boxed_type_register_static (g_intern_static_string ("CoglHandle"),
122                                              (GBoxedCopyFunc) cogl_object_ref,
123                                              (GBoxedFreeFunc) cogl_object_unref);
124
125   return our_type;
126 }
127
128 /* XXX: Unlike for cogl_object_get_user_data this code will return
129  * an empty entry if available and no entry for the given key can be
130  * found. */
131 static CoglUserDataEntry *
132 _cogl_object_find_entry (CoglObject *object, CoglUserDataKey *key)
133 {
134   CoglUserDataEntry *entry = NULL;
135   int count;
136   int i;
137
138   count = MIN (object->n_user_data_entries,
139                COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES);
140
141   for (i = 0; i < count; i++)
142     {
143       CoglUserDataEntry *current = &object->user_data_entry[i];
144       if (current->key == key)
145         return current;
146       if (current->user_data == NULL)
147         entry = current;
148     }
149
150   if (G_UNLIKELY (object->user_data_array != NULL))
151     {
152       for (i = 0; i < object->user_data_array->len; i++)
153         {
154           CoglUserDataEntry *current =
155             &g_array_index (object->user_data_array, CoglUserDataEntry, i);
156
157           if (current->key == key)
158             return current;
159           if (current->user_data == NULL)
160             entry = current;
161         }
162     }
163
164   return entry;
165 }
166
167 void
168 _cogl_object_set_user_data (CoglObject *object,
169                             CoglUserDataKey *key,
170                             void *user_data,
171                             CoglUserDataDestroyInternalCallback destroy)
172 {
173   CoglUserDataEntry new_entry;
174   CoglUserDataEntry *entry;
175
176   if (user_data)
177     {
178       new_entry.key = key;
179       new_entry.user_data = user_data;
180       new_entry.destroy = destroy;
181     }
182   else
183     memset (&new_entry, 0, sizeof (new_entry));
184
185   entry = _cogl_object_find_entry (object, key);
186   if (entry)
187     {
188       if (G_LIKELY (entry->destroy))
189         entry->destroy (entry->user_data, object);
190     }
191   else
192     {
193       /* NB: Setting a value of NULL is documented to delete the
194        * corresponding entry so we can return immediately in this
195        * case. */
196       if (user_data == NULL)
197         return;
198
199       if (G_LIKELY (object->n_user_data_entries <
200                     COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES))
201         entry = &object->user_data_entry[object->n_user_data_entries++];
202       else
203         {
204           if (G_UNLIKELY (object->user_data_array == NULL))
205             {
206               object->user_data_array =
207                 g_array_new (FALSE, FALSE, sizeof (CoglUserDataEntry));
208             }
209
210           g_array_set_size (object->user_data_array,
211                             object->user_data_array->len + 1);
212           entry =
213             &g_array_index (object->user_data_array, CoglUserDataEntry,
214                             object->user_data_array->len - 1);
215
216           object->n_user_data_entries++;
217         }
218     }
219
220   *entry = new_entry;
221 }
222
223 void
224 cogl_object_set_user_data (CoglObject *object,
225                            CoglUserDataKey *key,
226                            void *user_data,
227                            CoglUserDataDestroyCallback destroy)
228 {
229   _cogl_object_set_user_data (object, key, user_data,
230                               (CoglUserDataDestroyInternalCallback)destroy);
231 }
232
233 void *
234 cogl_object_get_user_data (CoglObject *object, CoglUserDataKey *key)
235 {
236   int count;
237   int i;
238
239   count = MIN (object->n_user_data_entries,
240                COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES);
241
242   for (i = 0; i < count; i++)
243     {
244       CoglUserDataEntry *entry = &object->user_data_entry[i];
245       if (entry->key == key)
246         return entry->user_data;
247     }
248
249   if (object->user_data_array != NULL)
250     {
251       for (i = 0; i < object->user_data_array->len; i++)
252         {
253           CoglUserDataEntry *entry =
254             &g_array_index (object->user_data_array, CoglUserDataEntry, i);
255
256           if (entry->key == key)
257             return entry->user_data;
258         }
259     }
260
261   return NULL;
262 }
263
264 void
265 cogl_debug_object_foreach_type (CoglDebugObjectForeachTypeCallback func,
266                                 void *user_data)
267 {
268   GHashTableIter iter;
269   unsigned long *instance_count;
270   CoglDebugObjectTypeInfo info;
271
272   g_hash_table_iter_init (&iter, _cogl_debug_instances);
273   while (g_hash_table_iter_next (&iter,
274                                  (void *) &info.name,
275                                  (void *) &instance_count))
276     {
277       info.instance_count = *instance_count;
278       func (&info, user_data);
279     }
280 }
281
282 static void
283 print_instances_cb (const CoglDebugObjectTypeInfo *info,
284                     void *user_data)
285 {
286   g_print ("\t%s: %lu\n", info->name, info->instance_count);
287 }
288
289 void
290 cogl_debug_object_print_instances (void)
291 {
292   g_print ("Cogl instances:\n");
293
294   cogl_debug_object_foreach_type (print_instances_cb, NULL);
295 }