1 | /* GObject - GLib Type, Object, Parameter and Signal Library |
---|
2 | * Copyright (C) 1997-1999, 2000-2001 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 | |
---|
20 | /* |
---|
21 | * MT safe |
---|
22 | */ |
---|
23 | |
---|
24 | #include "gparam.h" |
---|
25 | #include "gparamspecs.h" |
---|
26 | |
---|
27 | #include "gvaluecollector.h" |
---|
28 | #include <string.h> |
---|
29 | |
---|
30 | |
---|
31 | |
---|
32 | /* --- defines --- */ |
---|
33 | #define G_PARAM_USER_MASK (~0 << G_PARAM_USER_SHIFT) |
---|
34 | #define PSPEC_APPLIES_TO_VALUE(pspec, value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_PARAM_SPEC_VALUE_TYPE (pspec))) |
---|
35 | #define G_SLOCK(mutex) g_static_mutex_lock (mutex) |
---|
36 | #define G_SUNLOCK(mutex) g_static_mutex_unlock (mutex) |
---|
37 | |
---|
38 | |
---|
39 | /* --- prototypes --- */ |
---|
40 | static void g_param_spec_class_base_init (GParamSpecClass *class); |
---|
41 | static void g_param_spec_class_base_finalize (GParamSpecClass *class); |
---|
42 | static void g_param_spec_class_init (GParamSpecClass *class, |
---|
43 | gpointer class_data); |
---|
44 | static void g_param_spec_init (GParamSpec *pspec, |
---|
45 | GParamSpecClass *class); |
---|
46 | static void g_param_spec_finalize (GParamSpec *pspec); |
---|
47 | static void value_param_init (GValue *value); |
---|
48 | static void value_param_free_value (GValue *value); |
---|
49 | static void value_param_copy_value (const GValue *src_value, |
---|
50 | GValue *dest_value); |
---|
51 | static void value_param_transform_value (const GValue *src_value, |
---|
52 | GValue *dest_value); |
---|
53 | static gpointer value_param_peek_pointer (const GValue *value); |
---|
54 | static gchar* value_param_collect_value (GValue *value, |
---|
55 | guint n_collect_values, |
---|
56 | GTypeCValue *collect_values, |
---|
57 | guint collect_flags); |
---|
58 | static gchar* value_param_lcopy_value (const GValue *value, |
---|
59 | guint n_collect_values, |
---|
60 | GTypeCValue *collect_values, |
---|
61 | guint collect_flags); |
---|
62 | |
---|
63 | |
---|
64 | /* --- variables --- */ |
---|
65 | static GQuark quark_floating = 0; |
---|
66 | G_LOCK_DEFINE_STATIC (pspec_ref_count); |
---|
67 | |
---|
68 | |
---|
69 | /* --- functions --- */ |
---|
70 | void |
---|
71 | g_param_type_init (void) /* sync with gtype.c */ |
---|
72 | { |
---|
73 | static const GTypeFundamentalInfo finfo = { |
---|
74 | (G_TYPE_FLAG_CLASSED | |
---|
75 | G_TYPE_FLAG_INSTANTIATABLE | |
---|
76 | G_TYPE_FLAG_DERIVABLE | |
---|
77 | G_TYPE_FLAG_DEEP_DERIVABLE), |
---|
78 | }; |
---|
79 | static const GTypeValueTable param_value_table = { |
---|
80 | value_param_init, /* value_init */ |
---|
81 | value_param_free_value, /* value_free */ |
---|
82 | value_param_copy_value, /* value_copy */ |
---|
83 | value_param_peek_pointer, /* value_peek_pointer */ |
---|
84 | "p", /* collect_format */ |
---|
85 | value_param_collect_value, /* collect_value */ |
---|
86 | "p", /* lcopy_format */ |
---|
87 | value_param_lcopy_value, /* lcopy_value */ |
---|
88 | }; |
---|
89 | static const GTypeInfo param_spec_info = { |
---|
90 | sizeof (GParamSpecClass), |
---|
91 | |
---|
92 | (GBaseInitFunc) g_param_spec_class_base_init, |
---|
93 | (GBaseFinalizeFunc) g_param_spec_class_base_finalize, |
---|
94 | (GClassInitFunc) g_param_spec_class_init, |
---|
95 | (GClassFinalizeFunc) NULL, |
---|
96 | NULL, /* class_data */ |
---|
97 | |
---|
98 | sizeof (GParamSpec), |
---|
99 | 0, /* n_preallocs */ |
---|
100 | (GInstanceInitFunc) g_param_spec_init, |
---|
101 | |
---|
102 | ¶m_value_table, |
---|
103 | }; |
---|
104 | GType type; |
---|
105 | |
---|
106 | type = g_type_register_fundamental (G_TYPE_PARAM, "GParam", ¶m_spec_info, &finfo, G_TYPE_FLAG_ABSTRACT); |
---|
107 | g_assert (type == G_TYPE_PARAM); |
---|
108 | g_value_register_transform_func (G_TYPE_PARAM, G_TYPE_PARAM, value_param_transform_value); |
---|
109 | } |
---|
110 | |
---|
111 | static void |
---|
112 | g_param_spec_class_base_init (GParamSpecClass *class) |
---|
113 | { |
---|
114 | } |
---|
115 | |
---|
116 | static void |
---|
117 | g_param_spec_class_base_finalize (GParamSpecClass *class) |
---|
118 | { |
---|
119 | } |
---|
120 | |
---|
121 | static void |
---|
122 | g_param_spec_class_init (GParamSpecClass *class, |
---|
123 | gpointer class_data) |
---|
124 | { |
---|
125 | quark_floating = g_quark_from_static_string ("GParamSpec-floating"); |
---|
126 | |
---|
127 | class->value_type = G_TYPE_NONE; |
---|
128 | class->finalize = g_param_spec_finalize; |
---|
129 | class->value_set_default = NULL; |
---|
130 | class->value_validate = NULL; |
---|
131 | class->values_cmp = NULL; |
---|
132 | } |
---|
133 | |
---|
134 | static void |
---|
135 | g_param_spec_init (GParamSpec *pspec, |
---|
136 | GParamSpecClass *class) |
---|
137 | { |
---|
138 | pspec->name = NULL; |
---|
139 | pspec->_nick = NULL; |
---|
140 | pspec->_blurb = NULL; |
---|
141 | pspec->flags = 0; |
---|
142 | pspec->value_type = class->value_type; |
---|
143 | pspec->owner_type = 0; |
---|
144 | pspec->qdata = NULL; |
---|
145 | pspec->ref_count = 1; |
---|
146 | pspec->param_id = 0; |
---|
147 | g_datalist_id_set_data (&pspec->qdata, quark_floating, GUINT_TO_POINTER (TRUE)); |
---|
148 | } |
---|
149 | |
---|
150 | static void |
---|
151 | g_param_spec_finalize (GParamSpec *pspec) |
---|
152 | { |
---|
153 | g_datalist_clear (&pspec->qdata); |
---|
154 | |
---|
155 | g_free (pspec->name); |
---|
156 | g_free (pspec->_nick); |
---|
157 | g_free (pspec->_blurb); |
---|
158 | |
---|
159 | g_type_free_instance ((GTypeInstance*) pspec); |
---|
160 | } |
---|
161 | |
---|
162 | GParamSpec* |
---|
163 | g_param_spec_ref (GParamSpec *pspec) |
---|
164 | { |
---|
165 | g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL); |
---|
166 | |
---|
167 | G_LOCK (pspec_ref_count); |
---|
168 | if (pspec->ref_count > 0) |
---|
169 | { |
---|
170 | pspec->ref_count += 1; |
---|
171 | G_UNLOCK (pspec_ref_count); |
---|
172 | } |
---|
173 | else |
---|
174 | { |
---|
175 | G_UNLOCK (pspec_ref_count); |
---|
176 | g_return_val_if_fail (pspec->ref_count > 0, NULL); |
---|
177 | } |
---|
178 | |
---|
179 | return pspec; |
---|
180 | } |
---|
181 | |
---|
182 | void |
---|
183 | g_param_spec_unref (GParamSpec *pspec) |
---|
184 | { |
---|
185 | g_return_if_fail (G_IS_PARAM_SPEC (pspec)); |
---|
186 | |
---|
187 | G_LOCK (pspec_ref_count); |
---|
188 | if (pspec->ref_count > 0) |
---|
189 | { |
---|
190 | gboolean need_finalize; |
---|
191 | |
---|
192 | /* sync with _sink */ |
---|
193 | pspec->ref_count -= 1; |
---|
194 | need_finalize = pspec->ref_count == 0; |
---|
195 | G_UNLOCK (pspec_ref_count); |
---|
196 | if (need_finalize) |
---|
197 | G_PARAM_SPEC_GET_CLASS (pspec)->finalize (pspec); |
---|
198 | } |
---|
199 | else |
---|
200 | { |
---|
201 | G_UNLOCK (pspec_ref_count); |
---|
202 | g_return_if_fail (pspec->ref_count > 0); |
---|
203 | } |
---|
204 | } |
---|
205 | |
---|
206 | void |
---|
207 | g_param_spec_sink (GParamSpec *pspec) |
---|
208 | { |
---|
209 | g_return_if_fail (G_IS_PARAM_SPEC (pspec)); |
---|
210 | |
---|
211 | G_LOCK (pspec_ref_count); |
---|
212 | if (pspec->ref_count > 0) |
---|
213 | { |
---|
214 | if (g_datalist_id_remove_no_notify (&pspec->qdata, quark_floating)) |
---|
215 | { |
---|
216 | /* sync with _unref */ |
---|
217 | if (pspec->ref_count > 1) |
---|
218 | pspec->ref_count -= 1; |
---|
219 | else |
---|
220 | { |
---|
221 | G_UNLOCK (pspec_ref_count); |
---|
222 | g_param_spec_unref (pspec); |
---|
223 | |
---|
224 | return; |
---|
225 | } |
---|
226 | } |
---|
227 | G_UNLOCK (pspec_ref_count); |
---|
228 | } |
---|
229 | else |
---|
230 | { |
---|
231 | G_UNLOCK (pspec_ref_count); |
---|
232 | g_return_if_fail (pspec->ref_count > 0); |
---|
233 | } |
---|
234 | } |
---|
235 | |
---|
236 | G_CONST_RETURN gchar* |
---|
237 | g_param_spec_get_name (GParamSpec *pspec) |
---|
238 | { |
---|
239 | g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL); |
---|
240 | |
---|
241 | return pspec->name; |
---|
242 | } |
---|
243 | |
---|
244 | G_CONST_RETURN gchar* |
---|
245 | g_param_spec_get_nick (GParamSpec *pspec) |
---|
246 | { |
---|
247 | g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL); |
---|
248 | |
---|
249 | if (pspec->_nick) |
---|
250 | return pspec->_nick; |
---|
251 | else |
---|
252 | { |
---|
253 | GParamSpec *redirect_target; |
---|
254 | |
---|
255 | redirect_target = g_param_spec_get_redirect_target (pspec); |
---|
256 | if (redirect_target && redirect_target->_nick) |
---|
257 | return redirect_target->_nick; |
---|
258 | } |
---|
259 | |
---|
260 | return pspec->name; |
---|
261 | } |
---|
262 | |
---|
263 | G_CONST_RETURN gchar* |
---|
264 | g_param_spec_get_blurb (GParamSpec *pspec) |
---|
265 | { |
---|
266 | g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL); |
---|
267 | |
---|
268 | if (pspec->_blurb) |
---|
269 | return pspec->_blurb; |
---|
270 | else |
---|
271 | { |
---|
272 | GParamSpec *redirect_target; |
---|
273 | |
---|
274 | redirect_target = g_param_spec_get_redirect_target (pspec); |
---|
275 | if (redirect_target && redirect_target->_blurb) |
---|
276 | return redirect_target->_blurb; |
---|
277 | } |
---|
278 | |
---|
279 | return NULL; |
---|
280 | } |
---|
281 | |
---|
282 | static void |
---|
283 | canonicalize_key (gchar *key) |
---|
284 | { |
---|
285 | gchar *p; |
---|
286 | |
---|
287 | for (p = key; *p != 0; p++) |
---|
288 | { |
---|
289 | gchar c = *p; |
---|
290 | |
---|
291 | if (c != '-' && |
---|
292 | (c < '0' || c > '9') && |
---|
293 | (c < 'A' || c > 'Z') && |
---|
294 | (c < 'a' || c > 'z')) |
---|
295 | *p = '-'; |
---|
296 | } |
---|
297 | } |
---|
298 | |
---|
299 | gpointer |
---|
300 | g_param_spec_internal (GType param_type, |
---|
301 | const gchar *name, |
---|
302 | const gchar *nick, |
---|
303 | const gchar *blurb, |
---|
304 | GParamFlags flags) |
---|
305 | { |
---|
306 | GParamSpec *pspec; |
---|
307 | |
---|
308 | g_return_val_if_fail (G_TYPE_IS_PARAM (param_type) && param_type != G_TYPE_PARAM, NULL); |
---|
309 | g_return_val_if_fail (name != NULL, NULL); |
---|
310 | g_return_val_if_fail ((name[0] >= 'A' && name[0] <= 'Z') || (name[0] >= 'a' && name[0] <= 'z'), NULL); |
---|
311 | |
---|
312 | pspec = (gpointer) g_type_create_instance (param_type); |
---|
313 | pspec->name = g_strdup (name); |
---|
314 | canonicalize_key (pspec->name); |
---|
315 | pspec->_nick = g_strdup (nick); |
---|
316 | pspec->_blurb = g_strdup (blurb); |
---|
317 | pspec->flags = (flags & G_PARAM_USER_MASK) | (flags & G_PARAM_MASK); |
---|
318 | |
---|
319 | return pspec; |
---|
320 | } |
---|
321 | |
---|
322 | gpointer |
---|
323 | g_param_spec_get_qdata (GParamSpec *pspec, |
---|
324 | GQuark quark) |
---|
325 | { |
---|
326 | g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL); |
---|
327 | |
---|
328 | return quark ? g_datalist_id_get_data (&pspec->qdata, quark) : NULL; |
---|
329 | } |
---|
330 | |
---|
331 | void |
---|
332 | g_param_spec_set_qdata (GParamSpec *pspec, |
---|
333 | GQuark quark, |
---|
334 | gpointer data) |
---|
335 | { |
---|
336 | g_return_if_fail (G_IS_PARAM_SPEC (pspec)); |
---|
337 | g_return_if_fail (quark > 0); |
---|
338 | |
---|
339 | g_datalist_id_set_data (&pspec->qdata, quark, data); |
---|
340 | } |
---|
341 | |
---|
342 | void |
---|
343 | g_param_spec_set_qdata_full (GParamSpec *pspec, |
---|
344 | GQuark quark, |
---|
345 | gpointer data, |
---|
346 | GDestroyNotify destroy) |
---|
347 | { |
---|
348 | g_return_if_fail (G_IS_PARAM_SPEC (pspec)); |
---|
349 | g_return_if_fail (quark > 0); |
---|
350 | |
---|
351 | g_datalist_id_set_data_full (&pspec->qdata, quark, data, data ? destroy : (GDestroyNotify) NULL); |
---|
352 | } |
---|
353 | |
---|
354 | gpointer |
---|
355 | g_param_spec_steal_qdata (GParamSpec *pspec, |
---|
356 | GQuark quark) |
---|
357 | { |
---|
358 | g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL); |
---|
359 | g_return_val_if_fail (quark > 0, NULL); |
---|
360 | |
---|
361 | return g_datalist_id_remove_no_notify (&pspec->qdata, quark); |
---|
362 | } |
---|
363 | |
---|
364 | GParamSpec* |
---|
365 | g_param_spec_get_redirect_target (GParamSpec *pspec) |
---|
366 | { |
---|
367 | g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL); |
---|
368 | |
---|
369 | if (G_IS_PARAM_SPEC_OVERRIDE (pspec)) |
---|
370 | { |
---|
371 | GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec); |
---|
372 | |
---|
373 | return ospec->overridden; |
---|
374 | } |
---|
375 | else |
---|
376 | return NULL; |
---|
377 | } |
---|
378 | |
---|
379 | void |
---|
380 | g_param_value_set_default (GParamSpec *pspec, |
---|
381 | GValue *value) |
---|
382 | { |
---|
383 | g_return_if_fail (G_IS_PARAM_SPEC (pspec)); |
---|
384 | g_return_if_fail (G_IS_VALUE (value)); |
---|
385 | g_return_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value)); |
---|
386 | |
---|
387 | g_value_reset (value); |
---|
388 | G_PARAM_SPEC_GET_CLASS (pspec)->value_set_default (pspec, value); |
---|
389 | } |
---|
390 | |
---|
391 | gboolean |
---|
392 | g_param_value_defaults (GParamSpec *pspec, |
---|
393 | GValue *value) |
---|
394 | { |
---|
395 | GValue dflt_value = { 0, }; |
---|
396 | gboolean defaults; |
---|
397 | |
---|
398 | g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE); |
---|
399 | g_return_val_if_fail (G_IS_VALUE (value), FALSE); |
---|
400 | g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value), FALSE); |
---|
401 | |
---|
402 | g_value_init (&dflt_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); |
---|
403 | G_PARAM_SPEC_GET_CLASS (pspec)->value_set_default (pspec, &dflt_value); |
---|
404 | defaults = G_PARAM_SPEC_GET_CLASS (pspec)->values_cmp (pspec, value, &dflt_value) == 0; |
---|
405 | g_value_unset (&dflt_value); |
---|
406 | |
---|
407 | return defaults; |
---|
408 | } |
---|
409 | |
---|
410 | gboolean |
---|
411 | g_param_value_validate (GParamSpec *pspec, |
---|
412 | GValue *value) |
---|
413 | { |
---|
414 | g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE); |
---|
415 | g_return_val_if_fail (G_IS_VALUE (value), FALSE); |
---|
416 | g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value), FALSE); |
---|
417 | |
---|
418 | if (G_PARAM_SPEC_GET_CLASS (pspec)->value_validate) |
---|
419 | { |
---|
420 | GValue oval = *value; |
---|
421 | |
---|
422 | if (G_PARAM_SPEC_GET_CLASS (pspec)->value_validate (pspec, value) || |
---|
423 | memcmp (&oval.data, &value->data, sizeof (oval.data))) |
---|
424 | return TRUE; |
---|
425 | } |
---|
426 | |
---|
427 | return FALSE; |
---|
428 | } |
---|
429 | |
---|
430 | gboolean |
---|
431 | g_param_value_convert (GParamSpec *pspec, |
---|
432 | const GValue *src_value, |
---|
433 | GValue *dest_value, |
---|
434 | gboolean strict_validation) |
---|
435 | { |
---|
436 | GValue tmp_value = { 0, }; |
---|
437 | |
---|
438 | g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE); |
---|
439 | g_return_val_if_fail (G_IS_VALUE (src_value), FALSE); |
---|
440 | g_return_val_if_fail (G_IS_VALUE (dest_value), FALSE); |
---|
441 | g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, dest_value), FALSE); |
---|
442 | |
---|
443 | /* better leave dest_value untouched when returning FALSE */ |
---|
444 | |
---|
445 | g_value_init (&tmp_value, G_VALUE_TYPE (dest_value)); |
---|
446 | if (g_value_transform (src_value, &tmp_value) && |
---|
447 | (!g_param_value_validate (pspec, &tmp_value) || !strict_validation)) |
---|
448 | { |
---|
449 | g_value_unset (dest_value); |
---|
450 | |
---|
451 | /* values are relocatable */ |
---|
452 | memcpy (dest_value, &tmp_value, sizeof (tmp_value)); |
---|
453 | |
---|
454 | return TRUE; |
---|
455 | } |
---|
456 | else |
---|
457 | { |
---|
458 | g_value_unset (&tmp_value); |
---|
459 | |
---|
460 | return FALSE; |
---|
461 | } |
---|
462 | } |
---|
463 | |
---|
464 | gint |
---|
465 | g_param_values_cmp (GParamSpec *pspec, |
---|
466 | const GValue *value1, |
---|
467 | const GValue *value2) |
---|
468 | { |
---|
469 | gint cmp; |
---|
470 | |
---|
471 | /* param_values_cmp() effectively does: value1 - value2 |
---|
472 | * so the return values are: |
---|
473 | * -1) value1 < value2 |
---|
474 | * 0) value1 == value2 |
---|
475 | * 1) value1 > value2 |
---|
476 | */ |
---|
477 | g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), 0); |
---|
478 | g_return_val_if_fail (G_IS_VALUE (value1), 0); |
---|
479 | g_return_val_if_fail (G_IS_VALUE (value2), 0); |
---|
480 | g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value1), 0); |
---|
481 | g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value2), 0); |
---|
482 | |
---|
483 | cmp = G_PARAM_SPEC_GET_CLASS (pspec)->values_cmp (pspec, value1, value2); |
---|
484 | |
---|
485 | return CLAMP (cmp, -1, 1); |
---|
486 | } |
---|
487 | |
---|
488 | static void |
---|
489 | value_param_init (GValue *value) |
---|
490 | { |
---|
491 | value->data[0].v_pointer = NULL; |
---|
492 | } |
---|
493 | |
---|
494 | static void |
---|
495 | value_param_free_value (GValue *value) |
---|
496 | { |
---|
497 | if (value->data[0].v_pointer) |
---|
498 | g_param_spec_unref (value->data[0].v_pointer); |
---|
499 | } |
---|
500 | |
---|
501 | static void |
---|
502 | value_param_copy_value (const GValue *src_value, |
---|
503 | GValue *dest_value) |
---|
504 | { |
---|
505 | if (src_value->data[0].v_pointer) |
---|
506 | dest_value->data[0].v_pointer = g_param_spec_ref (src_value->data[0].v_pointer); |
---|
507 | else |
---|
508 | dest_value->data[0].v_pointer = NULL; |
---|
509 | } |
---|
510 | |
---|
511 | static void |
---|
512 | value_param_transform_value (const GValue *src_value, |
---|
513 | GValue *dest_value) |
---|
514 | { |
---|
515 | if (src_value->data[0].v_pointer && |
---|
516 | g_type_is_a (G_PARAM_SPEC_TYPE (dest_value->data[0].v_pointer), G_VALUE_TYPE (dest_value))) |
---|
517 | dest_value->data[0].v_pointer = g_param_spec_ref (src_value->data[0].v_pointer); |
---|
518 | else |
---|
519 | dest_value->data[0].v_pointer = NULL; |
---|
520 | } |
---|
521 | |
---|
522 | static gpointer |
---|
523 | value_param_peek_pointer (const GValue *value) |
---|
524 | { |
---|
525 | return value->data[0].v_pointer; |
---|
526 | } |
---|
527 | |
---|
528 | static gchar* |
---|
529 | value_param_collect_value (GValue *value, |
---|
530 | guint n_collect_values, |
---|
531 | GTypeCValue *collect_values, |
---|
532 | guint collect_flags) |
---|
533 | { |
---|
534 | if (collect_values[0].v_pointer) |
---|
535 | { |
---|
536 | GParamSpec *param = collect_values[0].v_pointer; |
---|
537 | |
---|
538 | if (param->g_type_instance.g_class == NULL) |
---|
539 | return g_strconcat ("invalid unclassed param spec pointer for value type `", |
---|
540 | G_VALUE_TYPE_NAME (value), |
---|
541 | "'", |
---|
542 | NULL); |
---|
543 | else if (!g_value_type_compatible (G_PARAM_SPEC_TYPE (param), G_VALUE_TYPE (value))) |
---|
544 | return g_strconcat ("invalid param spec type `", |
---|
545 | G_PARAM_SPEC_TYPE_NAME (param), |
---|
546 | "' for value type `", |
---|
547 | G_VALUE_TYPE_NAME (value), |
---|
548 | "'", |
---|
549 | NULL); |
---|
550 | value->data[0].v_pointer = g_param_spec_ref (param); |
---|
551 | } |
---|
552 | else |
---|
553 | value->data[0].v_pointer = NULL; |
---|
554 | |
---|
555 | return NULL; |
---|
556 | } |
---|
557 | |
---|
558 | static gchar* |
---|
559 | value_param_lcopy_value (const GValue *value, |
---|
560 | guint n_collect_values, |
---|
561 | GTypeCValue *collect_values, |
---|
562 | guint collect_flags) |
---|
563 | { |
---|
564 | GParamSpec **param_p = collect_values[0].v_pointer; |
---|
565 | |
---|
566 | if (!param_p) |
---|
567 | return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); |
---|
568 | |
---|
569 | if (!value->data[0].v_pointer) |
---|
570 | *param_p = NULL; |
---|
571 | else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) |
---|
572 | *param_p = value->data[0].v_pointer; |
---|
573 | else |
---|
574 | *param_p = g_param_spec_ref (value->data[0].v_pointer); |
---|
575 | |
---|
576 | return NULL; |
---|
577 | } |
---|
578 | |
---|
579 | |
---|
580 | /* --- param spec pool --- */ |
---|
581 | struct _GParamSpecPool |
---|
582 | { |
---|
583 | GStaticMutex smutex; |
---|
584 | gboolean type_prefixing; |
---|
585 | GHashTable *hash_table; |
---|
586 | }; |
---|
587 | |
---|
588 | static guint |
---|
589 | param_spec_pool_hash (gconstpointer key_spec) |
---|
590 | { |
---|
591 | const GParamSpec *key = key_spec; |
---|
592 | const gchar *p; |
---|
593 | guint h = key->owner_type; |
---|
594 | |
---|
595 | for (p = key->name; *p; p++) |
---|
596 | h = (h << 5) - h + *p; |
---|
597 | |
---|
598 | return h; |
---|
599 | } |
---|
600 | |
---|
601 | static gboolean |
---|
602 | param_spec_pool_equals (gconstpointer key_spec_1, |
---|
603 | gconstpointer key_spec_2) |
---|
604 | { |
---|
605 | const GParamSpec *key1 = key_spec_1; |
---|
606 | const GParamSpec *key2 = key_spec_2; |
---|
607 | |
---|
608 | return (key1->owner_type == key2->owner_type && |
---|
609 | strcmp (key1->name, key2->name) == 0); |
---|
610 | } |
---|
611 | |
---|
612 | GParamSpecPool* |
---|
613 | g_param_spec_pool_new (gboolean type_prefixing) |
---|
614 | { |
---|
615 | static GStaticMutex init_smutex = G_STATIC_MUTEX_INIT; |
---|
616 | GParamSpecPool *pool = g_new (GParamSpecPool, 1); |
---|
617 | |
---|
618 | memcpy (&pool->smutex, &init_smutex, sizeof (init_smutex)); |
---|
619 | pool->type_prefixing = type_prefixing != FALSE; |
---|
620 | pool->hash_table = g_hash_table_new (param_spec_pool_hash, param_spec_pool_equals); |
---|
621 | |
---|
622 | return pool; |
---|
623 | } |
---|
624 | |
---|
625 | void |
---|
626 | g_param_spec_pool_insert (GParamSpecPool *pool, |
---|
627 | GParamSpec *pspec, |
---|
628 | GType owner_type) |
---|
629 | { |
---|
630 | gchar *p; |
---|
631 | |
---|
632 | if (pool && pspec && owner_type > 0 && pspec->owner_type == 0) |
---|
633 | { |
---|
634 | G_SLOCK (&pool->smutex); |
---|
635 | for (p = pspec->name; *p; p++) |
---|
636 | { |
---|
637 | if (!strchr (G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-_", *p)) |
---|
638 | { |
---|
639 | g_warning (G_STRLOC ": pspec name \"%s\" contains invalid characters", pspec->name); |
---|
640 | G_SUNLOCK (&pool->smutex); |
---|
641 | return; |
---|
642 | } |
---|
643 | } |
---|
644 | |
---|
645 | pspec->owner_type = owner_type; |
---|
646 | g_param_spec_ref (pspec); |
---|
647 | g_hash_table_insert (pool->hash_table, pspec, pspec); |
---|
648 | G_SUNLOCK (&pool->smutex); |
---|
649 | } |
---|
650 | else |
---|
651 | { |
---|
652 | g_return_if_fail (pool != NULL); |
---|
653 | g_return_if_fail (pspec); |
---|
654 | g_return_if_fail (owner_type > 0); |
---|
655 | g_return_if_fail (pspec->owner_type == 0); |
---|
656 | } |
---|
657 | } |
---|
658 | |
---|
659 | void |
---|
660 | g_param_spec_pool_remove (GParamSpecPool *pool, |
---|
661 | GParamSpec *pspec) |
---|
662 | { |
---|
663 | if (pool && pspec) |
---|
664 | { |
---|
665 | G_SLOCK (&pool->smutex); |
---|
666 | if (g_hash_table_remove (pool->hash_table, pspec)) |
---|
667 | g_param_spec_unref (pspec); |
---|
668 | else |
---|
669 | g_warning (G_STRLOC ": attempt to remove unknown pspec `%s' from pool", pspec->name); |
---|
670 | G_SUNLOCK (&pool->smutex); |
---|
671 | } |
---|
672 | else |
---|
673 | { |
---|
674 | g_return_if_fail (pool != NULL); |
---|
675 | g_return_if_fail (pspec); |
---|
676 | } |
---|
677 | } |
---|
678 | |
---|
679 | static inline GParamSpec* |
---|
680 | param_spec_ht_lookup (GHashTable *hash_table, |
---|
681 | const gchar *param_name, |
---|
682 | GType owner_type, |
---|
683 | gboolean walk_ancestors) |
---|
684 | { |
---|
685 | GParamSpec key, *pspec; |
---|
686 | |
---|
687 | key.owner_type = owner_type; |
---|
688 | key.name = (gchar*) param_name; |
---|
689 | if (walk_ancestors) |
---|
690 | do |
---|
691 | { |
---|
692 | pspec = g_hash_table_lookup (hash_table, &key); |
---|
693 | if (pspec) |
---|
694 | return pspec; |
---|
695 | key.owner_type = g_type_parent (key.owner_type); |
---|
696 | } |
---|
697 | while (key.owner_type); |
---|
698 | else |
---|
699 | pspec = g_hash_table_lookup (hash_table, &key); |
---|
700 | |
---|
701 | if (!pspec) |
---|
702 | { |
---|
703 | /* try canonicalized form */ |
---|
704 | key.name = g_strdup (param_name); |
---|
705 | key.owner_type = owner_type; |
---|
706 | |
---|
707 | canonicalize_key (key.name); |
---|
708 | if (walk_ancestors) |
---|
709 | do |
---|
710 | { |
---|
711 | pspec = g_hash_table_lookup (hash_table, &key); |
---|
712 | if (pspec) |
---|
713 | { |
---|
714 | g_free (key.name); |
---|
715 | return pspec; |
---|
716 | } |
---|
717 | key.owner_type = g_type_parent (key.owner_type); |
---|
718 | } |
---|
719 | while (key.owner_type); |
---|
720 | else |
---|
721 | pspec = g_hash_table_lookup (hash_table, &key); |
---|
722 | g_free (key.name); |
---|
723 | } |
---|
724 | |
---|
725 | return pspec; |
---|
726 | } |
---|
727 | |
---|
728 | GParamSpec* |
---|
729 | g_param_spec_pool_lookup (GParamSpecPool *pool, |
---|
730 | const gchar *param_name, |
---|
731 | GType owner_type, |
---|
732 | gboolean walk_ancestors) |
---|
733 | { |
---|
734 | GParamSpec *pspec; |
---|
735 | gchar *delim; |
---|
736 | |
---|
737 | if (!pool || !param_name) |
---|
738 | { |
---|
739 | g_return_val_if_fail (pool != NULL, NULL); |
---|
740 | g_return_val_if_fail (param_name != NULL, NULL); |
---|
741 | } |
---|
742 | |
---|
743 | G_SLOCK (&pool->smutex); |
---|
744 | |
---|
745 | delim = pool->type_prefixing ? strchr (param_name, ':') : NULL; |
---|
746 | |
---|
747 | /* try quick and away, i.e. without prefix */ |
---|
748 | if (!delim) |
---|
749 | { |
---|
750 | pspec = param_spec_ht_lookup (pool->hash_table, param_name, owner_type, walk_ancestors); |
---|
751 | G_SUNLOCK (&pool->smutex); |
---|
752 | |
---|
753 | return pspec; |
---|
754 | } |
---|
755 | |
---|
756 | /* strip type prefix */ |
---|
757 | if (pool->type_prefixing && delim[1] == ':') |
---|
758 | { |
---|
759 | guint l = delim - param_name; |
---|
760 | gchar stack_buffer[32], *buffer = l < 32 ? stack_buffer : g_new (gchar, l + 1); |
---|
761 | GType type; |
---|
762 | |
---|
763 | strncpy (buffer, param_name, delim - param_name); |
---|
764 | buffer[l] = 0; |
---|
765 | type = g_type_from_name (buffer); |
---|
766 | if (l >= 32) |
---|
767 | g_free (buffer); |
---|
768 | if (type) /* type==0 isn't a valid type pefix */ |
---|
769 | { |
---|
770 | /* sanity check, these cases don't make a whole lot of sense */ |
---|
771 | if ((!walk_ancestors && type != owner_type) || !g_type_is_a (owner_type, type)) |
---|
772 | { |
---|
773 | G_SUNLOCK (&pool->smutex); |
---|
774 | |
---|
775 | return NULL; |
---|
776 | } |
---|
777 | owner_type = type; |
---|
778 | param_name += l + 2; |
---|
779 | pspec = param_spec_ht_lookup (pool->hash_table, param_name, owner_type, walk_ancestors); |
---|
780 | G_SUNLOCK (&pool->smutex); |
---|
781 | |
---|
782 | return pspec; |
---|
783 | } |
---|
784 | } |
---|
785 | /* malformed param_name */ |
---|
786 | |
---|
787 | G_SUNLOCK (&pool->smutex); |
---|
788 | |
---|
789 | return NULL; |
---|
790 | } |
---|
791 | |
---|
792 | static void |
---|
793 | pool_list (gpointer key, |
---|
794 | gpointer value, |
---|
795 | gpointer user_data) |
---|
796 | { |
---|
797 | GParamSpec *pspec = value; |
---|
798 | gpointer *data = user_data; |
---|
799 | GType owner_type = (GType) data[1]; |
---|
800 | |
---|
801 | if (owner_type == pspec->owner_type) |
---|
802 | data[0] = g_list_prepend (data[0], pspec); |
---|
803 | } |
---|
804 | |
---|
805 | GList* |
---|
806 | g_param_spec_pool_list_owned (GParamSpecPool *pool, |
---|
807 | GType owner_type) |
---|
808 | { |
---|
809 | gpointer data[2]; |
---|
810 | |
---|
811 | g_return_val_if_fail (pool != NULL, NULL); |
---|
812 | g_return_val_if_fail (owner_type > 0, NULL); |
---|
813 | |
---|
814 | G_SLOCK (&pool->smutex); |
---|
815 | data[0] = NULL; |
---|
816 | data[1] = (gpointer) owner_type; |
---|
817 | g_hash_table_foreach (pool->hash_table, pool_list, &data); |
---|
818 | G_SUNLOCK (&pool->smutex); |
---|
819 | |
---|
820 | return data[0]; |
---|
821 | } |
---|
822 | |
---|
823 | static gint |
---|
824 | pspec_compare_id (gconstpointer a, |
---|
825 | gconstpointer b) |
---|
826 | { |
---|
827 | const GParamSpec *pspec1 = a, *pspec2 = b; |
---|
828 | |
---|
829 | return pspec1->param_id < pspec2->param_id ? -1 : pspec1->param_id > pspec2->param_id; |
---|
830 | } |
---|
831 | |
---|
832 | static inline GSList* |
---|
833 | pspec_list_remove_overridden_and_redirected (GSList *plist, |
---|
834 | GHashTable *ht, |
---|
835 | GType owner_type, |
---|
836 | guint *n_p) |
---|
837 | { |
---|
838 | GSList *rlist = NULL; |
---|
839 | |
---|
840 | while (plist) |
---|
841 | { |
---|
842 | GSList *tmp = plist->next; |
---|
843 | GParamSpec *pspec = plist->data; |
---|
844 | GParamSpec *found; |
---|
845 | gboolean remove = FALSE; |
---|
846 | |
---|
847 | /* Remove paramspecs that are redirected, and also paramspecs |
---|
848 | * that have are overridden by non-redirected properties. |
---|
849 | * The idea is to get the single paramspec for each name that |
---|
850 | * best corresponds to what the application sees. |
---|
851 | */ |
---|
852 | if (g_param_spec_get_redirect_target (pspec)) |
---|
853 | remove = TRUE; |
---|
854 | else |
---|
855 | { |
---|
856 | found = param_spec_ht_lookup (ht, pspec->name, owner_type, TRUE); |
---|
857 | if (found != pspec) |
---|
858 | { |
---|
859 | GParamSpec *redirect = g_param_spec_get_redirect_target (found); |
---|
860 | if (redirect != pspec) |
---|
861 | remove = TRUE; |
---|
862 | } |
---|
863 | } |
---|
864 | |
---|
865 | if (remove) |
---|
866 | { |
---|
867 | g_slist_free_1 (plist); |
---|
868 | } |
---|
869 | else |
---|
870 | { |
---|
871 | plist->next = rlist; |
---|
872 | rlist = plist; |
---|
873 | *n_p += 1; |
---|
874 | } |
---|
875 | plist = tmp; |
---|
876 | } |
---|
877 | return rlist; |
---|
878 | } |
---|
879 | |
---|
880 | static void |
---|
881 | pool_depth_list (gpointer key, |
---|
882 | gpointer value, |
---|
883 | gpointer user_data) |
---|
884 | { |
---|
885 | GParamSpec *pspec = value; |
---|
886 | gpointer *data = user_data; |
---|
887 | GSList **slists = data[0]; |
---|
888 | GType owner_type = (GType) data[1]; |
---|
889 | |
---|
890 | if (g_type_is_a (owner_type, pspec->owner_type)) |
---|
891 | { |
---|
892 | if (G_TYPE_IS_INTERFACE (pspec->owner_type)) |
---|
893 | { |
---|
894 | slists[0] = g_slist_prepend (slists[0], pspec); |
---|
895 | } |
---|
896 | else |
---|
897 | { |
---|
898 | guint d = g_type_depth (pspec->owner_type); |
---|
899 | |
---|
900 | slists[d - 1] = g_slist_prepend (slists[d - 1], pspec); |
---|
901 | } |
---|
902 | } |
---|
903 | } |
---|
904 | |
---|
905 | /* We handle interfaces specially since we don't want to |
---|
906 | * count interface prerequsites like normal inheritance; |
---|
907 | * the property comes from the direct inheritance from |
---|
908 | * the prerequisite class, not from the interface that |
---|
909 | * prerequires it. |
---|
910 | * |
---|
911 | * also 'depth' isn't a meaningful concept for interface |
---|
912 | * prerequites. |
---|
913 | */ |
---|
914 | static void |
---|
915 | pool_depth_list_for_interface (gpointer key, |
---|
916 | gpointer value, |
---|
917 | gpointer user_data) |
---|
918 | { |
---|
919 | GParamSpec *pspec = value; |
---|
920 | gpointer *data = user_data; |
---|
921 | GSList **slists = data[0]; |
---|
922 | GType owner_type = (GType) data[1]; |
---|
923 | |
---|
924 | if (pspec->owner_type == owner_type) |
---|
925 | slists[0] = g_slist_prepend (slists[0], pspec); |
---|
926 | } |
---|
927 | |
---|
928 | GParamSpec** /* free result */ |
---|
929 | g_param_spec_pool_list (GParamSpecPool *pool, |
---|
930 | GType owner_type, |
---|
931 | guint *n_pspecs_p) |
---|
932 | { |
---|
933 | GParamSpec **pspecs, **p; |
---|
934 | GSList **slists, *node; |
---|
935 | gpointer data[2]; |
---|
936 | guint d, i; |
---|
937 | |
---|
938 | g_return_val_if_fail (pool != NULL, NULL); |
---|
939 | g_return_val_if_fail (owner_type > 0, NULL); |
---|
940 | g_return_val_if_fail (n_pspecs_p != NULL, NULL); |
---|
941 | |
---|
942 | G_SLOCK (&pool->smutex); |
---|
943 | *n_pspecs_p = 0; |
---|
944 | d = g_type_depth (owner_type); |
---|
945 | slists = g_new0 (GSList*, d); |
---|
946 | data[0] = slists; |
---|
947 | data[1] = (gpointer) owner_type; |
---|
948 | |
---|
949 | g_hash_table_foreach (pool->hash_table, |
---|
950 | G_TYPE_IS_INTERFACE (owner_type) ? |
---|
951 | pool_depth_list_for_interface : |
---|
952 | pool_depth_list, |
---|
953 | &data); |
---|
954 | |
---|
955 | for (i = 0; i < d; i++) |
---|
956 | slists[i] = pspec_list_remove_overridden_and_redirected (slists[i], pool->hash_table, owner_type, n_pspecs_p); |
---|
957 | pspecs = g_new (GParamSpec*, *n_pspecs_p + 1); |
---|
958 | p = pspecs; |
---|
959 | for (i = 0; i < d; i++) |
---|
960 | { |
---|
961 | slists[i] = g_slist_sort (slists[i], pspec_compare_id); |
---|
962 | for (node = slists[i]; node; node = node->next) |
---|
963 | *p++ = node->data; |
---|
964 | g_slist_free (slists[i]); |
---|
965 | } |
---|
966 | *p++ = NULL; |
---|
967 | g_free (slists); |
---|
968 | G_SUNLOCK (&pool->smutex); |
---|
969 | |
---|
970 | return pspecs; |
---|
971 | } |
---|
972 | |
---|
973 | |
---|
974 | /* --- auxillary functions --- */ |
---|
975 | typedef struct |
---|
976 | { |
---|
977 | /* class portion */ |
---|
978 | GType value_type; |
---|
979 | void (*finalize) (GParamSpec *pspec); |
---|
980 | void (*value_set_default) (GParamSpec *pspec, |
---|
981 | GValue *value); |
---|
982 | gboolean (*value_validate) (GParamSpec *pspec, |
---|
983 | GValue *value); |
---|
984 | gint (*values_cmp) (GParamSpec *pspec, |
---|
985 | const GValue *value1, |
---|
986 | const GValue *value2); |
---|
987 | } ParamSpecClassInfo; |
---|
988 | |
---|
989 | static void |
---|
990 | param_spec_generic_class_init (gpointer g_class, |
---|
991 | gpointer class_data) |
---|
992 | { |
---|
993 | GParamSpecClass *class = g_class; |
---|
994 | ParamSpecClassInfo *info = class_data; |
---|
995 | |
---|
996 | class->value_type = info->value_type; |
---|
997 | if (info->finalize) |
---|
998 | class->finalize = info->finalize; /* optional */ |
---|
999 | class->value_set_default = info->value_set_default; |
---|
1000 | if (info->value_validate) |
---|
1001 | class->value_validate = info->value_validate; /* optional */ |
---|
1002 | class->values_cmp = info->values_cmp; |
---|
1003 | g_free (class_data); |
---|
1004 | } |
---|
1005 | |
---|
1006 | static void |
---|
1007 | default_value_set_default (GParamSpec *pspec, |
---|
1008 | GValue *value) |
---|
1009 | { |
---|
1010 | /* value is already zero initialized */ |
---|
1011 | } |
---|
1012 | |
---|
1013 | static gint |
---|
1014 | default_values_cmp (GParamSpec *pspec, |
---|
1015 | const GValue *value1, |
---|
1016 | const GValue *value2) |
---|
1017 | { |
---|
1018 | return memcmp (&value1->data, &value2->data, sizeof (value1->data)); |
---|
1019 | } |
---|
1020 | |
---|
1021 | GType |
---|
1022 | g_param_type_register_static (const gchar *name, |
---|
1023 | const GParamSpecTypeInfo *pspec_info) |
---|
1024 | { |
---|
1025 | GTypeInfo info = { |
---|
1026 | sizeof (GParamSpecClass), /* class_size */ |
---|
1027 | NULL, /* base_init */ |
---|
1028 | NULL, /* base_destroy */ |
---|
1029 | param_spec_generic_class_init, /* class_init */ |
---|
1030 | NULL, /* class_destroy */ |
---|
1031 | NULL, /* class_data */ |
---|
1032 | 0, /* instance_size */ |
---|
1033 | 16, /* n_preallocs */ |
---|
1034 | NULL, /* instance_init */ |
---|
1035 | }; |
---|
1036 | ParamSpecClassInfo *cinfo; |
---|
1037 | |
---|
1038 | g_return_val_if_fail (name != NULL, 0); |
---|
1039 | g_return_val_if_fail (pspec_info != NULL, 0); |
---|
1040 | g_return_val_if_fail (g_type_from_name (name) == 0, 0); |
---|
1041 | g_return_val_if_fail (pspec_info->instance_size >= sizeof (GParamSpec), 0); |
---|
1042 | g_return_val_if_fail (g_type_name (pspec_info->value_type) != NULL, 0); |
---|
1043 | /* default: g_return_val_if_fail (pspec_info->value_set_default != NULL, 0); */ |
---|
1044 | /* optional: g_return_val_if_fail (pspec_info->value_validate != NULL, 0); */ |
---|
1045 | /* default: g_return_val_if_fail (pspec_info->values_cmp != NULL, 0); */ |
---|
1046 | |
---|
1047 | info.instance_size = pspec_info->instance_size; |
---|
1048 | info.n_preallocs = pspec_info->n_preallocs; |
---|
1049 | info.instance_init = (GInstanceInitFunc) pspec_info->instance_init; |
---|
1050 | cinfo = g_new (ParamSpecClassInfo, 1); |
---|
1051 | cinfo->value_type = pspec_info->value_type; |
---|
1052 | cinfo->finalize = pspec_info->finalize; |
---|
1053 | cinfo->value_set_default = pspec_info->value_set_default ? pspec_info->value_set_default : default_value_set_default; |
---|
1054 | cinfo->value_validate = pspec_info->value_validate; |
---|
1055 | cinfo->values_cmp = pspec_info->values_cmp ? pspec_info->values_cmp : default_values_cmp; |
---|
1056 | info.class_data = cinfo; |
---|
1057 | |
---|
1058 | return g_type_register_static (G_TYPE_PARAM, name, &info, 0); |
---|
1059 | } |
---|
1060 | |
---|
1061 | void |
---|
1062 | g_value_set_param (GValue *value, |
---|
1063 | GParamSpec *param) |
---|
1064 | { |
---|
1065 | g_return_if_fail (G_VALUE_HOLDS_PARAM (value)); |
---|
1066 | if (param) |
---|
1067 | g_return_if_fail (G_IS_PARAM_SPEC (param)); |
---|
1068 | |
---|
1069 | if (value->data[0].v_pointer) |
---|
1070 | g_param_spec_unref (value->data[0].v_pointer); |
---|
1071 | value->data[0].v_pointer = param; |
---|
1072 | if (value->data[0].v_pointer) |
---|
1073 | g_param_spec_ref (value->data[0].v_pointer); |
---|
1074 | } |
---|
1075 | |
---|
1076 | void |
---|
1077 | g_value_set_param_take_ownership (GValue *value, |
---|
1078 | GParamSpec *param) |
---|
1079 | { |
---|
1080 | g_value_take_param (value, param); |
---|
1081 | } |
---|
1082 | |
---|
1083 | void |
---|
1084 | g_value_take_param (GValue *value, |
---|
1085 | GParamSpec *param) |
---|
1086 | { |
---|
1087 | g_return_if_fail (G_VALUE_HOLDS_PARAM (value)); |
---|
1088 | if (param) |
---|
1089 | g_return_if_fail (G_IS_PARAM_SPEC (param)); |
---|
1090 | |
---|
1091 | if (value->data[0].v_pointer) |
---|
1092 | g_param_spec_unref (value->data[0].v_pointer); |
---|
1093 | value->data[0].v_pointer = param; /* we take over the reference count */ |
---|
1094 | } |
---|
1095 | |
---|
1096 | GParamSpec* |
---|
1097 | g_value_get_param (const GValue *value) |
---|
1098 | { |
---|
1099 | g_return_val_if_fail (G_VALUE_HOLDS_PARAM (value), NULL); |
---|
1100 | |
---|
1101 | return value->data[0].v_pointer; |
---|
1102 | } |
---|
1103 | |
---|
1104 | GParamSpec* |
---|
1105 | g_value_dup_param (const GValue *value) |
---|
1106 | { |
---|
1107 | g_return_val_if_fail (G_VALUE_HOLDS_PARAM (value), NULL); |
---|
1108 | |
---|
1109 | return value->data[0].v_pointer ? g_param_spec_ref (value->data[0].v_pointer) : NULL; |
---|
1110 | } |
---|