1 | /* GObject - GLib Type, Object, Parameter and Signal Library |
---|
2 | * Copyright (C) 1998-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 | #include "gobject.h" |
---|
20 | |
---|
21 | /* |
---|
22 | * MT safe |
---|
23 | */ |
---|
24 | |
---|
25 | #include "gvaluecollector.h" |
---|
26 | #include "gsignal.h" |
---|
27 | #include "gparamspecs.h" |
---|
28 | #include "gvaluetypes.h" |
---|
29 | #include "gobjectnotifyqueue.c" |
---|
30 | #include <string.h> |
---|
31 | #include <signal.h> |
---|
32 | |
---|
33 | |
---|
34 | #define PREALLOC_CPARAMS (8) |
---|
35 | |
---|
36 | |
---|
37 | /* --- macros --- */ |
---|
38 | #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id) |
---|
39 | #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id)) |
---|
40 | |
---|
41 | |
---|
42 | /* --- signals --- */ |
---|
43 | enum { |
---|
44 | NOTIFY, |
---|
45 | LAST_SIGNAL |
---|
46 | }; |
---|
47 | |
---|
48 | |
---|
49 | /* --- properties --- */ |
---|
50 | enum { |
---|
51 | PROP_NONE |
---|
52 | }; |
---|
53 | |
---|
54 | |
---|
55 | /* --- prototypes --- */ |
---|
56 | static void g_object_base_class_init (GObjectClass *class); |
---|
57 | static void g_object_base_class_finalize (GObjectClass *class); |
---|
58 | static void g_object_do_class_init (GObjectClass *class); |
---|
59 | static void g_object_init (GObject *object); |
---|
60 | static GObject* g_object_constructor (GType type, |
---|
61 | guint n_construct_properties, |
---|
62 | GObjectConstructParam *construct_params); |
---|
63 | static void g_object_last_unref (GObject *object); |
---|
64 | static void g_object_real_dispose (GObject *object); |
---|
65 | static void g_object_finalize (GObject *object); |
---|
66 | static void g_object_do_set_property (GObject *object, |
---|
67 | guint property_id, |
---|
68 | const GValue *value, |
---|
69 | GParamSpec *pspec); |
---|
70 | static void g_object_do_get_property (GObject *object, |
---|
71 | guint property_id, |
---|
72 | GValue *value, |
---|
73 | GParamSpec *pspec); |
---|
74 | static void g_value_object_init (GValue *value); |
---|
75 | static void g_value_object_free_value (GValue *value); |
---|
76 | static void g_value_object_copy_value (const GValue *src_value, |
---|
77 | GValue *dest_value); |
---|
78 | static void g_value_object_transform_value (const GValue *src_value, |
---|
79 | GValue *dest_value); |
---|
80 | static gpointer g_value_object_peek_pointer (const GValue *value); |
---|
81 | static gchar* g_value_object_collect_value (GValue *value, |
---|
82 | guint n_collect_values, |
---|
83 | GTypeCValue *collect_values, |
---|
84 | guint collect_flags); |
---|
85 | static gchar* g_value_object_lcopy_value (const GValue *value, |
---|
86 | guint n_collect_values, |
---|
87 | GTypeCValue *collect_values, |
---|
88 | guint collect_flags); |
---|
89 | static void g_object_dispatch_properties_changed (GObject *object, |
---|
90 | guint n_pspecs, |
---|
91 | GParamSpec **pspecs); |
---|
92 | static inline void object_get_property (GObject *object, |
---|
93 | GParamSpec *pspec, |
---|
94 | GValue *value); |
---|
95 | static inline void object_set_property (GObject *object, |
---|
96 | GParamSpec *pspec, |
---|
97 | const GValue *value, |
---|
98 | GObjectNotifyQueue *nqueue); |
---|
99 | |
---|
100 | static void object_interface_check_properties (gpointer func_data, |
---|
101 | gpointer g_iface); |
---|
102 | |
---|
103 | |
---|
104 | /* --- variables --- */ |
---|
105 | static GQuark quark_closure_array = 0; |
---|
106 | static GQuark quark_weak_refs = 0; |
---|
107 | static GParamSpecPool *pspec_pool = NULL; |
---|
108 | static GObjectNotifyContext property_notify_context = { 0, }; |
---|
109 | static gulong gobject_signals[LAST_SIGNAL] = { 0, }; |
---|
110 | G_LOCK_DEFINE_STATIC (construct_objects_lock); |
---|
111 | static GSList *construct_objects = NULL; |
---|
112 | |
---|
113 | |
---|
114 | /* --- functions --- */ |
---|
115 | #ifdef G_ENABLE_DEBUG |
---|
116 | #define IF_DEBUG(debug_type) if (_g_type_debug_flags & G_TYPE_DEBUG_ ## debug_type) |
---|
117 | G_LOCK_DEFINE_STATIC (debug_objects); |
---|
118 | static volatile GObject *g_trap_object_ref = NULL; |
---|
119 | static guint debug_objects_count = 0; |
---|
120 | static GHashTable *debug_objects_ht = NULL; |
---|
121 | static void |
---|
122 | debug_objects_foreach (gpointer key, |
---|
123 | gpointer value, |
---|
124 | gpointer user_data) |
---|
125 | { |
---|
126 | GObject *object = value; |
---|
127 | |
---|
128 | g_message ("[%p] stale %s\tref_count=%u", |
---|
129 | object, |
---|
130 | G_OBJECT_TYPE_NAME (object), |
---|
131 | object->ref_count); |
---|
132 | } |
---|
133 | static void |
---|
134 | debug_objects_atexit (void) |
---|
135 | { |
---|
136 | IF_DEBUG (OBJECTS) |
---|
137 | { |
---|
138 | G_LOCK (debug_objects); |
---|
139 | g_message ("stale GObjects: %u", debug_objects_count); |
---|
140 | g_hash_table_foreach (debug_objects_ht, debug_objects_foreach, NULL); |
---|
141 | G_UNLOCK (debug_objects); |
---|
142 | } |
---|
143 | } |
---|
144 | #endif /* G_ENABLE_DEBUG */ |
---|
145 | |
---|
146 | void |
---|
147 | g_object_type_init (void) /* sync with gtype.c */ |
---|
148 | { |
---|
149 | static gboolean initialized = FALSE; |
---|
150 | static const GTypeFundamentalInfo finfo = { |
---|
151 | G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE, |
---|
152 | }; |
---|
153 | static GTypeInfo info = { |
---|
154 | sizeof (GObjectClass), |
---|
155 | (GBaseInitFunc) g_object_base_class_init, |
---|
156 | (GBaseFinalizeFunc) g_object_base_class_finalize, |
---|
157 | (GClassInitFunc) g_object_do_class_init, |
---|
158 | NULL /* class_destroy */, |
---|
159 | NULL /* class_data */, |
---|
160 | sizeof (GObject), |
---|
161 | 0 /* n_preallocs */, |
---|
162 | (GInstanceInitFunc) g_object_init, |
---|
163 | NULL, /* value_table */ |
---|
164 | }; |
---|
165 | static const GTypeValueTable value_table = { |
---|
166 | g_value_object_init, /* value_init */ |
---|
167 | g_value_object_free_value, /* value_free */ |
---|
168 | g_value_object_copy_value, /* value_copy */ |
---|
169 | g_value_object_peek_pointer, /* value_peek_pointer */ |
---|
170 | "p", /* collect_format */ |
---|
171 | g_value_object_collect_value, /* collect_value */ |
---|
172 | "p", /* lcopy_format */ |
---|
173 | g_value_object_lcopy_value, /* lcopy_value */ |
---|
174 | }; |
---|
175 | GType type; |
---|
176 | |
---|
177 | g_return_if_fail (initialized == FALSE); |
---|
178 | initialized = TRUE; |
---|
179 | |
---|
180 | /* G_TYPE_OBJECT |
---|
181 | */ |
---|
182 | info.value_table = &value_table; |
---|
183 | type = g_type_register_fundamental (G_TYPE_OBJECT, "GObject", &info, &finfo, 0); |
---|
184 | g_assert (type == G_TYPE_OBJECT); |
---|
185 | g_value_register_transform_func (G_TYPE_OBJECT, G_TYPE_OBJECT, g_value_object_transform_value); |
---|
186 | |
---|
187 | #ifdef G_ENABLE_DEBUG |
---|
188 | IF_DEBUG (OBJECTS) |
---|
189 | { |
---|
190 | debug_objects_ht = g_hash_table_new (g_direct_hash, NULL); |
---|
191 | g_atexit (debug_objects_atexit); |
---|
192 | } |
---|
193 | #endif /* G_ENABLE_DEBUG */ |
---|
194 | } |
---|
195 | |
---|
196 | static void |
---|
197 | g_object_base_class_init (GObjectClass *class) |
---|
198 | { |
---|
199 | GObjectClass *pclass = g_type_class_peek_parent (class); |
---|
200 | |
---|
201 | /* reset instance specific fields and methods that don't get inherited */ |
---|
202 | class->construct_properties = pclass ? g_slist_copy (pclass->construct_properties) : NULL; |
---|
203 | class->get_property = NULL; |
---|
204 | class->set_property = NULL; |
---|
205 | } |
---|
206 | |
---|
207 | static void |
---|
208 | g_object_base_class_finalize (GObjectClass *class) |
---|
209 | { |
---|
210 | GList *list, *node; |
---|
211 | |
---|
212 | _g_signals_destroy (G_OBJECT_CLASS_TYPE (class)); |
---|
213 | |
---|
214 | g_slist_free (class->construct_properties); |
---|
215 | class->construct_properties = NULL; |
---|
216 | list = g_param_spec_pool_list_owned (pspec_pool, G_OBJECT_CLASS_TYPE (class)); |
---|
217 | for (node = list; node; node = node->next) |
---|
218 | { |
---|
219 | GParamSpec *pspec = node->data; |
---|
220 | |
---|
221 | g_param_spec_pool_remove (pspec_pool, pspec); |
---|
222 | PARAM_SPEC_SET_PARAM_ID (pspec, 0); |
---|
223 | g_param_spec_unref (pspec); |
---|
224 | } |
---|
225 | g_list_free (list); |
---|
226 | } |
---|
227 | |
---|
228 | static void |
---|
229 | g_object_notify_dispatcher (GObject *object, |
---|
230 | guint n_pspecs, |
---|
231 | GParamSpec **pspecs) |
---|
232 | { |
---|
233 | G_OBJECT_GET_CLASS (object)->dispatch_properties_changed (object, n_pspecs, pspecs); |
---|
234 | } |
---|
235 | |
---|
236 | static void |
---|
237 | g_object_do_class_init (GObjectClass *class) |
---|
238 | { |
---|
239 | /* read the comment about typedef struct CArray; on why not to change this quark */ |
---|
240 | quark_closure_array = g_quark_from_static_string ("GObject-closure-array"); |
---|
241 | |
---|
242 | quark_weak_refs = g_quark_from_static_string ("GObject-weak-references"); |
---|
243 | pspec_pool = g_param_spec_pool_new (TRUE); |
---|
244 | property_notify_context.quark_notify_queue = g_quark_from_static_string ("GObject-notify-queue"); |
---|
245 | property_notify_context.dispatcher = g_object_notify_dispatcher; |
---|
246 | |
---|
247 | class->constructor = g_object_constructor; |
---|
248 | class->set_property = g_object_do_set_property; |
---|
249 | class->get_property = g_object_do_get_property; |
---|
250 | class->dispose = g_object_real_dispose; |
---|
251 | class->finalize = g_object_finalize; |
---|
252 | class->dispatch_properties_changed = g_object_dispatch_properties_changed; |
---|
253 | class->notify = NULL; |
---|
254 | |
---|
255 | gobject_signals[NOTIFY] = |
---|
256 | g_signal_new ("notify", |
---|
257 | G_TYPE_FROM_CLASS (class), |
---|
258 | G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS | G_SIGNAL_ACTION, |
---|
259 | G_STRUCT_OFFSET (GObjectClass, notify), |
---|
260 | NULL, NULL, |
---|
261 | g_cclosure_marshal_VOID__PARAM, |
---|
262 | G_TYPE_NONE, |
---|
263 | 1, G_TYPE_PARAM); |
---|
264 | |
---|
265 | /* Install a check function that we'll use to verify that classes that |
---|
266 | * implement an interface implement all properties for that interface |
---|
267 | */ |
---|
268 | g_type_add_interface_check (NULL, object_interface_check_properties); |
---|
269 | } |
---|
270 | |
---|
271 | static void |
---|
272 | install_property_internal (GType g_type, |
---|
273 | guint property_id, |
---|
274 | GParamSpec *pspec) |
---|
275 | { |
---|
276 | if (g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type, FALSE)) |
---|
277 | { |
---|
278 | g_warning ("When installing property: type `%s' already has a property named `%s'", |
---|
279 | g_type_name (g_type), |
---|
280 | pspec->name); |
---|
281 | return; |
---|
282 | } |
---|
283 | |
---|
284 | g_param_spec_ref (pspec); |
---|
285 | g_param_spec_sink (pspec); |
---|
286 | PARAM_SPEC_SET_PARAM_ID (pspec, property_id); |
---|
287 | g_param_spec_pool_insert (pspec_pool, pspec, g_type); |
---|
288 | } |
---|
289 | |
---|
290 | void |
---|
291 | g_object_class_install_property (GObjectClass *class, |
---|
292 | guint property_id, |
---|
293 | GParamSpec *pspec) |
---|
294 | { |
---|
295 | g_return_if_fail (G_IS_OBJECT_CLASS (class)); |
---|
296 | g_return_if_fail (G_IS_PARAM_SPEC (pspec)); |
---|
297 | if (pspec->flags & G_PARAM_WRITABLE) |
---|
298 | g_return_if_fail (class->set_property != NULL); |
---|
299 | if (pspec->flags & G_PARAM_READABLE) |
---|
300 | g_return_if_fail (class->get_property != NULL); |
---|
301 | g_return_if_fail (property_id > 0); |
---|
302 | g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */ |
---|
303 | if (pspec->flags & G_PARAM_CONSTRUCT) |
---|
304 | g_return_if_fail ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); |
---|
305 | if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) |
---|
306 | g_return_if_fail (pspec->flags & G_PARAM_WRITABLE); |
---|
307 | |
---|
308 | install_property_internal (G_OBJECT_CLASS_TYPE (class), property_id, pspec); |
---|
309 | |
---|
310 | if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) |
---|
311 | class->construct_properties = g_slist_prepend (class->construct_properties, pspec); |
---|
312 | |
---|
313 | /* for property overrides of construct poperties, we have to get rid |
---|
314 | * of the overidden inherited construct property |
---|
315 | */ |
---|
316 | pspec = g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type_parent (G_OBJECT_CLASS_TYPE (class)), TRUE); |
---|
317 | if (pspec && pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) |
---|
318 | class->construct_properties = g_slist_remove (class->construct_properties, pspec); |
---|
319 | } |
---|
320 | |
---|
321 | void |
---|
322 | g_object_interface_install_property (gpointer g_iface, |
---|
323 | GParamSpec *pspec) |
---|
324 | { |
---|
325 | GTypeInterface *iface_class = g_iface; |
---|
326 | |
---|
327 | g_return_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type)); |
---|
328 | g_return_if_fail (G_IS_PARAM_SPEC (pspec)); |
---|
329 | g_return_if_fail (!G_IS_PARAM_SPEC_OVERRIDE (pspec)); /* paranoid */ |
---|
330 | g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */ |
---|
331 | |
---|
332 | install_property_internal (iface_class->g_type, 0, pspec); |
---|
333 | } |
---|
334 | |
---|
335 | GParamSpec* |
---|
336 | g_object_class_find_property (GObjectClass *class, |
---|
337 | const gchar *property_name) |
---|
338 | { |
---|
339 | GParamSpec *pspec; |
---|
340 | GParamSpec *redirect; |
---|
341 | |
---|
342 | g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL); |
---|
343 | g_return_val_if_fail (property_name != NULL, NULL); |
---|
344 | |
---|
345 | pspec = g_param_spec_pool_lookup (pspec_pool, |
---|
346 | property_name, |
---|
347 | G_OBJECT_CLASS_TYPE (class), |
---|
348 | TRUE); |
---|
349 | if (pspec) |
---|
350 | { |
---|
351 | redirect = g_param_spec_get_redirect_target (pspec); |
---|
352 | if (redirect) |
---|
353 | return redirect; |
---|
354 | else |
---|
355 | return pspec; |
---|
356 | } |
---|
357 | else |
---|
358 | return NULL; |
---|
359 | } |
---|
360 | |
---|
361 | GParamSpec* |
---|
362 | g_object_interface_find_property (gpointer g_iface, |
---|
363 | const gchar *property_name) |
---|
364 | { |
---|
365 | GTypeInterface *iface_class = g_iface; |
---|
366 | |
---|
367 | g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type), NULL); |
---|
368 | g_return_val_if_fail (property_name != NULL, NULL); |
---|
369 | |
---|
370 | return g_param_spec_pool_lookup (pspec_pool, |
---|
371 | property_name, |
---|
372 | iface_class->g_type, |
---|
373 | FALSE); |
---|
374 | } |
---|
375 | |
---|
376 | void |
---|
377 | g_object_class_override_property (GObjectClass *oclass, |
---|
378 | guint property_id, |
---|
379 | const gchar *name) |
---|
380 | { |
---|
381 | GParamSpec *overridden = NULL; |
---|
382 | GParamSpec *new; |
---|
383 | GType parent_type; |
---|
384 | |
---|
385 | g_return_if_fail (G_IS_OBJECT_CLASS (oclass)); |
---|
386 | g_return_if_fail (property_id > 0); |
---|
387 | g_return_if_fail (name != NULL); |
---|
388 | |
---|
389 | /* Find the overridden property; first check parent types |
---|
390 | */ |
---|
391 | parent_type = g_type_parent (G_OBJECT_CLASS_TYPE (oclass)); |
---|
392 | if (parent_type != G_TYPE_NONE) |
---|
393 | overridden = g_param_spec_pool_lookup (pspec_pool, |
---|
394 | name, |
---|
395 | parent_type, |
---|
396 | TRUE); |
---|
397 | if (!overridden) |
---|
398 | { |
---|
399 | GType *ifaces; |
---|
400 | guint n_ifaces; |
---|
401 | |
---|
402 | /* Now check interfaces |
---|
403 | */ |
---|
404 | ifaces = g_type_interfaces (G_OBJECT_CLASS_TYPE (oclass), &n_ifaces); |
---|
405 | while (n_ifaces-- && !overridden) |
---|
406 | { |
---|
407 | overridden = g_param_spec_pool_lookup (pspec_pool, |
---|
408 | name, |
---|
409 | ifaces[n_ifaces], |
---|
410 | FALSE); |
---|
411 | } |
---|
412 | |
---|
413 | g_free (ifaces); |
---|
414 | } |
---|
415 | |
---|
416 | if (!overridden) |
---|
417 | { |
---|
418 | g_warning ("%s: Can't find property to override for '%s::%s'", |
---|
419 | G_STRFUNC, G_OBJECT_CLASS_NAME (oclass), name); |
---|
420 | return; |
---|
421 | } |
---|
422 | |
---|
423 | new = g_param_spec_override (name, overridden); |
---|
424 | g_object_class_install_property (oclass, property_id, new); |
---|
425 | } |
---|
426 | |
---|
427 | GParamSpec** /* free result */ |
---|
428 | g_object_class_list_properties (GObjectClass *class, |
---|
429 | guint *n_properties_p) |
---|
430 | { |
---|
431 | GParamSpec **pspecs; |
---|
432 | guint n; |
---|
433 | |
---|
434 | g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL); |
---|
435 | |
---|
436 | pspecs = g_param_spec_pool_list (pspec_pool, |
---|
437 | G_OBJECT_CLASS_TYPE (class), |
---|
438 | &n); |
---|
439 | if (n_properties_p) |
---|
440 | *n_properties_p = n; |
---|
441 | |
---|
442 | return pspecs; |
---|
443 | } |
---|
444 | |
---|
445 | GParamSpec** /* free result */ |
---|
446 | g_object_interface_list_properties (gpointer g_iface, |
---|
447 | guint *n_properties_p) |
---|
448 | { |
---|
449 | GTypeInterface *iface_class = g_iface; |
---|
450 | GParamSpec **pspecs; |
---|
451 | guint n; |
---|
452 | |
---|
453 | g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type), NULL); |
---|
454 | |
---|
455 | pspecs = g_param_spec_pool_list (pspec_pool, |
---|
456 | iface_class->g_type, |
---|
457 | &n); |
---|
458 | if (n_properties_p) |
---|
459 | *n_properties_p = n; |
---|
460 | |
---|
461 | return pspecs; |
---|
462 | } |
---|
463 | |
---|
464 | static void |
---|
465 | g_object_init (GObject *object) |
---|
466 | { |
---|
467 | object->ref_count = 1; |
---|
468 | g_datalist_init (&object->qdata); |
---|
469 | |
---|
470 | /* freeze object's notification queue, g_object_newv() preserves pairedness */ |
---|
471 | g_object_notify_queue_freeze (object, &property_notify_context); |
---|
472 | |
---|
473 | /* allow construct-only properties to be set */ |
---|
474 | G_LOCK (construct_objects_lock); |
---|
475 | construct_objects = g_slist_prepend (construct_objects, object); |
---|
476 | G_UNLOCK (construct_objects_lock); |
---|
477 | |
---|
478 | #ifdef G_ENABLE_DEBUG |
---|
479 | IF_DEBUG (OBJECTS) |
---|
480 | { |
---|
481 | G_LOCK (debug_objects); |
---|
482 | debug_objects_count++; |
---|
483 | g_hash_table_insert (debug_objects_ht, object, object); |
---|
484 | G_UNLOCK (debug_objects); |
---|
485 | } |
---|
486 | #endif /* G_ENABLE_DEBUG */ |
---|
487 | } |
---|
488 | |
---|
489 | static void |
---|
490 | g_object_do_set_property (GObject *object, |
---|
491 | guint property_id, |
---|
492 | const GValue *value, |
---|
493 | GParamSpec *pspec) |
---|
494 | { |
---|
495 | switch (property_id) |
---|
496 | { |
---|
497 | default: |
---|
498 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
---|
499 | break; |
---|
500 | } |
---|
501 | } |
---|
502 | |
---|
503 | static void |
---|
504 | g_object_do_get_property (GObject *object, |
---|
505 | guint property_id, |
---|
506 | GValue *value, |
---|
507 | GParamSpec *pspec) |
---|
508 | { |
---|
509 | switch (property_id) |
---|
510 | { |
---|
511 | default: |
---|
512 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
---|
513 | break; |
---|
514 | } |
---|
515 | } |
---|
516 | |
---|
517 | static void |
---|
518 | g_object_real_dispose (GObject *object) |
---|
519 | { |
---|
520 | guint ref_count; |
---|
521 | |
---|
522 | g_signal_handlers_destroy (object); |
---|
523 | g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL); |
---|
524 | |
---|
525 | /* yes, temporarily altering the ref_count is hackish, but that |
---|
526 | * enforces people not jerking around with weak_ref notifiers |
---|
527 | */ |
---|
528 | ref_count = object->ref_count; |
---|
529 | object->ref_count = 0; |
---|
530 | g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL); |
---|
531 | object->ref_count = ref_count; |
---|
532 | } |
---|
533 | |
---|
534 | static void |
---|
535 | g_object_finalize (GObject *object) |
---|
536 | { |
---|
537 | g_datalist_clear (&object->qdata); |
---|
538 | |
---|
539 | #ifdef G_ENABLE_DEBUG |
---|
540 | IF_DEBUG (OBJECTS) |
---|
541 | { |
---|
542 | G_LOCK (debug_objects); |
---|
543 | g_assert (g_hash_table_lookup (debug_objects_ht, object) == object); |
---|
544 | g_hash_table_remove (debug_objects_ht, object); |
---|
545 | debug_objects_count--; |
---|
546 | G_UNLOCK (debug_objects); |
---|
547 | } |
---|
548 | #endif /* G_ENABLE_DEBUG */ |
---|
549 | } |
---|
550 | |
---|
551 | static void |
---|
552 | g_object_last_unref (GObject *object) |
---|
553 | { |
---|
554 | g_return_if_fail (object->ref_count > 0); |
---|
555 | |
---|
556 | if (object->ref_count == 1) /* may have been re-referenced meanwhile */ |
---|
557 | G_OBJECT_GET_CLASS (object)->dispose (object); |
---|
558 | |
---|
559 | #ifdef G_ENABLE_DEBUG |
---|
560 | if (g_trap_object_ref == object) |
---|
561 | G_BREAKPOINT (); |
---|
562 | #endif /* G_ENABLE_DEBUG */ |
---|
563 | |
---|
564 | object->ref_count -= 1; |
---|
565 | |
---|
566 | if (object->ref_count == 0) /* may have been re-referenced meanwhile */ |
---|
567 | { |
---|
568 | g_signal_handlers_destroy (object); |
---|
569 | g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL); |
---|
570 | G_OBJECT_GET_CLASS (object)->finalize (object); |
---|
571 | #ifdef G_ENABLE_DEBUG |
---|
572 | IF_DEBUG (OBJECTS) |
---|
573 | { |
---|
574 | /* catch objects not chaining finalize handlers */ |
---|
575 | G_LOCK (debug_objects); |
---|
576 | g_assert (g_hash_table_lookup (debug_objects_ht, object) == NULL); |
---|
577 | G_UNLOCK (debug_objects); |
---|
578 | } |
---|
579 | #endif /* G_ENABLE_DEBUG */ |
---|
580 | g_type_free_instance ((GTypeInstance*) object); |
---|
581 | } |
---|
582 | } |
---|
583 | |
---|
584 | static void |
---|
585 | g_object_dispatch_properties_changed (GObject *object, |
---|
586 | guint n_pspecs, |
---|
587 | GParamSpec **pspecs) |
---|
588 | { |
---|
589 | guint i; |
---|
590 | |
---|
591 | for (i = 0; i < n_pspecs; i++) |
---|
592 | g_signal_emit (object, gobject_signals[NOTIFY], g_quark_from_string (pspecs[i]->name), pspecs[i]); |
---|
593 | } |
---|
594 | |
---|
595 | void |
---|
596 | g_object_run_dispose (GObject *object) |
---|
597 | { |
---|
598 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
599 | g_return_if_fail (object->ref_count > 0); |
---|
600 | |
---|
601 | g_object_ref (object); |
---|
602 | G_OBJECT_GET_CLASS (object)->dispose (object); |
---|
603 | g_object_unref (object); |
---|
604 | } |
---|
605 | |
---|
606 | void |
---|
607 | g_object_freeze_notify (GObject *object) |
---|
608 | { |
---|
609 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
610 | if (!object->ref_count) |
---|
611 | return; |
---|
612 | |
---|
613 | g_object_ref (object); |
---|
614 | g_object_notify_queue_freeze (object, &property_notify_context); |
---|
615 | g_object_unref (object); |
---|
616 | } |
---|
617 | |
---|
618 | void |
---|
619 | g_object_notify (GObject *object, |
---|
620 | const gchar *property_name) |
---|
621 | { |
---|
622 | GParamSpec *pspec; |
---|
623 | |
---|
624 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
625 | g_return_if_fail (property_name != NULL); |
---|
626 | if (!object->ref_count) |
---|
627 | return; |
---|
628 | |
---|
629 | g_object_ref (object); |
---|
630 | /* We don't need to get the redirect target |
---|
631 | * (by, e.g. calling g_object_class_find_property()) |
---|
632 | * because g_object_notify_queue_add() does that |
---|
633 | */ |
---|
634 | pspec = g_param_spec_pool_lookup (pspec_pool, |
---|
635 | property_name, |
---|
636 | G_OBJECT_TYPE (object), |
---|
637 | TRUE); |
---|
638 | |
---|
639 | if (!pspec) |
---|
640 | g_warning ("%s: object class `%s' has no property named `%s'", |
---|
641 | G_STRFUNC, |
---|
642 | G_OBJECT_TYPE_NAME (object), |
---|
643 | property_name); |
---|
644 | else |
---|
645 | { |
---|
646 | GObjectNotifyQueue *nqueue = g_object_notify_queue_freeze (object, &property_notify_context); |
---|
647 | |
---|
648 | g_object_notify_queue_add (object, nqueue, pspec); |
---|
649 | g_object_notify_queue_thaw (object, nqueue); |
---|
650 | } |
---|
651 | g_object_unref (object); |
---|
652 | } |
---|
653 | |
---|
654 | void |
---|
655 | g_object_thaw_notify (GObject *object) |
---|
656 | { |
---|
657 | GObjectNotifyQueue *nqueue; |
---|
658 | |
---|
659 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
660 | if (!object->ref_count) |
---|
661 | return; |
---|
662 | |
---|
663 | g_object_ref (object); |
---|
664 | nqueue = g_object_notify_queue_from_object (object, &property_notify_context); |
---|
665 | if (!nqueue || !nqueue->freeze_count) |
---|
666 | g_warning ("%s: property-changed notification for %s(%p) is not frozen", |
---|
667 | G_STRFUNC, G_OBJECT_TYPE_NAME (object), object); |
---|
668 | else |
---|
669 | g_object_notify_queue_thaw (object, nqueue); |
---|
670 | g_object_unref (object); |
---|
671 | } |
---|
672 | |
---|
673 | static inline void |
---|
674 | object_get_property (GObject *object, |
---|
675 | GParamSpec *pspec, |
---|
676 | GValue *value) |
---|
677 | { |
---|
678 | GObjectClass *class = g_type_class_peek (pspec->owner_type); |
---|
679 | guint param_id = PARAM_SPEC_PARAM_ID (pspec); |
---|
680 | GParamSpec *redirect; |
---|
681 | |
---|
682 | redirect = g_param_spec_get_redirect_target (pspec); |
---|
683 | if (redirect) |
---|
684 | pspec = redirect; |
---|
685 | |
---|
686 | class->get_property (object, param_id, value, pspec); |
---|
687 | } |
---|
688 | |
---|
689 | static inline void |
---|
690 | object_set_property (GObject *object, |
---|
691 | GParamSpec *pspec, |
---|
692 | const GValue *value, |
---|
693 | GObjectNotifyQueue *nqueue) |
---|
694 | { |
---|
695 | GValue tmp_value = { 0, }; |
---|
696 | GObjectClass *class = g_type_class_peek (pspec->owner_type); |
---|
697 | guint param_id = PARAM_SPEC_PARAM_ID (pspec); |
---|
698 | GParamSpec *redirect; |
---|
699 | |
---|
700 | redirect = g_param_spec_get_redirect_target (pspec); |
---|
701 | if (redirect) |
---|
702 | pspec = redirect; |
---|
703 | |
---|
704 | /* provide a copy to work from, convert (if necessary) and validate */ |
---|
705 | g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); |
---|
706 | if (!g_value_transform (value, &tmp_value)) |
---|
707 | g_warning ("unable to set property `%s' of type `%s' from value of type `%s'", |
---|
708 | pspec->name, |
---|
709 | g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), |
---|
710 | G_VALUE_TYPE_NAME (value)); |
---|
711 | else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION)) |
---|
712 | { |
---|
713 | gchar *contents = g_strdup_value_contents (value); |
---|
714 | |
---|
715 | g_warning ("value \"%s\" of type `%s' is invalid or out of range for property `%s' of type `%s'", |
---|
716 | contents, |
---|
717 | G_VALUE_TYPE_NAME (value), |
---|
718 | pspec->name, |
---|
719 | g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec))); |
---|
720 | g_free (contents); |
---|
721 | } |
---|
722 | else |
---|
723 | { |
---|
724 | class->set_property (object, param_id, &tmp_value, pspec); |
---|
725 | g_object_notify_queue_add (object, nqueue, pspec); |
---|
726 | } |
---|
727 | g_value_unset (&tmp_value); |
---|
728 | } |
---|
729 | |
---|
730 | static void |
---|
731 | object_interface_check_properties (gpointer func_data, |
---|
732 | gpointer g_iface) |
---|
733 | { |
---|
734 | GTypeInterface *iface_class = g_iface; |
---|
735 | GObjectClass *class = g_type_class_peek (iface_class->g_instance_type); |
---|
736 | GType iface_type = iface_class->g_type; |
---|
737 | GParamSpec **pspecs; |
---|
738 | guint n; |
---|
739 | |
---|
740 | if (!G_IS_OBJECT_CLASS (class)) |
---|
741 | return; |
---|
742 | |
---|
743 | pspecs = g_param_spec_pool_list (pspec_pool, iface_type, &n); |
---|
744 | |
---|
745 | while (n--) |
---|
746 | { |
---|
747 | GParamSpec *class_pspec = g_param_spec_pool_lookup (pspec_pool, |
---|
748 | pspecs[n]->name, |
---|
749 | G_OBJECT_CLASS_TYPE (class), |
---|
750 | TRUE); |
---|
751 | |
---|
752 | if (!class_pspec) |
---|
753 | { |
---|
754 | g_critical ("Object class %s doesn't implement property " |
---|
755 | "'%s' from interface '%s'", |
---|
756 | g_type_name (G_OBJECT_CLASS_TYPE (class)), |
---|
757 | pspecs[n]->name, |
---|
758 | g_type_name (iface_type)); |
---|
759 | |
---|
760 | continue; |
---|
761 | } |
---|
762 | |
---|
763 | /* The implementation paramspec must have a less restrictive |
---|
764 | * type than the interface parameter spec for set() and a |
---|
765 | * more restrictive type for get(). We just require equality, |
---|
766 | * rather than doing something more complicated checking |
---|
767 | * the READABLE and WRITABLE flags. We also simplify here |
---|
768 | * by only checking the value type, not the G_PARAM_SPEC_TYPE. |
---|
769 | */ |
---|
770 | if (class_pspec && |
---|
771 | !g_type_is_a (G_PARAM_SPEC_VALUE_TYPE (pspecs[n]), |
---|
772 | G_PARAM_SPEC_VALUE_TYPE (class_pspec))) |
---|
773 | { |
---|
774 | g_critical ("Property '%s' on class '%s' has type '%s' " |
---|
775 | "which is different from the type '%s', " |
---|
776 | "of the property on interface '%s'\n", |
---|
777 | pspecs[n]->name, |
---|
778 | g_type_name (G_OBJECT_CLASS_TYPE (class)), |
---|
779 | g_type_name (G_PARAM_SPEC_VALUE_TYPE (class_pspec)), |
---|
780 | g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspecs[n])), |
---|
781 | g_type_name (iface_type)); |
---|
782 | } |
---|
783 | |
---|
784 | #define SUBSET(a,b,mask) (((a) & ~(b) & (mask)) == 0) |
---|
785 | |
---|
786 | /* CONSTRUCT and CONSTRUCT_ONLY add restrictions. |
---|
787 | * READABLE and WRITABLE remove restrictions. The implementation |
---|
788 | * paramspec must have less restrictive flags. |
---|
789 | */ |
---|
790 | if (class_pspec && |
---|
791 | (!SUBSET (class_pspec->flags, |
---|
792 | pspecs[n]->flags, |
---|
793 | G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY) || |
---|
794 | !SUBSET (pspecs[n]->flags, |
---|
795 | class_pspec->flags, |
---|
796 | G_PARAM_READABLE | G_PARAM_WRITABLE))) |
---|
797 | { |
---|
798 | g_critical ("Flags for property '%s' on class '%s' " |
---|
799 | "are not compatible with the property on" |
---|
800 | "interface '%s'\n", |
---|
801 | pspecs[n]->name, |
---|
802 | g_type_name (G_OBJECT_CLASS_TYPE (class)), |
---|
803 | g_type_name (iface_type)); |
---|
804 | } |
---|
805 | #undef SUBSET |
---|
806 | } |
---|
807 | |
---|
808 | g_free (pspecs); |
---|
809 | } |
---|
810 | |
---|
811 | gpointer |
---|
812 | g_object_new (GType object_type, |
---|
813 | const gchar *first_property_name, |
---|
814 | ...) |
---|
815 | { |
---|
816 | GObject *object; |
---|
817 | va_list var_args; |
---|
818 | |
---|
819 | g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL); |
---|
820 | |
---|
821 | va_start (var_args, first_property_name); |
---|
822 | object = g_object_new_valist (object_type, first_property_name, var_args); |
---|
823 | va_end (var_args); |
---|
824 | |
---|
825 | return object; |
---|
826 | } |
---|
827 | |
---|
828 | static gboolean |
---|
829 | object_in_construction (GObject *object) |
---|
830 | { |
---|
831 | gboolean in_construction; |
---|
832 | G_LOCK (construct_objects_lock); |
---|
833 | in_construction = g_slist_find (construct_objects, object) != NULL; |
---|
834 | G_UNLOCK (construct_objects_lock); |
---|
835 | return in_construction; |
---|
836 | } |
---|
837 | |
---|
838 | gpointer |
---|
839 | g_object_newv (GType object_type, |
---|
840 | guint n_parameters, |
---|
841 | GParameter *parameters) |
---|
842 | { |
---|
843 | GObjectConstructParam *cparams, *oparams; |
---|
844 | GObjectNotifyQueue *nqueue; |
---|
845 | GObject *object; |
---|
846 | GObjectClass *class, *unref_class = NULL; |
---|
847 | GSList *slist; |
---|
848 | guint n_total_cparams = 0, n_cparams = 0, n_oparams = 0, n_cvalues; |
---|
849 | GValue *cvalues; |
---|
850 | GList *clist = NULL; |
---|
851 | guint i; |
---|
852 | |
---|
853 | g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL); |
---|
854 | |
---|
855 | class = g_type_class_peek_static (object_type); |
---|
856 | if (!class) |
---|
857 | class = unref_class = g_type_class_ref (object_type); |
---|
858 | for (slist = class->construct_properties; slist; slist = slist->next) |
---|
859 | { |
---|
860 | clist = g_list_prepend (clist, slist->data); |
---|
861 | n_total_cparams += 1; |
---|
862 | } |
---|
863 | |
---|
864 | /* collect parameters, sort into construction and normal ones */ |
---|
865 | oparams = g_new (GObjectConstructParam, n_parameters); |
---|
866 | cparams = g_new (GObjectConstructParam, n_total_cparams); |
---|
867 | for (i = 0; i < n_parameters; i++) |
---|
868 | { |
---|
869 | GValue *value = ¶meters[i].value; |
---|
870 | GParamSpec *pspec = g_param_spec_pool_lookup (pspec_pool, |
---|
871 | parameters[i].name, |
---|
872 | object_type, |
---|
873 | TRUE); |
---|
874 | if (!pspec) |
---|
875 | { |
---|
876 | g_warning ("%s: object class `%s' has no property named `%s'", |
---|
877 | G_STRFUNC, |
---|
878 | g_type_name (object_type), |
---|
879 | parameters[i].name); |
---|
880 | continue; |
---|
881 | } |
---|
882 | if (!(pspec->flags & G_PARAM_WRITABLE)) |
---|
883 | { |
---|
884 | g_warning ("%s: property `%s' of object class `%s' is not writable", |
---|
885 | G_STRFUNC, |
---|
886 | pspec->name, |
---|
887 | g_type_name (object_type)); |
---|
888 | continue; |
---|
889 | } |
---|
890 | if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) |
---|
891 | { |
---|
892 | GList *list = g_list_find (clist, pspec); |
---|
893 | |
---|
894 | if (!list) |
---|
895 | { |
---|
896 | g_warning ("%s: construct property \"%s\" for object `%s' can't be set twice", |
---|
897 | G_STRFUNC, pspec->name, g_type_name (object_type)); |
---|
898 | continue; |
---|
899 | } |
---|
900 | cparams[n_cparams].pspec = pspec; |
---|
901 | cparams[n_cparams].value = value; |
---|
902 | n_cparams++; |
---|
903 | if (!list->prev) |
---|
904 | clist = list->next; |
---|
905 | else |
---|
906 | list->prev->next = list->next; |
---|
907 | if (list->next) |
---|
908 | list->next->prev = list->prev; |
---|
909 | g_list_free_1 (list); |
---|
910 | } |
---|
911 | else |
---|
912 | { |
---|
913 | oparams[n_oparams].pspec = pspec; |
---|
914 | oparams[n_oparams].value = value; |
---|
915 | n_oparams++; |
---|
916 | } |
---|
917 | } |
---|
918 | |
---|
919 | /* set remaining construction properties to default values */ |
---|
920 | n_cvalues = n_total_cparams - n_cparams; |
---|
921 | cvalues = g_new (GValue, n_cvalues); |
---|
922 | while (clist) |
---|
923 | { |
---|
924 | GList *tmp = clist->next; |
---|
925 | GParamSpec *pspec = clist->data; |
---|
926 | GValue *value = cvalues + n_total_cparams - n_cparams - 1; |
---|
927 | |
---|
928 | value->g_type = 0; |
---|
929 | g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec)); |
---|
930 | g_param_value_set_default (pspec, value); |
---|
931 | |
---|
932 | cparams[n_cparams].pspec = pspec; |
---|
933 | cparams[n_cparams].value = value; |
---|
934 | n_cparams++; |
---|
935 | |
---|
936 | g_list_free_1 (clist); |
---|
937 | clist = tmp; |
---|
938 | } |
---|
939 | |
---|
940 | /* construct object from construction parameters */ |
---|
941 | object = class->constructor (object_type, n_total_cparams, cparams); |
---|
942 | G_LOCK (construct_objects_lock); |
---|
943 | construct_objects = g_slist_remove (construct_objects, object); |
---|
944 | G_UNLOCK (construct_objects_lock); |
---|
945 | |
---|
946 | /* free construction values */ |
---|
947 | g_free (cparams); |
---|
948 | while (n_cvalues--) |
---|
949 | g_value_unset (cvalues + n_cvalues); |
---|
950 | g_free (cvalues); |
---|
951 | |
---|
952 | /* release g_object_init() notification queue freeze_count */ |
---|
953 | nqueue = g_object_notify_queue_freeze (object, &property_notify_context); |
---|
954 | g_object_notify_queue_thaw (object, nqueue); |
---|
955 | |
---|
956 | /* set remaining properties */ |
---|
957 | for (i = 0; i < n_oparams; i++) |
---|
958 | object_set_property (object, oparams[i].pspec, oparams[i].value, nqueue); |
---|
959 | g_free (oparams); |
---|
960 | |
---|
961 | if (unref_class) |
---|
962 | g_type_class_unref (unref_class); |
---|
963 | |
---|
964 | /* release our own freeze count and handle notifications */ |
---|
965 | g_object_notify_queue_thaw (object, nqueue); |
---|
966 | |
---|
967 | return object; |
---|
968 | } |
---|
969 | |
---|
970 | GObject* |
---|
971 | g_object_new_valist (GType object_type, |
---|
972 | const gchar *first_property_name, |
---|
973 | va_list var_args) |
---|
974 | { |
---|
975 | GObjectClass *class; |
---|
976 | GParameter *params; |
---|
977 | const gchar *name; |
---|
978 | GObject *object; |
---|
979 | guint n_params = 0, n_alloced_params = 16; |
---|
980 | |
---|
981 | g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL); |
---|
982 | |
---|
983 | if (!first_property_name) |
---|
984 | return g_object_newv (object_type, 0, NULL); |
---|
985 | |
---|
986 | class = g_type_class_ref (object_type); |
---|
987 | |
---|
988 | params = g_new (GParameter, n_alloced_params); |
---|
989 | name = first_property_name; |
---|
990 | while (name) |
---|
991 | { |
---|
992 | gchar *error = NULL; |
---|
993 | GParamSpec *pspec = g_param_spec_pool_lookup (pspec_pool, |
---|
994 | name, |
---|
995 | object_type, |
---|
996 | TRUE); |
---|
997 | if (!pspec) |
---|
998 | { |
---|
999 | g_warning ("%s: object class `%s' has no property named `%s'", |
---|
1000 | G_STRFUNC, |
---|
1001 | g_type_name (object_type), |
---|
1002 | name); |
---|
1003 | break; |
---|
1004 | } |
---|
1005 | if (n_params >= n_alloced_params) |
---|
1006 | { |
---|
1007 | n_alloced_params += 16; |
---|
1008 | params = g_renew (GParameter, params, n_alloced_params); |
---|
1009 | } |
---|
1010 | params[n_params].name = name; |
---|
1011 | params[n_params].value.g_type = 0; |
---|
1012 | g_value_init (¶ms[n_params].value, G_PARAM_SPEC_VALUE_TYPE (pspec)); |
---|
1013 | G_VALUE_COLLECT (¶ms[n_params].value, var_args, 0, &error); |
---|
1014 | if (error) |
---|
1015 | { |
---|
1016 | g_warning ("%s: %s", G_STRFUNC, error); |
---|
1017 | g_free (error); |
---|
1018 | g_value_unset (¶ms[n_params].value); |
---|
1019 | break; |
---|
1020 | } |
---|
1021 | n_params++; |
---|
1022 | name = va_arg (var_args, gchar*); |
---|
1023 | } |
---|
1024 | |
---|
1025 | object = g_object_newv (object_type, n_params, params); |
---|
1026 | |
---|
1027 | while (n_params--) |
---|
1028 | g_value_unset (¶ms[n_params].value); |
---|
1029 | g_free (params); |
---|
1030 | |
---|
1031 | g_type_class_unref (class); |
---|
1032 | |
---|
1033 | return object; |
---|
1034 | } |
---|
1035 | |
---|
1036 | static GObject* |
---|
1037 | g_object_constructor (GType type, |
---|
1038 | guint n_construct_properties, |
---|
1039 | GObjectConstructParam *construct_params) |
---|
1040 | { |
---|
1041 | GObject *object; |
---|
1042 | |
---|
1043 | /* create object */ |
---|
1044 | object = (GObject*) g_type_create_instance (type); |
---|
1045 | |
---|
1046 | /* set construction parameters */ |
---|
1047 | if (n_construct_properties) |
---|
1048 | { |
---|
1049 | GObjectNotifyQueue *nqueue = g_object_notify_queue_freeze (object, &property_notify_context); |
---|
1050 | |
---|
1051 | /* set construct properties */ |
---|
1052 | while (n_construct_properties--) |
---|
1053 | { |
---|
1054 | GValue *value = construct_params->value; |
---|
1055 | GParamSpec *pspec = construct_params->pspec; |
---|
1056 | |
---|
1057 | construct_params++; |
---|
1058 | object_set_property (object, pspec, value, nqueue); |
---|
1059 | } |
---|
1060 | g_object_notify_queue_thaw (object, nqueue); |
---|
1061 | /* the notification queue is still frozen from g_object_init(), so |
---|
1062 | * we don't need to handle it here, g_object_newv() takes |
---|
1063 | * care of that |
---|
1064 | */ |
---|
1065 | } |
---|
1066 | |
---|
1067 | return object; |
---|
1068 | } |
---|
1069 | |
---|
1070 | void |
---|
1071 | g_object_set_valist (GObject *object, |
---|
1072 | const gchar *first_property_name, |
---|
1073 | va_list var_args) |
---|
1074 | { |
---|
1075 | GObjectNotifyQueue *nqueue; |
---|
1076 | const gchar *name; |
---|
1077 | |
---|
1078 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1079 | |
---|
1080 | g_object_ref (object); |
---|
1081 | nqueue = g_object_notify_queue_freeze (object, &property_notify_context); |
---|
1082 | |
---|
1083 | name = first_property_name; |
---|
1084 | while (name) |
---|
1085 | { |
---|
1086 | GValue value = { 0, }; |
---|
1087 | GParamSpec *pspec; |
---|
1088 | gchar *error = NULL; |
---|
1089 | |
---|
1090 | pspec = g_param_spec_pool_lookup (pspec_pool, |
---|
1091 | name, |
---|
1092 | G_OBJECT_TYPE (object), |
---|
1093 | TRUE); |
---|
1094 | if (!pspec) |
---|
1095 | { |
---|
1096 | g_warning ("%s: object class `%s' has no property named `%s'", |
---|
1097 | G_STRFUNC, |
---|
1098 | G_OBJECT_TYPE_NAME (object), |
---|
1099 | name); |
---|
1100 | break; |
---|
1101 | } |
---|
1102 | if (!(pspec->flags & G_PARAM_WRITABLE)) |
---|
1103 | { |
---|
1104 | g_warning ("%s: property `%s' of object class `%s' is not writable", |
---|
1105 | G_STRFUNC, |
---|
1106 | pspec->name, |
---|
1107 | G_OBJECT_TYPE_NAME (object)); |
---|
1108 | break; |
---|
1109 | } |
---|
1110 | if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) && !object_in_construction (object)) |
---|
1111 | { |
---|
1112 | g_warning ("%s: construct property \"%s\" for object `%s' can't be set after construction", |
---|
1113 | G_STRFUNC, pspec->name, G_OBJECT_TYPE_NAME (object)); |
---|
1114 | break; |
---|
1115 | } |
---|
1116 | |
---|
1117 | g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); |
---|
1118 | |
---|
1119 | G_VALUE_COLLECT (&value, var_args, 0, &error); |
---|
1120 | if (error) |
---|
1121 | { |
---|
1122 | g_warning ("%s: %s", G_STRFUNC, error); |
---|
1123 | g_free (error); |
---|
1124 | g_value_unset (&value); |
---|
1125 | break; |
---|
1126 | } |
---|
1127 | |
---|
1128 | object_set_property (object, pspec, &value, nqueue); |
---|
1129 | g_value_unset (&value); |
---|
1130 | |
---|
1131 | name = va_arg (var_args, gchar*); |
---|
1132 | } |
---|
1133 | |
---|
1134 | g_object_notify_queue_thaw (object, nqueue); |
---|
1135 | g_object_unref (object); |
---|
1136 | } |
---|
1137 | |
---|
1138 | void |
---|
1139 | g_object_get_valist (GObject *object, |
---|
1140 | const gchar *first_property_name, |
---|
1141 | va_list var_args) |
---|
1142 | { |
---|
1143 | const gchar *name; |
---|
1144 | |
---|
1145 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1146 | |
---|
1147 | g_object_ref (object); |
---|
1148 | |
---|
1149 | name = first_property_name; |
---|
1150 | |
---|
1151 | while (name) |
---|
1152 | { |
---|
1153 | GValue value = { 0, }; |
---|
1154 | GParamSpec *pspec; |
---|
1155 | gchar *error; |
---|
1156 | |
---|
1157 | pspec = g_param_spec_pool_lookup (pspec_pool, |
---|
1158 | name, |
---|
1159 | G_OBJECT_TYPE (object), |
---|
1160 | TRUE); |
---|
1161 | if (!pspec) |
---|
1162 | { |
---|
1163 | g_warning ("%s: object class `%s' has no property named `%s'", |
---|
1164 | G_STRFUNC, |
---|
1165 | G_OBJECT_TYPE_NAME (object), |
---|
1166 | name); |
---|
1167 | break; |
---|
1168 | } |
---|
1169 | if (!(pspec->flags & G_PARAM_READABLE)) |
---|
1170 | { |
---|
1171 | g_warning ("%s: property `%s' of object class `%s' is not readable", |
---|
1172 | G_STRFUNC, |
---|
1173 | pspec->name, |
---|
1174 | G_OBJECT_TYPE_NAME (object)); |
---|
1175 | break; |
---|
1176 | } |
---|
1177 | |
---|
1178 | g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); |
---|
1179 | |
---|
1180 | object_get_property (object, pspec, &value); |
---|
1181 | |
---|
1182 | G_VALUE_LCOPY (&value, var_args, 0, &error); |
---|
1183 | if (error) |
---|
1184 | { |
---|
1185 | g_warning ("%s: %s", G_STRFUNC, error); |
---|
1186 | g_free (error); |
---|
1187 | g_value_unset (&value); |
---|
1188 | break; |
---|
1189 | } |
---|
1190 | |
---|
1191 | g_value_unset (&value); |
---|
1192 | |
---|
1193 | name = va_arg (var_args, gchar*); |
---|
1194 | } |
---|
1195 | |
---|
1196 | g_object_unref (object); |
---|
1197 | } |
---|
1198 | |
---|
1199 | void |
---|
1200 | g_object_set (gpointer _object, |
---|
1201 | const gchar *first_property_name, |
---|
1202 | ...) |
---|
1203 | { |
---|
1204 | GObject *object = _object; |
---|
1205 | va_list var_args; |
---|
1206 | |
---|
1207 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1208 | |
---|
1209 | va_start (var_args, first_property_name); |
---|
1210 | g_object_set_valist (object, first_property_name, var_args); |
---|
1211 | va_end (var_args); |
---|
1212 | } |
---|
1213 | |
---|
1214 | void |
---|
1215 | g_object_get (gpointer _object, |
---|
1216 | const gchar *first_property_name, |
---|
1217 | ...) |
---|
1218 | { |
---|
1219 | GObject *object = _object; |
---|
1220 | va_list var_args; |
---|
1221 | |
---|
1222 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1223 | |
---|
1224 | va_start (var_args, first_property_name); |
---|
1225 | g_object_get_valist (object, first_property_name, var_args); |
---|
1226 | va_end (var_args); |
---|
1227 | } |
---|
1228 | |
---|
1229 | void |
---|
1230 | g_object_set_property (GObject *object, |
---|
1231 | const gchar *property_name, |
---|
1232 | const GValue *value) |
---|
1233 | { |
---|
1234 | GObjectNotifyQueue *nqueue; |
---|
1235 | GParamSpec *pspec; |
---|
1236 | |
---|
1237 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1238 | g_return_if_fail (property_name != NULL); |
---|
1239 | g_return_if_fail (G_IS_VALUE (value)); |
---|
1240 | |
---|
1241 | g_object_ref (object); |
---|
1242 | nqueue = g_object_notify_queue_freeze (object, &property_notify_context); |
---|
1243 | |
---|
1244 | pspec = g_param_spec_pool_lookup (pspec_pool, |
---|
1245 | property_name, |
---|
1246 | G_OBJECT_TYPE (object), |
---|
1247 | TRUE); |
---|
1248 | if (!pspec) |
---|
1249 | g_warning ("%s: object class `%s' has no property named `%s'", |
---|
1250 | G_STRFUNC, |
---|
1251 | G_OBJECT_TYPE_NAME (object), |
---|
1252 | property_name); |
---|
1253 | else if (!(pspec->flags & G_PARAM_WRITABLE)) |
---|
1254 | g_warning ("%s: property `%s' of object class `%s' is not writable", |
---|
1255 | G_STRFUNC, |
---|
1256 | pspec->name, |
---|
1257 | G_OBJECT_TYPE_NAME (object)); |
---|
1258 | else if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) && !object_in_construction (object)) |
---|
1259 | g_warning ("%s: construct property \"%s\" for object `%s' can't be set after construction", |
---|
1260 | G_STRFUNC, pspec->name, G_OBJECT_TYPE_NAME (object)); |
---|
1261 | else |
---|
1262 | object_set_property (object, pspec, value, nqueue); |
---|
1263 | |
---|
1264 | g_object_notify_queue_thaw (object, nqueue); |
---|
1265 | g_object_unref (object); |
---|
1266 | } |
---|
1267 | |
---|
1268 | void |
---|
1269 | g_object_get_property (GObject *object, |
---|
1270 | const gchar *property_name, |
---|
1271 | GValue *value) |
---|
1272 | { |
---|
1273 | GParamSpec *pspec; |
---|
1274 | |
---|
1275 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1276 | g_return_if_fail (property_name != NULL); |
---|
1277 | g_return_if_fail (G_IS_VALUE (value)); |
---|
1278 | |
---|
1279 | g_object_ref (object); |
---|
1280 | |
---|
1281 | pspec = g_param_spec_pool_lookup (pspec_pool, |
---|
1282 | property_name, |
---|
1283 | G_OBJECT_TYPE (object), |
---|
1284 | TRUE); |
---|
1285 | if (!pspec) |
---|
1286 | g_warning ("%s: object class `%s' has no property named `%s'", |
---|
1287 | G_STRFUNC, |
---|
1288 | G_OBJECT_TYPE_NAME (object), |
---|
1289 | property_name); |
---|
1290 | else if (!(pspec->flags & G_PARAM_READABLE)) |
---|
1291 | g_warning ("%s: property `%s' of object class `%s' is not readable", |
---|
1292 | G_STRFUNC, |
---|
1293 | pspec->name, |
---|
1294 | G_OBJECT_TYPE_NAME (object)); |
---|
1295 | else |
---|
1296 | { |
---|
1297 | GValue *prop_value, tmp_value = { 0, }; |
---|
1298 | |
---|
1299 | /* auto-conversion of the callers value type |
---|
1300 | */ |
---|
1301 | if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec)) |
---|
1302 | { |
---|
1303 | g_value_reset (value); |
---|
1304 | prop_value = value; |
---|
1305 | } |
---|
1306 | else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value))) |
---|
1307 | { |
---|
1308 | g_warning ("%s: can't retrieve property `%s' of type `%s' as value of type `%s'", |
---|
1309 | G_STRFUNC, pspec->name, |
---|
1310 | g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), |
---|
1311 | G_VALUE_TYPE_NAME (value)); |
---|
1312 | g_object_unref (object); |
---|
1313 | return; |
---|
1314 | } |
---|
1315 | else |
---|
1316 | { |
---|
1317 | g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); |
---|
1318 | prop_value = &tmp_value; |
---|
1319 | } |
---|
1320 | object_get_property (object, pspec, prop_value); |
---|
1321 | if (prop_value != value) |
---|
1322 | { |
---|
1323 | g_value_transform (prop_value, value); |
---|
1324 | g_value_unset (&tmp_value); |
---|
1325 | } |
---|
1326 | } |
---|
1327 | |
---|
1328 | g_object_unref (object); |
---|
1329 | } |
---|
1330 | |
---|
1331 | gpointer |
---|
1332 | g_object_connect (gpointer _object, |
---|
1333 | const gchar *signal_spec, |
---|
1334 | ...) |
---|
1335 | { |
---|
1336 | GObject *object = _object; |
---|
1337 | va_list var_args; |
---|
1338 | |
---|
1339 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
---|
1340 | g_return_val_if_fail (object->ref_count > 0, object); |
---|
1341 | |
---|
1342 | va_start (var_args, signal_spec); |
---|
1343 | while (signal_spec) |
---|
1344 | { |
---|
1345 | GCallback callback = va_arg (var_args, GCallback); |
---|
1346 | gpointer data = va_arg (var_args, gpointer); |
---|
1347 | gulong sid; |
---|
1348 | |
---|
1349 | if (strncmp (signal_spec, "signal::", 8) == 0) |
---|
1350 | sid = g_signal_connect_data (object, signal_spec + 8, |
---|
1351 | callback, data, NULL, |
---|
1352 | 0); |
---|
1353 | else if (strncmp (signal_spec, "object_signal::", 15) == 0 || |
---|
1354 | strncmp (signal_spec, "object-signal::", 15) == 0) |
---|
1355 | sid = g_signal_connect_object (object, signal_spec + 15, |
---|
1356 | callback, data, |
---|
1357 | 0); |
---|
1358 | else if (strncmp (signal_spec, "swapped_signal::", 16) == 0 || |
---|
1359 | strncmp (signal_spec, "swapped-signal::", 16) == 0) |
---|
1360 | sid = g_signal_connect_data (object, signal_spec + 16, |
---|
1361 | callback, data, NULL, |
---|
1362 | G_CONNECT_SWAPPED); |
---|
1363 | else if (strncmp (signal_spec, "swapped_object_signal::", 23) == 0 || |
---|
1364 | strncmp (signal_spec, "swapped-object-signal::", 23) == 0) |
---|
1365 | sid = g_signal_connect_object (object, signal_spec + 23, |
---|
1366 | callback, data, |
---|
1367 | G_CONNECT_SWAPPED); |
---|
1368 | else if (strncmp (signal_spec, "signal_after::", 14) == 0 || |
---|
1369 | strncmp (signal_spec, "signal-after::", 14) == 0) |
---|
1370 | sid = g_signal_connect_data (object, signal_spec + 14, |
---|
1371 | callback, data, NULL, |
---|
1372 | G_CONNECT_AFTER); |
---|
1373 | else if (strncmp (signal_spec, "object_signal_after::", 21) == 0 || |
---|
1374 | strncmp (signal_spec, "object-signal-after::", 21) == 0) |
---|
1375 | sid = g_signal_connect_object (object, signal_spec + 21, |
---|
1376 | callback, data, |
---|
1377 | G_CONNECT_AFTER); |
---|
1378 | else if (strncmp (signal_spec, "swapped_signal_after::", 22) == 0 || |
---|
1379 | strncmp (signal_spec, "swapped-signal-after::", 22) == 0) |
---|
1380 | sid = g_signal_connect_data (object, signal_spec + 22, |
---|
1381 | callback, data, NULL, |
---|
1382 | G_CONNECT_SWAPPED | G_CONNECT_AFTER); |
---|
1383 | else if (strncmp (signal_spec, "swapped_object_signal_after::", 29) == 0 || |
---|
1384 | strncmp (signal_spec, "swapped-object-signal-after::", 29) == 0) |
---|
1385 | sid = g_signal_connect_object (object, signal_spec + 29, |
---|
1386 | callback, data, |
---|
1387 | G_CONNECT_SWAPPED | G_CONNECT_AFTER); |
---|
1388 | else |
---|
1389 | { |
---|
1390 | g_warning ("%s: invalid signal spec \"%s\"", G_STRFUNC, signal_spec); |
---|
1391 | break; |
---|
1392 | } |
---|
1393 | signal_spec = va_arg (var_args, gchar*); |
---|
1394 | } |
---|
1395 | va_end (var_args); |
---|
1396 | |
---|
1397 | return object; |
---|
1398 | } |
---|
1399 | |
---|
1400 | void |
---|
1401 | g_object_disconnect (gpointer _object, |
---|
1402 | const gchar *signal_spec, |
---|
1403 | ...) |
---|
1404 | { |
---|
1405 | GObject *object = _object; |
---|
1406 | va_list var_args; |
---|
1407 | |
---|
1408 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1409 | g_return_if_fail (object->ref_count > 0); |
---|
1410 | |
---|
1411 | va_start (var_args, signal_spec); |
---|
1412 | while (signal_spec) |
---|
1413 | { |
---|
1414 | GCallback callback = va_arg (var_args, GCallback); |
---|
1415 | gpointer data = va_arg (var_args, gpointer); |
---|
1416 | guint sid = 0, detail = 0, mask = 0; |
---|
1417 | |
---|
1418 | if (strncmp (signal_spec, "any_signal::", 12) == 0 || |
---|
1419 | strncmp (signal_spec, "any-signal::", 12) == 0) |
---|
1420 | { |
---|
1421 | signal_spec += 12; |
---|
1422 | mask = G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA; |
---|
1423 | } |
---|
1424 | else if (strcmp (signal_spec, "any_signal") == 0 || |
---|
1425 | strcmp (signal_spec, "any-signal") == 0) |
---|
1426 | { |
---|
1427 | signal_spec += 10; |
---|
1428 | mask = G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA; |
---|
1429 | } |
---|
1430 | else |
---|
1431 | { |
---|
1432 | g_warning ("%s: invalid signal spec \"%s\"", G_STRFUNC, signal_spec); |
---|
1433 | break; |
---|
1434 | } |
---|
1435 | |
---|
1436 | if ((mask & G_SIGNAL_MATCH_ID) && |
---|
1437 | !g_signal_parse_name (signal_spec, G_OBJECT_TYPE (object), &sid, &detail, FALSE)) |
---|
1438 | g_warning ("%s: invalid signal name \"%s\"", G_STRFUNC, signal_spec); |
---|
1439 | else if (!g_signal_handlers_disconnect_matched (object, mask | (detail ? G_SIGNAL_MATCH_DETAIL : 0), |
---|
1440 | sid, detail, |
---|
1441 | NULL, (gpointer)callback, data)) |
---|
1442 | g_warning ("%s: signal handler %p(%p) is not connected", G_STRFUNC, callback, data); |
---|
1443 | signal_spec = va_arg (var_args, gchar*); |
---|
1444 | } |
---|
1445 | va_end (var_args); |
---|
1446 | } |
---|
1447 | |
---|
1448 | typedef struct { |
---|
1449 | GObject *object; |
---|
1450 | guint n_weak_refs; |
---|
1451 | struct { |
---|
1452 | GWeakNotify notify; |
---|
1453 | gpointer data; |
---|
1454 | } weak_refs[1]; /* flexible array */ |
---|
1455 | } WeakRefStack; |
---|
1456 | |
---|
1457 | static void |
---|
1458 | weak_refs_notify (gpointer data) |
---|
1459 | { |
---|
1460 | WeakRefStack *wstack = data; |
---|
1461 | guint i; |
---|
1462 | |
---|
1463 | for (i = 0; i < wstack->n_weak_refs; i++) |
---|
1464 | wstack->weak_refs[i].notify (wstack->weak_refs[i].data, wstack->object); |
---|
1465 | g_free (wstack); |
---|
1466 | } |
---|
1467 | |
---|
1468 | void |
---|
1469 | g_object_weak_ref (GObject *object, |
---|
1470 | GWeakNotify notify, |
---|
1471 | gpointer data) |
---|
1472 | { |
---|
1473 | WeakRefStack *wstack; |
---|
1474 | guint i; |
---|
1475 | |
---|
1476 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1477 | g_return_if_fail (notify != NULL); |
---|
1478 | g_return_if_fail (object->ref_count >= 1); |
---|
1479 | |
---|
1480 | wstack = g_datalist_id_remove_no_notify (&object->qdata, quark_weak_refs); |
---|
1481 | if (wstack) |
---|
1482 | { |
---|
1483 | i = wstack->n_weak_refs++; |
---|
1484 | wstack = g_realloc (wstack, sizeof (*wstack) + sizeof (wstack->weak_refs[0]) * i); |
---|
1485 | } |
---|
1486 | else |
---|
1487 | { |
---|
1488 | wstack = g_renew (WeakRefStack, NULL, 1); |
---|
1489 | wstack->object = object; |
---|
1490 | wstack->n_weak_refs = 1; |
---|
1491 | i = 0; |
---|
1492 | } |
---|
1493 | wstack->weak_refs[i].notify = notify; |
---|
1494 | wstack->weak_refs[i].data = data; |
---|
1495 | g_datalist_id_set_data_full (&object->qdata, quark_weak_refs, wstack, weak_refs_notify); |
---|
1496 | } |
---|
1497 | |
---|
1498 | void |
---|
1499 | g_object_weak_unref (GObject *object, |
---|
1500 | GWeakNotify notify, |
---|
1501 | gpointer data) |
---|
1502 | { |
---|
1503 | WeakRefStack *wstack; |
---|
1504 | gboolean found_one = FALSE; |
---|
1505 | |
---|
1506 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1507 | g_return_if_fail (notify != NULL); |
---|
1508 | |
---|
1509 | wstack = g_datalist_id_get_data (&object->qdata, quark_weak_refs); |
---|
1510 | if (wstack) |
---|
1511 | { |
---|
1512 | guint i; |
---|
1513 | |
---|
1514 | for (i = 0; i < wstack->n_weak_refs; i++) |
---|
1515 | if (wstack->weak_refs[i].notify == notify && |
---|
1516 | wstack->weak_refs[i].data == data) |
---|
1517 | { |
---|
1518 | found_one = TRUE; |
---|
1519 | wstack->n_weak_refs -= 1; |
---|
1520 | if (i != wstack->n_weak_refs) |
---|
1521 | { |
---|
1522 | wstack->weak_refs[i].notify = wstack->weak_refs[wstack->n_weak_refs].notify; |
---|
1523 | wstack->weak_refs[i].data = wstack->weak_refs[wstack->n_weak_refs].data; |
---|
1524 | } |
---|
1525 | break; |
---|
1526 | } |
---|
1527 | } |
---|
1528 | if (!found_one) |
---|
1529 | g_warning ("%s: couldn't find weak ref %p(%p)", G_STRFUNC, notify, data); |
---|
1530 | } |
---|
1531 | |
---|
1532 | void |
---|
1533 | g_object_add_weak_pointer (GObject *object, |
---|
1534 | gpointer *weak_pointer_location) |
---|
1535 | { |
---|
1536 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1537 | g_return_if_fail (weak_pointer_location != NULL); |
---|
1538 | |
---|
1539 | g_object_weak_ref (object, |
---|
1540 | (GWeakNotify) g_nullify_pointer, |
---|
1541 | weak_pointer_location); |
---|
1542 | } |
---|
1543 | |
---|
1544 | void |
---|
1545 | g_object_remove_weak_pointer (GObject *object, |
---|
1546 | gpointer *weak_pointer_location) |
---|
1547 | { |
---|
1548 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1549 | g_return_if_fail (weak_pointer_location != NULL); |
---|
1550 | |
---|
1551 | g_object_weak_unref (object, |
---|
1552 | (GWeakNotify) g_nullify_pointer, |
---|
1553 | weak_pointer_location); |
---|
1554 | } |
---|
1555 | |
---|
1556 | gpointer |
---|
1557 | g_object_ref (gpointer _object) |
---|
1558 | { |
---|
1559 | GObject *object = _object; |
---|
1560 | |
---|
1561 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
---|
1562 | g_return_val_if_fail (object->ref_count > 0, NULL); |
---|
1563 | |
---|
1564 | #ifdef G_ENABLE_DEBUG |
---|
1565 | if (g_trap_object_ref == object) |
---|
1566 | G_BREAKPOINT (); |
---|
1567 | #endif /* G_ENABLE_DEBUG */ |
---|
1568 | |
---|
1569 | object->ref_count += 1; |
---|
1570 | |
---|
1571 | return object; |
---|
1572 | } |
---|
1573 | |
---|
1574 | void |
---|
1575 | g_object_unref (gpointer _object) |
---|
1576 | { |
---|
1577 | GObject *object = _object; |
---|
1578 | |
---|
1579 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1580 | g_return_if_fail (object->ref_count > 0); |
---|
1581 | |
---|
1582 | #ifdef G_ENABLE_DEBUG |
---|
1583 | if (g_trap_object_ref == object) |
---|
1584 | G_BREAKPOINT (); |
---|
1585 | #endif /* G_ENABLE_DEBUG */ |
---|
1586 | |
---|
1587 | if (object->ref_count > 1) |
---|
1588 | object->ref_count -= 1; |
---|
1589 | else |
---|
1590 | g_object_last_unref (object); |
---|
1591 | } |
---|
1592 | |
---|
1593 | gpointer |
---|
1594 | g_object_get_qdata (GObject *object, |
---|
1595 | GQuark quark) |
---|
1596 | { |
---|
1597 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
---|
1598 | |
---|
1599 | return quark ? g_datalist_id_get_data (&object->qdata, quark) : NULL; |
---|
1600 | } |
---|
1601 | |
---|
1602 | void |
---|
1603 | g_object_set_qdata (GObject *object, |
---|
1604 | GQuark quark, |
---|
1605 | gpointer data) |
---|
1606 | { |
---|
1607 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1608 | g_return_if_fail (quark > 0); |
---|
1609 | |
---|
1610 | g_datalist_id_set_data (&object->qdata, quark, data); |
---|
1611 | } |
---|
1612 | |
---|
1613 | void |
---|
1614 | g_object_set_qdata_full (GObject *object, |
---|
1615 | GQuark quark, |
---|
1616 | gpointer data, |
---|
1617 | GDestroyNotify destroy) |
---|
1618 | { |
---|
1619 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1620 | g_return_if_fail (quark > 0); |
---|
1621 | |
---|
1622 | g_datalist_id_set_data_full (&object->qdata, quark, data, |
---|
1623 | data ? destroy : (GDestroyNotify) NULL); |
---|
1624 | } |
---|
1625 | |
---|
1626 | gpointer |
---|
1627 | g_object_steal_qdata (GObject *object, |
---|
1628 | GQuark quark) |
---|
1629 | { |
---|
1630 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
---|
1631 | g_return_val_if_fail (quark > 0, NULL); |
---|
1632 | |
---|
1633 | return g_datalist_id_remove_no_notify (&object->qdata, quark); |
---|
1634 | } |
---|
1635 | |
---|
1636 | gpointer |
---|
1637 | g_object_get_data (GObject *object, |
---|
1638 | const gchar *key) |
---|
1639 | { |
---|
1640 | GQuark quark; |
---|
1641 | |
---|
1642 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
---|
1643 | g_return_val_if_fail (key != NULL, NULL); |
---|
1644 | |
---|
1645 | quark = g_quark_try_string (key); |
---|
1646 | |
---|
1647 | return quark ? g_datalist_id_get_data (&object->qdata, quark) : NULL; |
---|
1648 | } |
---|
1649 | |
---|
1650 | void |
---|
1651 | g_object_set_data (GObject *object, |
---|
1652 | const gchar *key, |
---|
1653 | gpointer data) |
---|
1654 | { |
---|
1655 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1656 | g_return_if_fail (key != NULL); |
---|
1657 | |
---|
1658 | g_datalist_id_set_data (&object->qdata, g_quark_from_string (key), data); |
---|
1659 | } |
---|
1660 | |
---|
1661 | void |
---|
1662 | g_object_set_data_full (GObject *object, |
---|
1663 | const gchar *key, |
---|
1664 | gpointer data, |
---|
1665 | GDestroyNotify destroy) |
---|
1666 | { |
---|
1667 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1668 | g_return_if_fail (key != NULL); |
---|
1669 | |
---|
1670 | g_datalist_id_set_data_full (&object->qdata, g_quark_from_string (key), data, |
---|
1671 | data ? destroy : (GDestroyNotify) NULL); |
---|
1672 | } |
---|
1673 | |
---|
1674 | gpointer |
---|
1675 | g_object_steal_data (GObject *object, |
---|
1676 | const gchar *key) |
---|
1677 | { |
---|
1678 | GQuark quark; |
---|
1679 | |
---|
1680 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
---|
1681 | g_return_val_if_fail (key != NULL, NULL); |
---|
1682 | |
---|
1683 | quark = g_quark_try_string (key); |
---|
1684 | |
---|
1685 | return quark ? g_datalist_id_remove_no_notify (&object->qdata, quark) : NULL; |
---|
1686 | } |
---|
1687 | |
---|
1688 | static void |
---|
1689 | g_value_object_init (GValue *value) |
---|
1690 | { |
---|
1691 | value->data[0].v_pointer = NULL; |
---|
1692 | } |
---|
1693 | |
---|
1694 | static void |
---|
1695 | g_value_object_free_value (GValue *value) |
---|
1696 | { |
---|
1697 | if (value->data[0].v_pointer) |
---|
1698 | g_object_unref (value->data[0].v_pointer); |
---|
1699 | } |
---|
1700 | |
---|
1701 | static void |
---|
1702 | g_value_object_copy_value (const GValue *src_value, |
---|
1703 | GValue *dest_value) |
---|
1704 | { |
---|
1705 | if (src_value->data[0].v_pointer) |
---|
1706 | dest_value->data[0].v_pointer = g_object_ref (src_value->data[0].v_pointer); |
---|
1707 | else |
---|
1708 | dest_value->data[0].v_pointer = NULL; |
---|
1709 | } |
---|
1710 | |
---|
1711 | static void |
---|
1712 | g_value_object_transform_value (const GValue *src_value, |
---|
1713 | GValue *dest_value) |
---|
1714 | { |
---|
1715 | if (src_value->data[0].v_pointer && g_type_is_a (G_OBJECT_TYPE (src_value->data[0].v_pointer), G_VALUE_TYPE (dest_value))) |
---|
1716 | dest_value->data[0].v_pointer = g_object_ref (src_value->data[0].v_pointer); |
---|
1717 | else |
---|
1718 | dest_value->data[0].v_pointer = NULL; |
---|
1719 | } |
---|
1720 | |
---|
1721 | static gpointer |
---|
1722 | g_value_object_peek_pointer (const GValue *value) |
---|
1723 | { |
---|
1724 | return value->data[0].v_pointer; |
---|
1725 | } |
---|
1726 | |
---|
1727 | static gchar* |
---|
1728 | g_value_object_collect_value (GValue *value, |
---|
1729 | guint n_collect_values, |
---|
1730 | GTypeCValue *collect_values, |
---|
1731 | guint collect_flags) |
---|
1732 | { |
---|
1733 | if (collect_values[0].v_pointer) |
---|
1734 | { |
---|
1735 | GObject *object = collect_values[0].v_pointer; |
---|
1736 | |
---|
1737 | if (object->g_type_instance.g_class == NULL) |
---|
1738 | return g_strconcat ("invalid unclassed object pointer for value type `", |
---|
1739 | G_VALUE_TYPE_NAME (value), |
---|
1740 | "'", |
---|
1741 | NULL); |
---|
1742 | else if (!g_value_type_compatible (G_OBJECT_TYPE (object), G_VALUE_TYPE (value))) |
---|
1743 | return g_strconcat ("invalid object type `", |
---|
1744 | G_OBJECT_TYPE_NAME (object), |
---|
1745 | "' for value type `", |
---|
1746 | G_VALUE_TYPE_NAME (value), |
---|
1747 | "'", |
---|
1748 | NULL); |
---|
1749 | /* never honour G_VALUE_NOCOPY_CONTENTS for ref-counted types */ |
---|
1750 | value->data[0].v_pointer = g_object_ref (object); |
---|
1751 | } |
---|
1752 | else |
---|
1753 | value->data[0].v_pointer = NULL; |
---|
1754 | |
---|
1755 | return NULL; |
---|
1756 | } |
---|
1757 | |
---|
1758 | static gchar* |
---|
1759 | g_value_object_lcopy_value (const GValue *value, |
---|
1760 | guint n_collect_values, |
---|
1761 | GTypeCValue *collect_values, |
---|
1762 | guint collect_flags) |
---|
1763 | { |
---|
1764 | GObject **object_p = collect_values[0].v_pointer; |
---|
1765 | |
---|
1766 | if (!object_p) |
---|
1767 | return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); |
---|
1768 | |
---|
1769 | if (!value->data[0].v_pointer) |
---|
1770 | *object_p = NULL; |
---|
1771 | else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) |
---|
1772 | *object_p = value->data[0].v_pointer; |
---|
1773 | else |
---|
1774 | *object_p = g_object_ref (value->data[0].v_pointer); |
---|
1775 | |
---|
1776 | return NULL; |
---|
1777 | } |
---|
1778 | |
---|
1779 | void |
---|
1780 | g_value_set_object (GValue *value, |
---|
1781 | gpointer v_object) |
---|
1782 | { |
---|
1783 | GObject *old; |
---|
1784 | |
---|
1785 | g_return_if_fail (G_VALUE_HOLDS_OBJECT (value)); |
---|
1786 | |
---|
1787 | old = value->data[0].v_pointer; |
---|
1788 | |
---|
1789 | if (v_object) |
---|
1790 | { |
---|
1791 | g_return_if_fail (G_IS_OBJECT (v_object)); |
---|
1792 | g_return_if_fail (g_value_type_compatible (G_OBJECT_TYPE (v_object), G_VALUE_TYPE (value))); |
---|
1793 | |
---|
1794 | value->data[0].v_pointer = v_object; |
---|
1795 | g_object_ref (value->data[0].v_pointer); |
---|
1796 | } |
---|
1797 | else |
---|
1798 | value->data[0].v_pointer = NULL; |
---|
1799 | |
---|
1800 | if (old) |
---|
1801 | g_object_unref (old); |
---|
1802 | } |
---|
1803 | |
---|
1804 | void |
---|
1805 | g_value_set_object_take_ownership (GValue *value, |
---|
1806 | gpointer v_object) |
---|
1807 | { |
---|
1808 | g_value_take_object (value, v_object); |
---|
1809 | } |
---|
1810 | |
---|
1811 | void |
---|
1812 | g_value_take_object (GValue *value, |
---|
1813 | gpointer v_object) |
---|
1814 | { |
---|
1815 | g_return_if_fail (G_VALUE_HOLDS_OBJECT (value)); |
---|
1816 | |
---|
1817 | if (value->data[0].v_pointer) |
---|
1818 | { |
---|
1819 | g_object_unref (value->data[0].v_pointer); |
---|
1820 | value->data[0].v_pointer = NULL; |
---|
1821 | } |
---|
1822 | |
---|
1823 | if (v_object) |
---|
1824 | { |
---|
1825 | g_return_if_fail (G_IS_OBJECT (v_object)); |
---|
1826 | g_return_if_fail (g_value_type_compatible (G_OBJECT_TYPE (v_object), G_VALUE_TYPE (value))); |
---|
1827 | |
---|
1828 | value->data[0].v_pointer = v_object; /* we take over the reference count */ |
---|
1829 | } |
---|
1830 | } |
---|
1831 | |
---|
1832 | gpointer |
---|
1833 | g_value_get_object (const GValue *value) |
---|
1834 | { |
---|
1835 | g_return_val_if_fail (G_VALUE_HOLDS_OBJECT (value), NULL); |
---|
1836 | |
---|
1837 | return value->data[0].v_pointer; |
---|
1838 | } |
---|
1839 | |
---|
1840 | GObject* |
---|
1841 | g_value_dup_object (const GValue *value) |
---|
1842 | { |
---|
1843 | g_return_val_if_fail (G_VALUE_HOLDS_OBJECT (value), NULL); |
---|
1844 | |
---|
1845 | return value->data[0].v_pointer ? g_object_ref (value->data[0].v_pointer) : NULL; |
---|
1846 | } |
---|
1847 | |
---|
1848 | gulong |
---|
1849 | g_signal_connect_object (gpointer instance, |
---|
1850 | const gchar *detailed_signal, |
---|
1851 | GCallback c_handler, |
---|
1852 | gpointer gobject, |
---|
1853 | GConnectFlags connect_flags) |
---|
1854 | { |
---|
1855 | g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0); |
---|
1856 | g_return_val_if_fail (detailed_signal != NULL, 0); |
---|
1857 | g_return_val_if_fail (c_handler != NULL, 0); |
---|
1858 | |
---|
1859 | if (gobject) |
---|
1860 | { |
---|
1861 | GClosure *closure; |
---|
1862 | |
---|
1863 | g_return_val_if_fail (G_IS_OBJECT (gobject), 0); |
---|
1864 | |
---|
1865 | closure = ((connect_flags & G_CONNECT_SWAPPED) ? g_cclosure_new_object_swap : g_cclosure_new_object) (c_handler, gobject); |
---|
1866 | |
---|
1867 | return g_signal_connect_closure (instance, detailed_signal, closure, connect_flags & G_CONNECT_AFTER); |
---|
1868 | } |
---|
1869 | else |
---|
1870 | return g_signal_connect_data (instance, detailed_signal, c_handler, NULL, NULL, connect_flags); |
---|
1871 | } |
---|
1872 | |
---|
1873 | typedef struct { |
---|
1874 | GObject *object; |
---|
1875 | guint n_closures; |
---|
1876 | GClosure *closures[1]; /* flexible array */ |
---|
1877 | } CArray; |
---|
1878 | /* don't change this structure without supplying an accessor for |
---|
1879 | * watched closures, e.g.: |
---|
1880 | * GSList* g_object_list_watched_closures (GObject *object) |
---|
1881 | * { |
---|
1882 | * CArray *carray; |
---|
1883 | * g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
---|
1884 | * carray = g_object_get_data (object, "GObject-closure-array"); |
---|
1885 | * if (carray) |
---|
1886 | * { |
---|
1887 | * GSList *slist = NULL; |
---|
1888 | * guint i; |
---|
1889 | * for (i = 0; i < carray->n_closures; i++) |
---|
1890 | * slist = g_slist_prepend (slist, carray->closures[i]); |
---|
1891 | * return slist; |
---|
1892 | * } |
---|
1893 | * return NULL; |
---|
1894 | * } |
---|
1895 | */ |
---|
1896 | |
---|
1897 | static void |
---|
1898 | object_remove_closure (gpointer data, |
---|
1899 | GClosure *closure) |
---|
1900 | { |
---|
1901 | GObject *object = data; |
---|
1902 | CArray *carray = g_object_get_qdata (object, quark_closure_array); |
---|
1903 | guint i; |
---|
1904 | |
---|
1905 | for (i = 0; i < carray->n_closures; i++) |
---|
1906 | if (carray->closures[i] == closure) |
---|
1907 | { |
---|
1908 | carray->n_closures--; |
---|
1909 | if (i < carray->n_closures) |
---|
1910 | carray->closures[i] = carray->closures[carray->n_closures]; |
---|
1911 | return; |
---|
1912 | } |
---|
1913 | g_assert_not_reached (); |
---|
1914 | } |
---|
1915 | |
---|
1916 | static void |
---|
1917 | destroy_closure_array (gpointer data) |
---|
1918 | { |
---|
1919 | CArray *carray = data; |
---|
1920 | GObject *object = carray->object; |
---|
1921 | guint i, n = carray->n_closures; |
---|
1922 | |
---|
1923 | for (i = 0; i < n; i++) |
---|
1924 | { |
---|
1925 | GClosure *closure = carray->closures[i]; |
---|
1926 | |
---|
1927 | /* removing object_remove_closure() upfront is probably faster than |
---|
1928 | * letting it fiddle with quark_closure_array which is empty anyways |
---|
1929 | */ |
---|
1930 | g_closure_remove_invalidate_notifier (closure, object, object_remove_closure); |
---|
1931 | g_closure_invalidate (closure); |
---|
1932 | } |
---|
1933 | g_free (carray); |
---|
1934 | } |
---|
1935 | |
---|
1936 | void |
---|
1937 | g_object_watch_closure (GObject *object, |
---|
1938 | GClosure *closure) |
---|
1939 | { |
---|
1940 | CArray *carray; |
---|
1941 | guint i; |
---|
1942 | |
---|
1943 | g_return_if_fail (G_IS_OBJECT (object)); |
---|
1944 | g_return_if_fail (closure != NULL); |
---|
1945 | g_return_if_fail (closure->is_invalid == FALSE); |
---|
1946 | g_return_if_fail (closure->in_marshal == FALSE); |
---|
1947 | g_return_if_fail (object->ref_count > 0); /* this doesn't work on finalizing objects */ |
---|
1948 | |
---|
1949 | g_closure_add_invalidate_notifier (closure, object, object_remove_closure); |
---|
1950 | g_closure_add_marshal_guards (closure, |
---|
1951 | object, (GClosureNotify) g_object_ref, |
---|
1952 | object, (GClosureNotify) g_object_unref); |
---|
1953 | carray = g_datalist_id_remove_no_notify (&object->qdata, quark_closure_array); |
---|
1954 | if (!carray) |
---|
1955 | { |
---|
1956 | carray = g_renew (CArray, NULL, 1); |
---|
1957 | carray->object = object; |
---|
1958 | carray->n_closures = 1; |
---|
1959 | i = 0; |
---|
1960 | } |
---|
1961 | else |
---|
1962 | { |
---|
1963 | i = carray->n_closures++; |
---|
1964 | carray = g_realloc (carray, sizeof (*carray) + sizeof (carray->closures[0]) * i); |
---|
1965 | } |
---|
1966 | carray->closures[i] = closure; |
---|
1967 | g_datalist_id_set_data_full (&object->qdata, quark_closure_array, carray, destroy_closure_array); |
---|
1968 | } |
---|
1969 | |
---|
1970 | GClosure* |
---|
1971 | g_closure_new_object (guint sizeof_closure, |
---|
1972 | GObject *object) |
---|
1973 | { |
---|
1974 | GClosure *closure; |
---|
1975 | |
---|
1976 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
---|
1977 | g_return_val_if_fail (object->ref_count > 0, NULL); /* this doesn't work on finalizing objects */ |
---|
1978 | |
---|
1979 | closure = g_closure_new_simple (sizeof_closure, object); |
---|
1980 | g_object_watch_closure (object, closure); |
---|
1981 | |
---|
1982 | return closure; |
---|
1983 | } |
---|
1984 | |
---|
1985 | GClosure* |
---|
1986 | g_cclosure_new_object (GCallback callback_func, |
---|
1987 | GObject *object) |
---|
1988 | { |
---|
1989 | GClosure *closure; |
---|
1990 | |
---|
1991 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
---|
1992 | g_return_val_if_fail (object->ref_count > 0, NULL); /* this doesn't work on finalizing objects */ |
---|
1993 | g_return_val_if_fail (callback_func != NULL, NULL); |
---|
1994 | |
---|
1995 | closure = g_cclosure_new (callback_func, object, NULL); |
---|
1996 | g_object_watch_closure (object, closure); |
---|
1997 | |
---|
1998 | return closure; |
---|
1999 | } |
---|
2000 | |
---|
2001 | GClosure* |
---|
2002 | g_cclosure_new_object_swap (GCallback callback_func, |
---|
2003 | GObject *object) |
---|
2004 | { |
---|
2005 | GClosure *closure; |
---|
2006 | |
---|
2007 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
---|
2008 | g_return_val_if_fail (object->ref_count > 0, NULL); /* this doesn't work on finalizing objects */ |
---|
2009 | g_return_val_if_fail (callback_func != NULL, NULL); |
---|
2010 | |
---|
2011 | closure = g_cclosure_new_swap (callback_func, object, NULL); |
---|
2012 | g_object_watch_closure (object, closure); |
---|
2013 | |
---|
2014 | return closure; |
---|
2015 | } |
---|