add reserved fundamental ids for gtk types (for transition time). added
[platform/upstream/glib.git] / gobject / gvalue.c
1 /* GObject - GLib Type, Object, Parameter and Signal Library
2  * Copyright (C) 1997, 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General
15  * Public License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include        "gvalue.h"
20
21
22 /* --- defines --- */
23 #define G_PARAM_SPEC_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_PARAM, GParamSpecClass))
24
25
26 /* --- typedefs & structures --- */
27 typedef struct
28 {
29   GType          value_type1;
30   GType          value_type2;
31   GValueExchange func;
32   GType          first_type;
33 } ExchangeEntry;
34
35
36 /* --- variables --- */
37 static GHashTable *param_exchange_ht = NULL;
38
39
40 /* --- functions --- */
41 void
42 g_value_init (GValue *value,
43               GType   g_type)
44 {
45   GParamSpecClass *pclass;
46
47   g_return_if_fail (value != NULL);
48   g_return_if_fail (G_VALUE_TYPE (value) == 0);
49   g_type = g_type_next_base (g_type, G_TYPE_PARAM);
50   g_return_if_fail (G_TYPE_IS_VALUE (g_type));
51
52   memset (value, 0, sizeof (*value));
53   value->g_type = g_type;
54
55   pclass = g_type_class_ref (G_VALUE_TYPE (value));
56   pclass->param_init (value, NULL);
57   g_type_class_unref (pclass);
58 }
59
60 void
61 g_value_init_default (GValue     *value,
62                       GParamSpec *pspec)
63 {
64   g_return_if_fail (value != NULL);
65   g_return_if_fail (G_VALUE_TYPE (value) == 0);
66   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
67
68   memset (value, 0, sizeof (*value));
69   value->g_type = g_type_next_base (G_PARAM_SPEC_TYPE (pspec), G_TYPE_PARAM);
70
71   G_PARAM_SPEC_GET_CLASS (pspec)->param_init (value, pspec);
72 }
73
74 gboolean
75 g_value_validate (GValue     *value,
76                   GParamSpec *pspec)
77 {
78   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
79   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
80   g_return_val_if_fail (g_type_is_a (G_PARAM_SPEC_TYPE (pspec), G_VALUE_TYPE (value)), FALSE);
81
82   if (G_PARAM_SPEC_GET_CLASS (pspec)->param_validate)
83     {
84       GValue oval = *value;
85       
86       if (G_PARAM_SPEC_GET_CLASS (pspec)->param_validate (value, pspec) ||
87           memcmp (&oval.data, &value->data, sizeof (oval.data)))
88         return TRUE;
89     }
90   return FALSE;
91 }
92
93 gboolean
94 g_value_defaults (const GValue *value,
95                   GParamSpec   *pspec)
96 {
97   GValue dflt_value = { 0, };
98   gboolean defaults;
99
100   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
101   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
102   g_return_val_if_fail (g_type_is_a (G_PARAM_SPEC_TYPE (pspec), G_VALUE_TYPE (value)), FALSE);
103   
104   dflt_value.g_type = g_type_next_base (G_PARAM_SPEC_TYPE (pspec), G_TYPE_PARAM);
105   G_PARAM_SPEC_GET_CLASS (pspec)->param_init (&dflt_value, pspec);
106   defaults = g_values_cmp (value, &dflt_value, pspec) == 0;
107   g_value_unset (&dflt_value);
108
109   return defaults;
110 }
111
112 void
113 g_value_set_default (GValue     *value,
114                      GParamSpec *pspec)
115 {
116   GValue tmp_value = { 0, };
117
118   g_return_if_fail (G_IS_VALUE (value));
119   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
120   g_return_if_fail (g_type_is_a (G_PARAM_SPEC_TYPE (pspec), G_VALUE_TYPE (value)));
121
122   /* retrive default value */
123   tmp_value.g_type = g_type_next_base (G_PARAM_SPEC_TYPE (pspec), G_TYPE_PARAM);
124   G_PARAM_SPEC_GET_CLASS (pspec)->param_init (&tmp_value, pspec);
125
126   /* set default value */
127   g_values_exchange (&tmp_value, value);
128
129   g_value_unset (&tmp_value);
130 }
131
132 gint
133 g_values_cmp (const GValue *value1,
134               const GValue *value2,
135               GParamSpec   *pspec)
136 {
137   GParamSpecClass *pclass;
138   gint cmp;
139
140   /* param_values_cmp() effectively does: value1 - value2
141    * so the return values are:
142    * -1)  value1 < value2
143    *  0)  value1 == value2
144    *  1)  value1 > value2
145    */
146   g_return_val_if_fail (G_IS_VALUE (value1), 0);
147   g_return_val_if_fail (G_IS_VALUE (value2), 0);
148   g_return_val_if_fail (G_VALUE_TYPE (value1) == G_VALUE_TYPE (value2), 0);
149   if (pspec)
150     {
151       g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), 0);
152       g_return_val_if_fail (g_type_is_a (G_PARAM_SPEC_TYPE (pspec), G_VALUE_TYPE (value1)), FALSE);
153     }
154
155   pclass = g_type_class_ref (G_VALUE_TYPE (value1));
156   cmp = pclass->param_values_cmp (value1, value2, pspec);
157   g_type_class_unref (pclass);
158
159   return CLAMP (cmp, -1, 1);
160 }
161
162 void
163 g_value_copy (const GValue *src_value,
164               GValue       *dest_value)
165 {
166   g_return_if_fail (G_IS_VALUE (src_value));
167   g_return_if_fail (G_IS_VALUE (dest_value));
168   g_return_if_fail (G_VALUE_TYPE (src_value) == G_VALUE_TYPE (dest_value));
169
170   if (src_value != dest_value)
171     {
172       GParamSpecClass *pclass = g_type_class_ref (G_VALUE_TYPE (src_value));
173       
174       /* make sure dest_value's value is free()d and zero initialized */
175       g_value_reset (dest_value);
176       
177       if (pclass->param_copy_value)
178         pclass->param_copy_value (src_value, dest_value);
179       else
180         memcpy (&dest_value->data, &src_value->data, sizeof (src_value->data));
181       g_type_class_unref (pclass);
182     }
183 }
184
185 void
186 g_value_unset (GValue *value)
187 {
188   GParamSpecClass *pclass;
189
190   g_return_if_fail (G_IS_VALUE (value));
191
192   pclass = g_type_class_ref (G_VALUE_TYPE (value));
193   if (pclass->param_free_value)
194     pclass->param_free_value (value);
195   memset (value, 0, sizeof (*value));
196   g_type_class_unref (pclass);
197 }
198
199 void
200 g_value_reset (GValue *value)
201 {
202   GParamSpecClass *pclass;
203   GType g_type;
204
205   g_return_if_fail (G_IS_VALUE (value));
206
207   g_type = G_VALUE_TYPE (value);
208   pclass = g_type_class_ref (g_type);
209
210   if (pclass->param_free_value)
211     pclass->param_free_value (value);
212   memset (value, 0, sizeof (*value));
213
214   value->g_type = g_type;
215   pclass->param_init (value, NULL);
216   
217   g_type_class_unref (pclass);
218 }
219
220 static gint
221 exchange_entries_equal (gconstpointer v1,
222                         gconstpointer v2)
223 {
224   const ExchangeEntry *entry1 = v1;
225   const ExchangeEntry *entry2 = v2;
226
227   return (entry1->value_type1 == entry2->value_type1 &&
228           entry1->value_type2 == entry2->value_type2);
229 }
230
231 static guint
232 exchange_entry_hash (gconstpointer key)
233 {
234   const ExchangeEntry *entry = key;
235
236   return entry->value_type1 ^ entry->value_type2;
237 }
238
239 static void
240 value_exchange_memcpy (GValue *value1,
241                        GValue *value2)
242 {
243   GValue tmp_value;
244
245   memcpy (&tmp_value.data, &value1->data, sizeof (value1->data));
246   memcpy (&value1->data, &value2->data, sizeof (value1->data));
247   memcpy (&value2->data, &tmp_value.data, sizeof (value2->data));
248 }
249
250 static inline GValueExchange
251 exchange_func_lookup (GType     value_type1,
252                       GType     value_type2,
253                       gboolean *need_swap)
254 {
255   if (value_type1 == value_type2)
256     return value_exchange_memcpy;
257   else
258     {
259       ExchangeEntry entry, *ret;
260       
261       entry.value_type1 = MIN (value_type1, value_type2);
262       entry.value_type2 = MAX (value_type1, value_type2);
263       
264       ret = g_hash_table_lookup (param_exchange_ht, &entry);
265       if (ret)
266         {
267           if (need_swap)
268             *need_swap = ret->first_type == value_type1;
269
270           return ret->func;
271         }
272     }
273   return NULL;
274 }
275
276 void
277 g_value_register_exchange_func (GType          value_type1,
278                                 GType          value_type2,
279                                 GValueExchange func)
280 {
281   GType type1, type2;
282
283   g_return_if_fail (G_TYPE_IS_VALUE (value_type1));
284   g_return_if_fail (G_TYPE_IS_VALUE (value_type2));
285   g_return_if_fail (func != NULL);
286
287   type1 = g_type_next_base (value_type1, G_TYPE_PARAM);
288   type2 = g_type_next_base (value_type2, G_TYPE_PARAM);
289
290   if (param_exchange_ht && exchange_func_lookup (type1, type2, NULL))
291     g_warning (G_STRLOC ": cannot re-register param value exchange function "
292                "for `%s' and `%s'",
293                g_type_name (type1),
294                g_type_name (type2));
295   else
296     {
297       ExchangeEntry *entry = g_new (ExchangeEntry, 1);
298
299       if (!param_exchange_ht)
300         param_exchange_ht = g_hash_table_new (exchange_entry_hash, exchange_entries_equal);
301       entry->value_type1 = MIN (type1, type2);
302       entry->value_type2 = MAX (type1, type2);
303       entry->func = func;
304       entry->first_type = type1;
305       g_hash_table_insert (param_exchange_ht, entry, entry);
306     }
307 }
308
309 gboolean
310 g_value_types_exchangable (GType value_type1,
311                            GType value_type2)
312 {
313   GType type1, type2;
314
315   g_return_val_if_fail (G_TYPE_IS_VALUE (value_type1), FALSE);
316   g_return_val_if_fail (G_TYPE_IS_VALUE (value_type2), FALSE);
317
318   type1 = g_type_next_base (value_type1, G_TYPE_PARAM);
319   type2 = g_type_next_base (value_type2, G_TYPE_PARAM);
320
321   return exchange_func_lookup (type1, type2, NULL) != NULL;
322 }
323
324 gboolean
325 g_values_exchange (GValue *value1,
326                    GValue *value2)
327 {
328   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
329   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
330
331   if (value1 != value2)
332     {
333       GType type1 = g_type_next_base (G_VALUE_TYPE (value1), G_TYPE_PARAM);
334       GType type2 = g_type_next_base (G_VALUE_TYPE (value2), G_TYPE_PARAM);
335       gboolean need_swap;
336       GValueExchange value_exchange = exchange_func_lookup (type1,
337                                                             type2,
338                                                             &need_swap);
339       if (value_exchange)
340         {
341           if (need_swap)
342             value_exchange (value2, value1);
343           else
344             value_exchange (value1, value2);
345         }
346
347       return value_exchange != NULL;
348     }
349
350   return TRUE;
351 }
352
353 gboolean
354 g_value_convert (const GValue *src_value,
355                  GValue       *dest_value)
356 {
357   gboolean success = TRUE;
358
359   g_return_val_if_fail (G_IS_VALUE (src_value), FALSE);
360   g_return_val_if_fail (G_IS_VALUE (dest_value), FALSE);
361
362   if (src_value != dest_value)
363     {
364       GValue tmp_value = { 0, };
365
366       g_value_init (&tmp_value, G_VALUE_TYPE (src_value));
367       g_value_copy (src_value, &tmp_value);
368       
369       success = g_values_exchange (&tmp_value, dest_value);
370       g_value_unset (&tmp_value);
371     }
372
373   return success;
374 }