nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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, see <http://www.gnu.org/licenses/>. |
||
16 | */ |
||
17 | |||
18 | /* |
||
19 | * MT safe with regards to reference counting. |
||
20 | */ |
||
21 | |||
22 | #include "config.h" |
||
23 | |||
24 | #include <string.h> |
||
25 | #include <signal.h> |
||
26 | |||
27 | #include "gobject.h" |
||
28 | #include "gtype-private.h" |
||
29 | #include "gvaluecollector.h" |
||
30 | #include "gsignal.h" |
||
31 | #include "gparamspecs.h" |
||
32 | #include "gvaluetypes.h" |
||
33 | #include "gobject_trace.h" |
||
34 | #include "gconstructor.h" |
||
35 | |||
36 | /** |
||
37 | * SECTION:objects |
||
38 | * @title: GObject |
||
39 | * @short_description: The base object type |
||
40 | * @see_also: #GParamSpecObject, g_param_spec_object() |
||
41 | * |
||
42 | * GObject is the fundamental type providing the common attributes and |
||
43 | * methods for all object types in GTK+, Pango and other libraries |
||
44 | * based on GObject. The GObject class provides methods for object |
||
45 | * construction and destruction, property access methods, and signal |
||
46 | * support. Signals are described in detail [here][gobject-Signals]. |
||
47 | * |
||
48 | * For a tutorial on implementing a new GObject class, see [How to define and |
||
49 | * implement a new GObject][howto-gobject]. For a list of naming conventions for |
||
50 | * GObjects and their methods, see the [GType conventions][gtype-conventions]. |
||
51 | * For the high-level concepts behind GObject, read [Instantiable classed types: |
||
52 | * Objects][gtype-instantiable-classed]. |
||
53 | * |
||
54 | * ## Floating references # {#floating-ref} |
||
55 | * |
||
56 | * GInitiallyUnowned is derived from GObject. The only difference between |
||
57 | * the two is that the initial reference of a GInitiallyUnowned is flagged |
||
58 | * as a "floating" reference. This means that it is not specifically |
||
59 | * claimed to be "owned" by any code portion. The main motivation for |
||
60 | * providing floating references is C convenience. In particular, it |
||
61 | * allows code to be written as: |
||
62 | * |[<!-- language="C" --> |
||
63 | * container = create_container (); |
||
64 | * container_add_child (container, create_child()); |
||
65 | * ]| |
||
66 | * If container_add_child() calls g_object_ref_sink() on the passed-in child, |
||
67 | * no reference of the newly created child is leaked. Without floating |
||
68 | * references, container_add_child() can only g_object_ref() the new child, |
||
69 | * so to implement this code without reference leaks, it would have to be |
||
70 | * written as: |
||
71 | * |[<!-- language="C" --> |
||
72 | * Child *child; |
||
73 | * container = create_container (); |
||
74 | * child = create_child (); |
||
75 | * container_add_child (container, child); |
||
76 | * g_object_unref (child); |
||
77 | * ]| |
||
78 | * The floating reference can be converted into an ordinary reference by |
||
79 | * calling g_object_ref_sink(). For already sunken objects (objects that |
||
80 | * don't have a floating reference anymore), g_object_ref_sink() is equivalent |
||
81 | * to g_object_ref() and returns a new reference. |
||
82 | * |
||
83 | * Since floating references are useful almost exclusively for C convenience, |
||
84 | * language bindings that provide automated reference and memory ownership |
||
85 | * maintenance (such as smart pointers or garbage collection) should not |
||
86 | * expose floating references in their API. |
||
87 | * |
||
88 | * Some object implementations may need to save an objects floating state |
||
89 | * across certain code portions (an example is #GtkMenu), to achieve this, |
||
90 | * the following sequence can be used: |
||
91 | * |
||
92 | * |[<!-- language="C" --> |
||
93 | * // save floating state |
||
94 | * gboolean was_floating = g_object_is_floating (object); |
||
95 | * g_object_ref_sink (object); |
||
96 | * // protected code portion |
||
97 | * |
||
98 | * ... |
||
99 | * |
||
100 | * // restore floating state |
||
101 | * if (was_floating) |
||
102 | * g_object_force_floating (object); |
||
103 | * else |
||
104 | * g_object_unref (object); // release previously acquired reference |
||
105 | * ]| |
||
106 | */ |
||
107 | |||
108 | |||
109 | /* --- macros --- */ |
||
110 | #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id) |
||
111 | #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id)) |
||
112 | |||
113 | #define OBJECT_HAS_TOGGLE_REF_FLAG 0x1 |
||
114 | #define OBJECT_HAS_TOGGLE_REF(object) \ |
||
115 | ((g_datalist_get_flags (&(object)->qdata) & OBJECT_HAS_TOGGLE_REF_FLAG) != 0) |
||
116 | #define OBJECT_FLOATING_FLAG 0x2 |
||
117 | |||
118 | #define CLASS_HAS_PROPS_FLAG 0x1 |
||
119 | #define CLASS_HAS_PROPS(class) \ |
||
120 | ((class)->flags & CLASS_HAS_PROPS_FLAG) |
||
121 | #define CLASS_HAS_CUSTOM_CONSTRUCTOR(class) \ |
||
122 | ((class)->constructor != g_object_constructor) |
||
123 | #define CLASS_HAS_CUSTOM_CONSTRUCTED(class) \ |
||
124 | ((class)->constructed != g_object_constructed) |
||
125 | |||
126 | #define CLASS_HAS_DERIVED_CLASS_FLAG 0x2 |
||
127 | #define CLASS_HAS_DERIVED_CLASS(class) \ |
||
128 | ((class)->flags & CLASS_HAS_DERIVED_CLASS_FLAG) |
||
129 | |||
130 | /* --- signals --- */ |
||
131 | enum { |
||
132 | NOTIFY, |
||
133 | LAST_SIGNAL |
||
134 | }; |
||
135 | |||
136 | |||
137 | /* --- properties --- */ |
||
138 | enum { |
||
139 | PROP_NONE |
||
140 | }; |
||
141 | |||
142 | |||
143 | /* --- prototypes --- */ |
||
144 | static void g_object_base_class_init (GObjectClass *class); |
||
145 | static void g_object_base_class_finalize (GObjectClass *class); |
||
146 | static void g_object_do_class_init (GObjectClass *class); |
||
147 | static void g_object_init (GObject *object, |
||
148 | GObjectClass *class); |
||
149 | static GObject* g_object_constructor (GType type, |
||
150 | guint n_construct_properties, |
||
151 | GObjectConstructParam *construct_params); |
||
152 | static void g_object_constructed (GObject *object); |
||
153 | static void g_object_real_dispose (GObject *object); |
||
154 | static void g_object_finalize (GObject *object); |
||
155 | static void g_object_do_set_property (GObject *object, |
||
156 | guint property_id, |
||
157 | const GValue *value, |
||
158 | GParamSpec *pspec); |
||
159 | static void g_object_do_get_property (GObject *object, |
||
160 | guint property_id, |
||
161 | GValue *value, |
||
162 | GParamSpec *pspec); |
||
163 | static void g_value_object_init (GValue *value); |
||
164 | static void g_value_object_free_value (GValue *value); |
||
165 | static void g_value_object_copy_value (const GValue *src_value, |
||
166 | GValue *dest_value); |
||
167 | static void g_value_object_transform_value (const GValue *src_value, |
||
168 | GValue *dest_value); |
||
169 | static gpointer g_value_object_peek_pointer (const GValue *value); |
||
170 | static gchar* g_value_object_collect_value (GValue *value, |
||
171 | guint n_collect_values, |
||
172 | GTypeCValue *collect_values, |
||
173 | guint collect_flags); |
||
174 | static gchar* g_value_object_lcopy_value (const GValue *value, |
||
175 | guint n_collect_values, |
||
176 | GTypeCValue *collect_values, |
||
177 | guint collect_flags); |
||
178 | static void g_object_dispatch_properties_changed (GObject *object, |
||
179 | guint n_pspecs, |
||
180 | GParamSpec **pspecs); |
||
181 | static guint object_floating_flag_handler (GObject *object, |
||
182 | gint job); |
||
183 | |||
184 | static void object_interface_check_properties (gpointer check_data, |
||
185 | gpointer g_iface); |
||
186 | |||
187 | /* --- typedefs --- */ |
||
188 | typedef struct _GObjectNotifyQueue GObjectNotifyQueue; |
||
189 | |||
190 | struct _GObjectNotifyQueue |
||
191 | { |
||
192 | GSList *pspecs; |
||
193 | guint16 n_pspecs; |
||
194 | guint16 freeze_count; |
||
195 | }; |
||
196 | |||
197 | /* --- variables --- */ |
||
198 | G_LOCK_DEFINE_STATIC (closure_array_mutex); |
||
199 | G_LOCK_DEFINE_STATIC (weak_refs_mutex); |
||
200 | G_LOCK_DEFINE_STATIC (toggle_refs_mutex); |
||
201 | static GQuark quark_closure_array = 0; |
||
202 | static GQuark quark_weak_refs = 0; |
||
203 | static GQuark quark_toggle_refs = 0; |
||
204 | static GQuark quark_notify_queue; |
||
205 | static GQuark quark_in_construction; |
||
206 | static GParamSpecPool *pspec_pool = NULL; |
||
207 | static gulong gobject_signals[LAST_SIGNAL] = { 0, }; |
||
208 | static guint (*floating_flag_handler) (GObject*, gint) = object_floating_flag_handler; |
||
209 | /* qdata pointing to GSList<GWeakRef *>, protected by weak_locations_lock */ |
||
210 | static GQuark quark_weak_locations = 0; |
||
211 | static GRWLock weak_locations_lock; |
||
212 | |||
213 | G_LOCK_DEFINE_STATIC(notify_lock); |
||
214 | |||
215 | /* --- functions --- */ |
||
216 | static void |
||
217 | g_object_notify_queue_free (gpointer data) |
||
218 | { |
||
219 | GObjectNotifyQueue *nqueue = data; |
||
220 | |||
221 | g_slist_free (nqueue->pspecs); |
||
222 | g_slice_free (GObjectNotifyQueue, nqueue); |
||
223 | } |
||
224 | |||
225 | static GObjectNotifyQueue* |
||
226 | g_object_notify_queue_freeze (GObject *object, |
||
227 | gboolean conditional) |
||
228 | { |
||
229 | GObjectNotifyQueue *nqueue; |
||
230 | |||
231 | G_LOCK(notify_lock); |
||
232 | nqueue = g_datalist_id_get_data (&object->qdata, quark_notify_queue); |
||
233 | if (!nqueue) |
||
234 | { |
||
235 | if (conditional) |
||
236 | { |
||
237 | G_UNLOCK(notify_lock); |
||
238 | return NULL; |
||
239 | } |
||
240 | |||
241 | nqueue = g_slice_new0 (GObjectNotifyQueue); |
||
242 | g_datalist_id_set_data_full (&object->qdata, quark_notify_queue, |
||
243 | nqueue, g_object_notify_queue_free); |
||
244 | } |
||
245 | |||
246 | if (nqueue->freeze_count >= 65535) |
||
247 | g_critical("Free queue for %s (%p) is larger than 65535," |
||
248 | " called g_object_freeze_notify() too often." |
||
249 | " Forgot to call g_object_thaw_notify() or infinite loop", |
||
250 | G_OBJECT_TYPE_NAME (object), object); |
||
251 | else |
||
252 | nqueue->freeze_count++; |
||
253 | G_UNLOCK(notify_lock); |
||
254 | |||
255 | return nqueue; |
||
256 | } |
||
257 | |||
258 | static void |
||
259 | g_object_notify_queue_thaw (GObject *object, |
||
260 | GObjectNotifyQueue *nqueue) |
||
261 | { |
||
262 | GParamSpec *pspecs_mem[16], **pspecs, **free_me = NULL; |
||
263 | GSList *slist; |
||
264 | guint n_pspecs = 0; |
||
265 | |||
266 | g_return_if_fail (nqueue->freeze_count > 0); |
||
267 | g_return_if_fail (g_atomic_int_get(&object->ref_count) > 0); |
||
268 | |||
269 | G_LOCK(notify_lock); |
||
270 | |||
271 | /* Just make sure we never get into some nasty race condition */ |
||
272 | if (G_UNLIKELY(nqueue->freeze_count == 0)) { |
||
273 | G_UNLOCK(notify_lock); |
||
274 | g_warning ("%s: property-changed notification for %s(%p) is not frozen", |
||
275 | G_STRFUNC, G_OBJECT_TYPE_NAME (object), object); |
||
276 | return; |
||
277 | } |
||
278 | |||
279 | nqueue->freeze_count--; |
||
280 | if (nqueue->freeze_count) { |
||
281 | G_UNLOCK(notify_lock); |
||
282 | return; |
||
283 | } |
||
284 | |||
285 | pspecs = nqueue->n_pspecs > 16 ? free_me = g_new (GParamSpec*, nqueue->n_pspecs) : pspecs_mem; |
||
286 | |||
287 | for (slist = nqueue->pspecs; slist; slist = slist->next) |
||
288 | { |
||
289 | pspecs[n_pspecs++] = slist->data; |
||
290 | } |
||
291 | g_datalist_id_set_data (&object->qdata, quark_notify_queue, NULL); |
||
292 | |||
293 | G_UNLOCK(notify_lock); |
||
294 | |||
295 | if (n_pspecs) |
||
296 | G_OBJECT_GET_CLASS (object)->dispatch_properties_changed (object, n_pspecs, pspecs); |
||
297 | g_free (free_me); |
||
298 | } |
||
299 | |||
300 | static void |
||
301 | g_object_notify_queue_add (GObject *object, |
||
302 | GObjectNotifyQueue *nqueue, |
||
303 | GParamSpec *pspec) |
||
304 | { |
||
305 | G_LOCK(notify_lock); |
||
306 | |||
307 | g_assert (nqueue->n_pspecs < 65535); |
||
308 | |||
309 | if (g_slist_find (nqueue->pspecs, pspec) == NULL) |
||
310 | { |
||
311 | nqueue->pspecs = g_slist_prepend (nqueue->pspecs, pspec); |
||
312 | nqueue->n_pspecs++; |
||
313 | } |
||
314 | |||
315 | G_UNLOCK(notify_lock); |
||
316 | } |
||
317 | |||
318 | #ifdef G_ENABLE_DEBUG |
||
319 | #define IF_DEBUG(debug_type) if (_g_type_debug_flags & G_TYPE_DEBUG_ ## debug_type) |
||
320 | G_LOCK_DEFINE_STATIC (debug_objects); |
||
321 | static guint debug_objects_count = 0; |
||
322 | static GHashTable *debug_objects_ht = NULL; |
||
323 | |||
324 | static void |
||
325 | debug_objects_foreach (gpointer key, |
||
326 | gpointer value, |
||
327 | gpointer user_data) |
||
328 | { |
||
329 | GObject *object = value; |
||
330 | |||
331 | g_message ("[%p] stale %s\tref_count=%u", |
||
332 | object, |
||
333 | G_OBJECT_TYPE_NAME (object), |
||
334 | object->ref_count); |
||
335 | } |
||
336 | |||
337 | #ifdef G_HAS_CONSTRUCTORS |
||
338 | #ifdef G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA |
||
339 | #pragma G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(debug_objects_atexit) |
||
340 | #endif |
||
341 | G_DEFINE_DESTRUCTOR(debug_objects_atexit) |
||
342 | #endif /* G_HAS_CONSTRUCTORS */ |
||
343 | |||
344 | static void |
||
345 | debug_objects_atexit (void) |
||
346 | { |
||
347 | IF_DEBUG (OBJECTS) |
||
348 | { |
||
349 | G_LOCK (debug_objects); |
||
350 | g_message ("stale GObjects: %u", debug_objects_count); |
||
351 | g_hash_table_foreach (debug_objects_ht, debug_objects_foreach, NULL); |
||
352 | G_UNLOCK (debug_objects); |
||
353 | } |
||
354 | } |
||
355 | #endif /* G_ENABLE_DEBUG */ |
||
356 | |||
357 | void |
||
358 | _g_object_type_init (void) |
||
359 | { |
||
360 | static gboolean initialized = FALSE; |
||
361 | static const GTypeFundamentalInfo finfo = { |
||
362 | G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE, |
||
363 | }; |
||
364 | GTypeInfo info = { |
||
365 | sizeof (GObjectClass), |
||
366 | (GBaseInitFunc) g_object_base_class_init, |
||
367 | (GBaseFinalizeFunc) g_object_base_class_finalize, |
||
368 | (GClassInitFunc) g_object_do_class_init, |
||
369 | NULL /* class_destroy */, |
||
370 | NULL /* class_data */, |
||
371 | sizeof (GObject), |
||
372 | |||
373 | (GInstanceInitFunc) g_object_init, |
||
374 | NULL, /* value_table */ |
||
375 | }; |
||
376 | static const GTypeValueTable value_table = { |
||
377 | g_value_object_init, /* value_init */ |
||
378 | g_value_object_free_value, /* value_free */ |
||
379 | g_value_object_copy_value, /* value_copy */ |
||
380 | g_value_object_peek_pointer, /* value_peek_pointer */ |
||
381 | "p", /* collect_format */ |
||
382 | g_value_object_collect_value, /* collect_value */ |
||
383 | "p", /* lcopy_format */ |
||
384 | g_value_object_lcopy_value, /* lcopy_value */ |
||
385 | }; |
||
386 | GType type; |
||
387 | |||
388 | g_return_if_fail (initialized == FALSE); |
||
389 | initialized = TRUE; |
||
390 | |||
391 | /* G_TYPE_OBJECT |
||
392 | */ |
||
393 | info.value_table = &value_table; |
||
394 | type = g_type_register_fundamental (G_TYPE_OBJECT, g_intern_static_string ("GObject"), &info, &finfo, 0); |
||
395 | g_assert (type == G_TYPE_OBJECT); |
||
396 | g_value_register_transform_func (G_TYPE_OBJECT, G_TYPE_OBJECT, g_value_object_transform_value); |
||
397 | |||
398 | #ifdef G_ENABLE_DEBUG |
||
399 | IF_DEBUG (OBJECTS) |
||
400 | { |
||
401 | debug_objects_ht = g_hash_table_new (g_direct_hash, NULL); |
||
402 | #ifndef G_HAS_CONSTRUCTORS |
||
403 | g_atexit (debug_objects_atexit); |
||
404 | #endif /* G_HAS_CONSTRUCTORS */ |
||
405 | } |
||
406 | #endif /* G_ENABLE_DEBUG */ |
||
407 | } |
||
408 | |||
409 | static void |
||
410 | g_object_base_class_init (GObjectClass *class) |
||
411 | { |
||
412 | GObjectClass *pclass = g_type_class_peek_parent (class); |
||
413 | |||
414 | /* Don't inherit HAS_DERIVED_CLASS flag from parent class */ |
||
415 | class->flags &= ~CLASS_HAS_DERIVED_CLASS_FLAG; |
||
416 | |||
417 | if (pclass) |
||
418 | pclass->flags |= CLASS_HAS_DERIVED_CLASS_FLAG; |
||
419 | |||
420 | /* reset instance specific fields and methods that don't get inherited */ |
||
421 | class->construct_properties = pclass ? g_slist_copy (pclass->construct_properties) : NULL; |
||
422 | class->get_property = NULL; |
||
423 | class->set_property = NULL; |
||
424 | } |
||
425 | |||
426 | static void |
||
427 | g_object_base_class_finalize (GObjectClass *class) |
||
428 | { |
||
429 | GList *list, *node; |
||
430 | |||
431 | _g_signals_destroy (G_OBJECT_CLASS_TYPE (class)); |
||
432 | |||
433 | g_slist_free (class->construct_properties); |
||
434 | class->construct_properties = NULL; |
||
435 | list = g_param_spec_pool_list_owned (pspec_pool, G_OBJECT_CLASS_TYPE (class)); |
||
436 | for (node = list; node; node = node->next) |
||
437 | { |
||
438 | GParamSpec *pspec = node->data; |
||
439 | |||
440 | g_param_spec_pool_remove (pspec_pool, pspec); |
||
441 | PARAM_SPEC_SET_PARAM_ID (pspec, 0); |
||
442 | g_param_spec_unref (pspec); |
||
443 | } |
||
444 | g_list_free (list); |
||
445 | } |
||
446 | |||
447 | static void |
||
448 | g_object_do_class_init (GObjectClass *class) |
||
449 | { |
||
450 | /* read the comment about typedef struct CArray; on why not to change this quark */ |
||
451 | quark_closure_array = g_quark_from_static_string ("GObject-closure-array"); |
||
452 | |||
453 | quark_weak_refs = g_quark_from_static_string ("GObject-weak-references"); |
||
454 | quark_weak_locations = g_quark_from_static_string ("GObject-weak-locations"); |
||
455 | quark_toggle_refs = g_quark_from_static_string ("GObject-toggle-references"); |
||
456 | quark_notify_queue = g_quark_from_static_string ("GObject-notify-queue"); |
||
457 | quark_in_construction = g_quark_from_static_string ("GObject-in-construction"); |
||
458 | pspec_pool = g_param_spec_pool_new (TRUE); |
||
459 | |||
460 | class->constructor = g_object_constructor; |
||
461 | class->constructed = g_object_constructed; |
||
462 | class->set_property = g_object_do_set_property; |
||
463 | class->get_property = g_object_do_get_property; |
||
464 | class->dispose = g_object_real_dispose; |
||
465 | class->finalize = g_object_finalize; |
||
466 | class->dispatch_properties_changed = g_object_dispatch_properties_changed; |
||
467 | class->notify = NULL; |
||
468 | |||
469 | /** |
||
470 | * GObject::notify: |
||
471 | * @gobject: the object which received the signal. |
||
472 | * @pspec: the #GParamSpec of the property which changed. |
||
473 | * |
||
474 | * The notify signal is emitted on an object when one of its |
||
475 | * properties has been changed. Note that getting this signal |
||
476 | * doesn't guarantee that the value of the property has actually |
||
477 | * changed, it may also be emitted when the setter for the property |
||
478 | * is called to reinstate the previous value. |
||
479 | * |
||
480 | * This signal is typically used to obtain change notification for a |
||
481 | * single property, by specifying the property name as a detail in the |
||
482 | * g_signal_connect() call, like this: |
||
483 | * |[<!-- language="C" --> |
||
484 | * g_signal_connect (text_view->buffer, "notify::paste-target-list", |
||
485 | * G_CALLBACK (gtk_text_view_target_list_notify), |
||
486 | * text_view) |
||
487 | * ]| |
||
488 | * It is important to note that you must use |
||
489 | * [canonical][canonical-parameter-name] parameter names as |
||
490 | * detail strings for the notify signal. |
||
491 | */ |
||
492 | gobject_signals[NOTIFY] = |
||
493 | g_signal_new (g_intern_static_string ("notify"), |
||
494 | G_TYPE_FROM_CLASS (class), |
||
495 | G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS | G_SIGNAL_ACTION, |
||
496 | G_STRUCT_OFFSET (GObjectClass, notify), |
||
497 | NULL, NULL, |
||
498 | g_cclosure_marshal_VOID__PARAM, |
||
499 | G_TYPE_NONE, |
||
500 | 1, G_TYPE_PARAM); |
||
501 | |||
502 | /* Install a check function that we'll use to verify that classes that |
||
503 | * implement an interface implement all properties for that interface |
||
504 | */ |
||
505 | g_type_add_interface_check (NULL, object_interface_check_properties); |
||
506 | } |
||
507 | |||
508 | static inline void |
||
509 | install_property_internal (GType g_type, |
||
510 | guint property_id, |
||
511 | GParamSpec *pspec) |
||
512 | { |
||
513 | if (g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type, FALSE)) |
||
514 | { |
||
515 | g_warning ("When installing property: type '%s' already has a property named '%s'", |
||
516 | g_type_name (g_type), |
||
517 | pspec->name); |
||
518 | return; |
||
519 | } |
||
520 | |||
521 | g_param_spec_ref_sink (pspec); |
||
522 | PARAM_SPEC_SET_PARAM_ID (pspec, property_id); |
||
523 | g_param_spec_pool_insert (pspec_pool, pspec, g_type); |
||
524 | } |
||
525 | |||
526 | /** |
||
527 | * g_object_class_install_property: |
||
528 | * @oclass: a #GObjectClass |
||
529 | * @property_id: the id for the new property |
||
530 | * @pspec: the #GParamSpec for the new property |
||
531 | * |
||
532 | * Installs a new property. |
||
533 | * |
||
534 | * All properties should be installed during the class initializer. It |
||
535 | * is possible to install properties after that, but doing so is not |
||
536 | * recommend, and specifically, is not guaranteed to be thread-safe vs. |
||
537 | * use of properties on the same type on other threads. |
||
538 | * |
||
539 | * Note that it is possible to redefine a property in a derived class, |
||
540 | * by installing a property with the same name. This can be useful at times, |
||
541 | * e.g. to change the range of allowed values or the default value. |
||
542 | */ |
||
543 | void |
||
544 | g_object_class_install_property (GObjectClass *class, |
||
545 | guint property_id, |
||
546 | GParamSpec *pspec) |
||
547 | { |
||
548 | g_return_if_fail (G_IS_OBJECT_CLASS (class)); |
||
549 | g_return_if_fail (G_IS_PARAM_SPEC (pspec)); |
||
550 | |||
551 | if (CLASS_HAS_DERIVED_CLASS (class)) |
||
552 | g_error ("Attempt to add property %s::%s to class after it was derived", G_OBJECT_CLASS_NAME (class), pspec->name); |
||
553 | |||
554 | class->flags |= CLASS_HAS_PROPS_FLAG; |
||
555 | |||
556 | g_return_if_fail (pspec->flags & (G_PARAM_READABLE | G_PARAM_WRITABLE)); |
||
557 | if (pspec->flags & G_PARAM_WRITABLE) |
||
558 | g_return_if_fail (class->set_property != NULL); |
||
559 | if (pspec->flags & G_PARAM_READABLE) |
||
560 | g_return_if_fail (class->get_property != NULL); |
||
561 | g_return_if_fail (property_id > 0); |
||
562 | g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */ |
||
563 | if (pspec->flags & G_PARAM_CONSTRUCT) |
||
564 | g_return_if_fail ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); |
||
565 | if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) |
||
566 | g_return_if_fail (pspec->flags & G_PARAM_WRITABLE); |
||
567 | |||
568 | install_property_internal (G_OBJECT_CLASS_TYPE (class), property_id, pspec); |
||
569 | |||
570 | if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) |
||
571 | class->construct_properties = g_slist_append (class->construct_properties, pspec); |
||
572 | |||
573 | /* for property overrides of construct properties, we have to get rid |
||
574 | * of the overidden inherited construct property |
||
575 | */ |
||
576 | pspec = g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type_parent (G_OBJECT_CLASS_TYPE (class)), TRUE); |
||
577 | if (pspec && pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) |
||
578 | class->construct_properties = g_slist_remove (class->construct_properties, pspec); |
||
579 | } |
||
580 | |||
581 | /** |
||
582 | * g_object_class_install_properties: |
||
583 | * @oclass: a #GObjectClass |
||
584 | * @n_pspecs: the length of the #GParamSpecs array |
||
585 | * @pspecs: (array length=n_pspecs): the #GParamSpecs array |
||
586 | * defining the new properties |
||
587 | * |
||
588 | * Installs new properties from an array of #GParamSpecs. |
||
589 | * |
||
590 | * All properties should be installed during the class initializer. It |
||
591 | * is possible to install properties after that, but doing so is not |
||
592 | * recommend, and specifically, is not guaranteed to be thread-safe vs. |
||
593 | * use of properties on the same type on other threads. |
||
594 | * |
||
595 | * The property id of each property is the index of each #GParamSpec in |
||
596 | * the @pspecs array. |
||
597 | * |
||
598 | * The property id of 0 is treated specially by #GObject and it should not |
||
599 | * be used to store a #GParamSpec. |
||
600 | * |
||
601 | * This function should be used if you plan to use a static array of |
||
602 | * #GParamSpecs and g_object_notify_by_pspec(). For instance, this |
||
603 | * class initialization: |
||
604 | * |
||
605 | * |[<!-- language="C" --> |
||
606 | * enum { |
||
607 | * PROP_0, PROP_FOO, PROP_BAR, N_PROPERTIES |
||
608 | * }; |
||
609 | * |
||
610 | * static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; |
||
611 | * |
||
612 | * static void |
||
613 | * my_object_class_init (MyObjectClass *klass) |
||
614 | * { |
||
615 | * GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
||
616 | * |
||
617 | * obj_properties[PROP_FOO] = |
||
618 | * g_param_spec_int ("foo", "Foo", "Foo", |
||
619 | * -1, G_MAXINT, |
||
620 | * 0, |
||
621 | * G_PARAM_READWRITE); |
||
622 | * |
||
623 | * obj_properties[PROP_BAR] = |
||
624 | * g_param_spec_string ("bar", "Bar", "Bar", |
||
625 | * NULL, |
||
626 | * G_PARAM_READWRITE); |
||
627 | * |
||
628 | * gobject_class->set_property = my_object_set_property; |
||
629 | * gobject_class->get_property = my_object_get_property; |
||
630 | * g_object_class_install_properties (gobject_class, |
||
631 | * N_PROPERTIES, |
||
632 | * obj_properties); |
||
633 | * } |
||
634 | * ]| |
||
635 | * |
||
636 | * allows calling g_object_notify_by_pspec() to notify of property changes: |
||
637 | * |
||
638 | * |[<!-- language="C" --> |
||
639 | * void |
||
640 | * my_object_set_foo (MyObject *self, gint foo) |
||
641 | * { |
||
642 | * if (self->foo != foo) |
||
643 | * { |
||
644 | * self->foo = foo; |
||
645 | * g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_FOO]); |
||
646 | * } |
||
647 | * } |
||
648 | * ]| |
||
649 | * |
||
650 | * Since: 2.26 |
||
651 | */ |
||
652 | void |
||
653 | g_object_class_install_properties (GObjectClass *oclass, |
||
654 | guint n_pspecs, |
||
655 | GParamSpec **pspecs) |
||
656 | { |
||
657 | GType oclass_type, parent_type; |
||
658 | gint i; |
||
659 | |||
660 | g_return_if_fail (G_IS_OBJECT_CLASS (oclass)); |
||
661 | g_return_if_fail (n_pspecs > 1); |
||
662 | g_return_if_fail (pspecs[0] == NULL); |
||
663 | |||
664 | if (CLASS_HAS_DERIVED_CLASS (oclass)) |
||
665 | g_error ("Attempt to add properties to %s after it was derived", |
||
666 | G_OBJECT_CLASS_NAME (oclass)); |
||
667 | |||
668 | oclass_type = G_OBJECT_CLASS_TYPE (oclass); |
||
669 | parent_type = g_type_parent (oclass_type); |
||
670 | |||
671 | /* we skip the first element of the array as it would have a 0 prop_id */ |
||
672 | for (i = 1; i < n_pspecs; i++) |
||
673 | { |
||
674 | GParamSpec *pspec = pspecs[i]; |
||
675 | |||
676 | g_return_if_fail (pspec != NULL); |
||
677 | |||
678 | if (pspec->flags & G_PARAM_WRITABLE) |
||
679 | g_return_if_fail (oclass->set_property != NULL); |
||
680 | if (pspec->flags & G_PARAM_READABLE) |
||
681 | g_return_if_fail (oclass->get_property != NULL); |
||
682 | g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */ |
||
683 | if (pspec->flags & G_PARAM_CONSTRUCT) |
||
684 | g_return_if_fail ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); |
||
685 | if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) |
||
686 | g_return_if_fail (pspec->flags & G_PARAM_WRITABLE); |
||
687 | |||
688 | oclass->flags |= CLASS_HAS_PROPS_FLAG; |
||
689 | install_property_internal (oclass_type, i, pspec); |
||
690 | |||
691 | if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) |
||
692 | oclass->construct_properties = g_slist_append (oclass->construct_properties, pspec); |
||
693 | |||
694 | /* for property overrides of construct properties, we have to get rid |
||
695 | * of the overidden inherited construct property |
||
696 | */ |
||
697 | pspec = g_param_spec_pool_lookup (pspec_pool, pspec->name, parent_type, TRUE); |
||
698 | if (pspec && pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) |
||
699 | oclass->construct_properties = g_slist_remove (oclass->construct_properties, pspec); |
||
700 | } |
||
701 | } |
||
702 | |||
703 | /** |
||
704 | * g_object_interface_install_property: |
||
705 | * @g_iface: (type GObject.TypeInterface): any interface vtable for the |
||
706 | * interface, or the default |
||
707 | * vtable for the interface. |
||
708 | * @pspec: the #GParamSpec for the new property |
||
709 | * |
||
710 | * Add a property to an interface; this is only useful for interfaces |
||
711 | * that are added to GObject-derived types. Adding a property to an |
||
712 | * interface forces all objects classes with that interface to have a |
||
713 | * compatible property. The compatible property could be a newly |
||
714 | * created #GParamSpec, but normally |
||
715 | * g_object_class_override_property() will be used so that the object |
||
716 | * class only needs to provide an implementation and inherits the |
||
717 | * property description, default value, bounds, and so forth from the |
||
718 | * interface property. |
||
719 | * |
||
720 | * This function is meant to be called from the interface's default |
||
721 | * vtable initialization function (the @class_init member of |
||
722 | * #GTypeInfo.) It must not be called after after @class_init has |
||
723 | * been called for any object types implementing this interface. |
||
724 | * |
||
725 | * Since: 2.4 |
||
726 | */ |
||
727 | void |
||
728 | g_object_interface_install_property (gpointer g_iface, |
||
729 | GParamSpec *pspec) |
||
730 | { |
||
731 | GTypeInterface *iface_class = g_iface; |
||
732 | |||
733 | g_return_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type)); |
||
734 | g_return_if_fail (G_IS_PARAM_SPEC (pspec)); |
||
735 | g_return_if_fail (!G_IS_PARAM_SPEC_OVERRIDE (pspec)); /* paranoid */ |
||
736 | g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */ |
||
737 | |||
738 | g_return_if_fail (pspec->flags & (G_PARAM_READABLE | G_PARAM_WRITABLE)); |
||
739 | if (pspec->flags & G_PARAM_CONSTRUCT) |
||
740 | g_return_if_fail ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); |
||
741 | if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) |
||
742 | g_return_if_fail (pspec->flags & G_PARAM_WRITABLE); |
||
743 | |||
744 | install_property_internal (iface_class->g_type, 0, pspec); |
||
745 | } |
||
746 | |||
747 | /** |
||
748 | * g_object_class_find_property: |
||
749 | * @oclass: a #GObjectClass |
||
750 | * @property_name: the name of the property to look up |
||
751 | * |
||
752 | * Looks up the #GParamSpec for a property of a class. |
||
753 | * |
||
754 | * Returns: (transfer none): the #GParamSpec for the property, or |
||
755 | * %NULL if the class doesn't have a property of that name |
||
756 | */ |
||
757 | GParamSpec* |
||
758 | g_object_class_find_property (GObjectClass *class, |
||
759 | const gchar *property_name) |
||
760 | { |
||
761 | GParamSpec *pspec; |
||
762 | GParamSpec *redirect; |
||
763 | |||
764 | g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL); |
||
765 | g_return_val_if_fail (property_name != NULL, NULL); |
||
766 | |||
767 | pspec = g_param_spec_pool_lookup (pspec_pool, |
||
768 | property_name, |
||
769 | G_OBJECT_CLASS_TYPE (class), |
||
770 | TRUE); |
||
771 | if (pspec) |
||
772 | { |
||
773 | redirect = g_param_spec_get_redirect_target (pspec); |
||
774 | if (redirect) |
||
775 | return redirect; |
||
776 | else |
||
777 | return pspec; |
||
778 | } |
||
779 | else |
||
780 | return NULL; |
||
781 | } |
||
782 | |||
783 | /** |
||
784 | * g_object_interface_find_property: |
||
785 | * @g_iface: (type GObject.TypeInterface): any interface vtable for the |
||
786 | * interface, or the default vtable for the interface |
||
787 | * @property_name: name of a property to lookup. |
||
788 | * |
||
789 | * Find the #GParamSpec with the given name for an |
||
790 | * interface. Generally, the interface vtable passed in as @g_iface |
||
791 | * will be the default vtable from g_type_default_interface_ref(), or, |
||
792 | * if you know the interface has already been loaded, |
||
793 | * g_type_default_interface_peek(). |
||
794 | * |
||
795 | * Since: 2.4 |
||
796 | * |
||
797 | * Returns: (transfer none): the #GParamSpec for the property of the |
||
798 | * interface with the name @property_name, or %NULL if no |
||
799 | * such property exists. |
||
800 | */ |
||
801 | GParamSpec* |
||
802 | g_object_interface_find_property (gpointer g_iface, |
||
803 | const gchar *property_name) |
||
804 | { |
||
805 | GTypeInterface *iface_class = g_iface; |
||
806 | |||
807 | g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type), NULL); |
||
808 | g_return_val_if_fail (property_name != NULL, NULL); |
||
809 | |||
810 | return g_param_spec_pool_lookup (pspec_pool, |
||
811 | property_name, |
||
812 | iface_class->g_type, |
||
813 | FALSE); |
||
814 | } |
||
815 | |||
816 | /** |
||
817 | * g_object_class_override_property: |
||
818 | * @oclass: a #GObjectClass |
||
819 | * @property_id: the new property ID |
||
820 | * @name: the name of a property registered in a parent class or |
||
821 | * in an interface of this class. |
||
822 | * |
||
823 | * Registers @property_id as referring to a property with the name |
||
824 | * @name in a parent class or in an interface implemented by @oclass. |
||
825 | * This allows this class to "override" a property implementation in |
||
826 | * a parent class or to provide the implementation of a property from |
||
827 | * an interface. |
||
828 | * |
||
829 | * Internally, overriding is implemented by creating a property of type |
||
830 | * #GParamSpecOverride; generally operations that query the properties of |
||
831 | * the object class, such as g_object_class_find_property() or |
||
832 | * g_object_class_list_properties() will return the overridden |
||
833 | * property. However, in one case, the @construct_properties argument of |
||
834 | * the @constructor virtual function, the #GParamSpecOverride is passed |
||
835 | * instead, so that the @param_id field of the #GParamSpec will be |
||
836 | * correct. For virtually all uses, this makes no difference. If you |
||
837 | * need to get the overridden property, you can call |
||
838 | * g_param_spec_get_redirect_target(). |
||
839 | * |
||
840 | * Since: 2.4 |
||
841 | */ |
||
842 | void |
||
843 | g_object_class_override_property (GObjectClass *oclass, |
||
844 | guint property_id, |
||
845 | const gchar *name) |
||
846 | { |
||
847 | GParamSpec *overridden = NULL; |
||
848 | GParamSpec *new; |
||
849 | GType parent_type; |
||
850 | |||
851 | g_return_if_fail (G_IS_OBJECT_CLASS (oclass)); |
||
852 | g_return_if_fail (property_id > 0); |
||
853 | g_return_if_fail (name != NULL); |
||
854 | |||
855 | /* Find the overridden property; first check parent types |
||
856 | */ |
||
857 | parent_type = g_type_parent (G_OBJECT_CLASS_TYPE (oclass)); |
||
858 | if (parent_type != G_TYPE_NONE) |
||
859 | overridden = g_param_spec_pool_lookup (pspec_pool, |
||
860 | name, |
||
861 | parent_type, |
||
862 | TRUE); |
||
863 | if (!overridden) |
||
864 | { |
||
865 | GType *ifaces; |
||
866 | guint n_ifaces; |
||
867 | |||
868 | /* Now check interfaces |
||
869 | */ |
||
870 | ifaces = g_type_interfaces (G_OBJECT_CLASS_TYPE (oclass), &n_ifaces); |
||
871 | while (n_ifaces-- && !overridden) |
||
872 | { |
||
873 | overridden = g_param_spec_pool_lookup (pspec_pool, |
||
874 | name, |
||
875 | ifaces[n_ifaces], |
||
876 | FALSE); |
||
877 | } |
||
878 | |||
879 | g_free (ifaces); |
||
880 | } |
||
881 | |||
882 | if (!overridden) |
||
883 | { |
||
884 | g_warning ("%s: Can't find property to override for '%s::%s'", |
||
885 | G_STRFUNC, G_OBJECT_CLASS_NAME (oclass), name); |
||
886 | return; |
||
887 | } |
||
888 | |||
889 | new = g_param_spec_override (name, overridden); |
||
890 | g_object_class_install_property (oclass, property_id, new); |
||
891 | } |
||
892 | |||
893 | /** |
||
894 | * g_object_class_list_properties: |
||
895 | * @oclass: a #GObjectClass |
||
896 | * @n_properties: (out): return location for the length of the returned array |
||
897 | * |
||
898 | * Get an array of #GParamSpec* for all properties of a class. |
||
899 | * |
||
900 | * Returns: (array length=n_properties) (transfer container): an array of |
||
901 | * #GParamSpec* which should be freed after use |
||
902 | */ |
||
903 | GParamSpec** /* free result */ |
||
904 | g_object_class_list_properties (GObjectClass *class, |
||
905 | guint *n_properties_p) |
||
906 | { |
||
907 | GParamSpec **pspecs; |
||
908 | guint n; |
||
909 | |||
910 | g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL); |
||
911 | |||
912 | pspecs = g_param_spec_pool_list (pspec_pool, |
||
913 | G_OBJECT_CLASS_TYPE (class), |
||
914 | &n); |
||
915 | if (n_properties_p) |
||
916 | *n_properties_p = n; |
||
917 | |||
918 | return pspecs; |
||
919 | } |
||
920 | |||
921 | /** |
||
922 | * g_object_interface_list_properties: |
||
923 | * @g_iface: (type GObject.TypeInterface): any interface vtable for the |
||
924 | * interface, or the default vtable for the interface |
||
925 | * @n_properties_p: (out): location to store number of properties returned. |
||
926 | * |
||
927 | * Lists the properties of an interface.Generally, the interface |
||
928 | * vtable passed in as @g_iface will be the default vtable from |
||
929 | * g_type_default_interface_ref(), or, if you know the interface has |
||
930 | * already been loaded, g_type_default_interface_peek(). |
||
931 | * |
||
932 | * Since: 2.4 |
||
933 | * |
||
934 | * Returns: (array length=n_properties_p) (transfer container): a |
||
935 | * pointer to an array of pointers to #GParamSpec |
||
936 | * structures. The paramspecs are owned by GLib, but the |
||
937 | * array should be freed with g_free() when you are done with |
||
938 | * it. |
||
939 | */ |
||
940 | GParamSpec** |
||
941 | g_object_interface_list_properties (gpointer g_iface, |
||
942 | guint *n_properties_p) |
||
943 | { |
||
944 | GTypeInterface *iface_class = g_iface; |
||
945 | GParamSpec **pspecs; |
||
946 | guint n; |
||
947 | |||
948 | g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type), NULL); |
||
949 | |||
950 | pspecs = g_param_spec_pool_list (pspec_pool, |
||
951 | iface_class->g_type, |
||
952 | &n); |
||
953 | if (n_properties_p) |
||
954 | *n_properties_p = n; |
||
955 | |||
956 | return pspecs; |
||
957 | } |
||
958 | |||
959 | static inline gboolean |
||
960 | object_in_construction (GObject *object) |
||
961 | { |
||
962 | return g_datalist_id_get_data (&object->qdata, quark_in_construction) != NULL; |
||
963 | } |
||
964 | |||
965 | static void |
||
966 | g_object_init (GObject *object, |
||
967 | GObjectClass *class) |
||
968 | { |
||
969 | object->ref_count = 1; |
||
970 | object->qdata = NULL; |
||
971 | |||
972 | if (CLASS_HAS_PROPS (class)) |
||
973 | { |
||
974 | /* freeze object's notification queue, g_object_newv() preserves pairedness */ |
||
975 | g_object_notify_queue_freeze (object, FALSE); |
||
976 | } |
||
977 | |||
978 | if (CLASS_HAS_CUSTOM_CONSTRUCTOR (class)) |
||
979 | { |
||
980 | /* mark object in-construction for notify_queue_thaw() and to allow construct-only properties */ |
||
981 | g_datalist_id_set_data (&object->qdata, quark_in_construction, object); |
||
982 | } |
||
983 | |||
984 | #ifdef G_ENABLE_DEBUG |
||
985 | IF_DEBUG (OBJECTS) |
||
986 | { |
||
987 | G_LOCK (debug_objects); |
||
988 | debug_objects_count++; |
||
989 | g_hash_table_insert (debug_objects_ht, object, object); |
||
990 | G_UNLOCK (debug_objects); |
||
991 | } |
||
992 | #endif /* G_ENABLE_DEBUG */ |
||
993 | } |
||
994 | |||
995 | static void |
||
996 | g_object_do_set_property (GObject *object, |
||
997 | guint property_id, |
||
998 | const GValue *value, |
||
999 | GParamSpec *pspec) |
||
1000 | { |
||
1001 | switch (property_id) |
||
1002 | { |
||
1003 | default: |
||
1004 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
||
1005 | break; |
||
1006 | } |
||
1007 | } |
||
1008 | |||
1009 | static void |
||
1010 | g_object_do_get_property (GObject *object, |
||
1011 | guint property_id, |
||
1012 | GValue *value, |
||
1013 | GParamSpec *pspec) |
||
1014 | { |
||
1015 | switch (property_id) |
||
1016 | { |
||
1017 | default: |
||
1018 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
||
1019 | break; |
||
1020 | } |
||
1021 | } |
||
1022 | |||
1023 | static void |
||
1024 | g_object_real_dispose (GObject *object) |
||
1025 | { |
||
1026 | g_signal_handlers_destroy (object); |
||
1027 | g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL); |
||
1028 | g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL); |
||
1029 | } |
||
1030 | |||
1031 | static void |
||
1032 | g_object_finalize (GObject *object) |
||
1033 | { |
||
1034 | if (object_in_construction (object)) |
||
1035 | { |
||
1036 | g_critical ("object %s %p finalized while still in-construction", |
||
1037 | G_OBJECT_TYPE_NAME (object), object); |
||
1038 | } |
||
1039 | |||
1040 | g_datalist_clear (&object->qdata); |
||
1041 | |||
1042 | #ifdef G_ENABLE_DEBUG |
||
1043 | IF_DEBUG (OBJECTS) |
||
1044 | { |
||
1045 | G_LOCK (debug_objects); |
||
1046 | g_assert (g_hash_table_lookup (debug_objects_ht, object) == object); |
||
1047 | g_hash_table_remove (debug_objects_ht, object); |
||
1048 | debug_objects_count--; |
||
1049 | G_UNLOCK (debug_objects); |
||
1050 | } |
||
1051 | #endif /* G_ENABLE_DEBUG */ |
||
1052 | } |
||
1053 | |||
1054 | static void |
||
1055 | g_object_dispatch_properties_changed (GObject *object, |
||
1056 | guint n_pspecs, |
||
1057 | GParamSpec **pspecs) |
||
1058 | { |
||
1059 | guint i; |
||
1060 | |||
1061 | for (i = 0; i < n_pspecs; i++) |
||
1062 | g_signal_emit (object, gobject_signals[NOTIFY], g_param_spec_get_name_quark (pspecs[i]), pspecs[i]); |
||
1063 | } |
||
1064 | |||
1065 | /** |
||
1066 | * g_object_run_dispose: |
||
1067 | * @object: a #GObject |
||
1068 | * |
||
1069 | * Releases all references to other objects. This can be used to break |
||
1070 | * reference cycles. |
||
1071 | * |
||
1072 | * This function should only be called from object system implementations. |
||
1073 | */ |
||
1074 | void |
||
1075 | g_object_run_dispose (GObject *object) |
||
1076 | { |
||
1077 | g_return_if_fail (G_IS_OBJECT (object)); |
||
1078 | g_return_if_fail (object->ref_count > 0); |
||
1079 | |||
1080 | g_object_ref (object); |
||
1081 | TRACE (GOBJECT_OBJECT_DISPOSE(object,G_TYPE_FROM_INSTANCE(object), 0)); |
||
1082 | G_OBJECT_GET_CLASS (object)->dispose (object); |
||
1083 | TRACE (GOBJECT_OBJECT_DISPOSE_END(object,G_TYPE_FROM_INSTANCE(object), 0)); |
||
1084 | g_object_unref (object); |
||
1085 | } |
||
1086 | |||
1087 | /** |
||
1088 | * g_object_freeze_notify: |
||
1089 | * @object: a #GObject |
||
1090 | * |
||
1091 | * Increases the freeze count on @object. If the freeze count is |
||
1092 | * non-zero, the emission of "notify" signals on @object is |
||
1093 | * stopped. The signals are queued until the freeze count is decreased |
||
1094 | * to zero. Duplicate notifications are squashed so that at most one |
||
1095 | * #GObject::notify signal is emitted for each property modified while the |
||
1096 | * object is frozen. |
||
1097 | * |
||
1098 | * This is necessary for accessors that modify multiple properties to prevent |
||
1099 | * premature notification while the object is still being modified. |
||
1100 | */ |
||
1101 | void |
||
1102 | g_object_freeze_notify (GObject *object) |
||
1103 | { |
||
1104 | g_return_if_fail (G_IS_OBJECT (object)); |
||
1105 | |||
1106 | if (g_atomic_int_get (&object->ref_count) == 0) |
||
1107 | return; |
||
1108 | |||
1109 | g_object_ref (object); |
||
1110 | g_object_notify_queue_freeze (object, FALSE); |
||
1111 | g_object_unref (object); |
||
1112 | } |
||
1113 | |||
1114 | static GParamSpec * |
||
1115 | get_notify_pspec (GParamSpec *pspec) |
||
1116 | { |
||
1117 | GParamSpec *redirected; |
||
1118 | |||
1119 | /* we don't notify on non-READABLE parameters */ |
||
1120 | if (~pspec->flags & G_PARAM_READABLE) |
||
1121 | return NULL; |
||
1122 | |||
1123 | /* if the paramspec is redirected, notify on the target */ |
||
1124 | redirected = g_param_spec_get_redirect_target (pspec); |
||
1125 | if (redirected != NULL) |
||
1126 | return redirected; |
||
1127 | |||
1128 | /* else, notify normally */ |
||
1129 | return pspec; |
||
1130 | } |
||
1131 | |||
1132 | static inline void |
||
1133 | g_object_notify_by_spec_internal (GObject *object, |
||
1134 | GParamSpec *pspec) |
||
1135 | { |
||
1136 | GParamSpec *notify_pspec; |
||
1137 | |||
1138 | notify_pspec = get_notify_pspec (pspec); |
||
1139 | |||
1140 | if (notify_pspec != NULL) |
||
1141 | { |
||
1142 | GObjectNotifyQueue *nqueue; |
||
1143 | |||
1144 | /* conditional freeze: only increase freeze count if already frozen */ |
||
1145 | nqueue = g_object_notify_queue_freeze (object, TRUE); |
||
1146 | |||
1147 | if (nqueue != NULL) |
||
1148 | { |
||
1149 | /* we're frozen, so add to the queue and release our freeze */ |
||
1150 | g_object_notify_queue_add (object, nqueue, notify_pspec); |
||
1151 | g_object_notify_queue_thaw (object, nqueue); |
||
1152 | } |
||
1153 | else |
||
1154 | /* not frozen, so just dispatch the notification directly */ |
||
1155 | G_OBJECT_GET_CLASS (object) |
||
1156 | ->dispatch_properties_changed (object, 1, ¬ify_pspec); |
||
1157 | } |
||
1158 | } |
||
1159 | |||
1160 | /** |
||
1161 | * g_object_notify: |
||
1162 | * @object: a #GObject |
||
1163 | * @property_name: the name of a property installed on the class of @object. |
||
1164 | * |
||
1165 | * Emits a "notify" signal for the property @property_name on @object. |
||
1166 | * |
||
1167 | * When possible, eg. when signaling a property change from within the class |
||
1168 | * that registered the property, you should use g_object_notify_by_pspec() |
||
1169 | * instead. |
||
1170 | * |
||
1171 | * Note that emission of the notify signal may be blocked with |
||
1172 | * g_object_freeze_notify(). In this case, the signal emissions are queued |
||
1173 | * and will be emitted (in reverse order) when g_object_thaw_notify() is |
||
1174 | * called. |
||
1175 | */ |
||
1176 | void |
||
1177 | g_object_notify (GObject *object, |
||
1178 | const gchar *property_name) |
||
1179 | { |
||
1180 | GParamSpec *pspec; |
||
1181 | |||
1182 | g_return_if_fail (G_IS_OBJECT (object)); |
||
1183 | g_return_if_fail (property_name != NULL); |
||
1184 | if (g_atomic_int_get (&object->ref_count) == 0) |
||
1185 | return; |
||
1186 | |||
1187 | g_object_ref (object); |
||
1188 | /* We don't need to get the redirect target |
||
1189 | * (by, e.g. calling g_object_class_find_property()) |
||
1190 | * because g_object_notify_queue_add() does that |
||
1191 | */ |
||
1192 | pspec = g_param_spec_pool_lookup (pspec_pool, |
||
1193 | property_name, |
||
1194 | G_OBJECT_TYPE (object), |
||
1195 | TRUE); |
||
1196 | |||
1197 | if (!pspec) |
||
1198 | g_warning ("%s: object class '%s' has no property named '%s'", |
||
1199 | G_STRFUNC, |
||
1200 | G_OBJECT_TYPE_NAME (object), |
||
1201 | property_name); |
||
1202 | else |
||
1203 | g_object_notify_by_spec_internal (object, pspec); |
||
1204 | g_object_unref (object); |
||
1205 | } |
||
1206 | |||
1207 | /** |
||
1208 | * g_object_notify_by_pspec: |
||
1209 | * @object: a #GObject |
||
1210 | * @pspec: the #GParamSpec of a property installed on the class of @object. |
||
1211 | * |
||
1212 | * Emits a "notify" signal for the property specified by @pspec on @object. |
||
1213 | * |
||
1214 | * This function omits the property name lookup, hence it is faster than |
||
1215 | * g_object_notify(). |
||
1216 | * |
||
1217 | * One way to avoid using g_object_notify() from within the |
||
1218 | * class that registered the properties, and using g_object_notify_by_pspec() |
||
1219 | * instead, is to store the GParamSpec used with |
||
1220 | * g_object_class_install_property() inside a static array, e.g.: |
||
1221 | * |
||
1222 | *|[<!-- language="C" --> |
||
1223 | * enum |
||
1224 | * { |
||
1225 | * PROP_0, |
||
1226 | * PROP_FOO, |
||
1227 | * PROP_LAST |
||
1228 | * }; |
||
1229 | * |
||
1230 | * static GParamSpec *properties[PROP_LAST]; |
||
1231 | * |
||
1232 | * static void |
||
1233 | * my_object_class_init (MyObjectClass *klass) |
||
1234 | * { |
||
1235 | * properties[PROP_FOO] = g_param_spec_int ("foo", "Foo", "The foo", |
||
1236 | * 0, 100, |
||
1237 | * 50, |
||
1238 | * G_PARAM_READWRITE); |
||
1239 | * g_object_class_install_property (gobject_class, |
||
1240 | * PROP_FOO, |
||
1241 | * properties[PROP_FOO]); |
||
1242 | * } |
||
1243 | * ]| |
||
1244 | * |
||
1245 | * and then notify a change on the "foo" property with: |
||
1246 | * |
||
1247 | * |[<!-- language="C" --> |
||
1248 | * g_object_notify_by_pspec (self, properties[PROP_FOO]); |
||
1249 | * ]| |
||
1250 | * |
||
1251 | * Since: 2.26 |
||
1252 | */ |
||
1253 | void |
||
1254 | g_object_notify_by_pspec (GObject *object, |
||
1255 | GParamSpec *pspec) |
||
1256 | { |
||
1257 | |||
1258 | g_return_if_fail (G_IS_OBJECT (object)); |
||
1259 | g_return_if_fail (G_IS_PARAM_SPEC (pspec)); |
||
1260 | |||
1261 | if (g_atomic_int_get (&object->ref_count) == 0) |
||
1262 | return; |
||
1263 | |||
1264 | g_object_ref (object); |
||
1265 | g_object_notify_by_spec_internal (object, pspec); |
||
1266 | g_object_unref (object); |
||
1267 | } |
||
1268 | |||
1269 | /** |
||
1270 | * g_object_thaw_notify: |
||
1271 | * @object: a #GObject |
||
1272 | * |
||
1273 | * Reverts the effect of a previous call to |
||
1274 | * g_object_freeze_notify(). The freeze count is decreased on @object |
||
1275 | * and when it reaches zero, queued "notify" signals are emitted. |
||
1276 | * |
||
1277 | * Duplicate notifications for each property are squashed so that at most one |
||
1278 | * #GObject::notify signal is emitted for each property, in the reverse order |
||
1279 | * in which they have been queued. |
||
1280 | * |
||
1281 | * It is an error to call this function when the freeze count is zero. |
||
1282 | */ |
||
1283 | void |
||
1284 | g_object_thaw_notify (GObject *object) |
||
1285 | { |
||
1286 | GObjectNotifyQueue *nqueue; |
||
1287 | |||
1288 | g_return_if_fail (G_IS_OBJECT (object)); |
||
1289 | if (g_atomic_int_get (&object->ref_count) == 0) |
||
1290 | return; |
||
1291 | |||
1292 | g_object_ref (object); |
||
1293 | |||
1294 | /* FIXME: Freezing is the only way to get at the notify queue. |
||
1295 | * So we freeze once and then thaw twice. |
||
1296 | */ |
||
1297 | nqueue = g_object_notify_queue_freeze (object, FALSE); |
||
1298 | g_object_notify_queue_thaw (object, nqueue); |
||
1299 | g_object_notify_queue_thaw (object, nqueue); |
||
1300 | |||
1301 | g_object_unref (object); |
||
1302 | } |
||
1303 | |||
1304 | static void |
||
1305 | consider_issuing_property_deprecation_warning (const GParamSpec *pspec) |
||
1306 | { |
||
1307 | static GHashTable *already_warned_table; |
||
1308 | static const gchar *enable_diagnostic; |
||
1309 | static GMutex already_warned_lock; |
||
1310 | gboolean already; |
||
1311 | |||
1312 | if (!(pspec->flags & G_PARAM_DEPRECATED)) |
||
1313 | return; |
||
1314 | |||
1315 | if (g_once_init_enter (&enable_diagnostic)) |
||
1316 | { |
||
1317 | const gchar *value = g_getenv ("G_ENABLE_DIAGNOSTIC"); |
||
1318 | |||
1319 | if (!value) |
||
1320 | value = "0"; |
||
1321 | |||
1322 | g_once_init_leave (&enable_diagnostic, value); |
||
1323 | } |
||
1324 | |||
1325 | if (enable_diagnostic[0] == '0') |
||
1326 | return; |
||
1327 | |||
1328 | /* We hash only on property names: this means that we could end up in |
||
1329 | * a situation where we fail to emit a warning about a pair of |
||
1330 | * same-named deprecated properties used on two separate types. |
||
1331 | * That's pretty unlikely to occur, and even if it does, you'll still |
||
1332 | * have seen the warning for the first one... |
||
1333 | * |
||
1334 | * Doing it this way lets us hash directly on the (interned) property |
||
1335 | * name pointers. |
||
1336 | */ |
||
1337 | g_mutex_lock (&already_warned_lock); |
||
1338 | |||
1339 | if (already_warned_table == NULL) |
||
1340 | already_warned_table = g_hash_table_new (NULL, NULL); |
||
1341 | |||
1342 | already = g_hash_table_contains (already_warned_table, (gpointer) pspec->name); |
||
1343 | if (!already) |
||
1344 | g_hash_table_add (already_warned_table, (gpointer) pspec->name); |
||
1345 | |||
1346 | g_mutex_unlock (&already_warned_lock); |
||
1347 | |||
1348 | if (!already) |
||
1349 | g_warning ("The property %s:%s is deprecated and shouldn't be used " |
||
1350 | "anymore. It will be removed in a future version.", |
||
1351 | g_type_name (pspec->owner_type), pspec->name); |
||
1352 | } |
||
1353 | |||
1354 | static inline void |
||
1355 | object_get_property (GObject *object, |
||
1356 | GParamSpec *pspec, |
||
1357 | GValue *value) |
||
1358 | { |
||
1359 | GObjectClass *class = g_type_class_peek (pspec->owner_type); |
||
1360 | guint param_id = PARAM_SPEC_PARAM_ID (pspec); |
||
1361 | GParamSpec *redirect; |
||
1362 | |||
1363 | if (class == NULL) |
||
1364 | { |
||
1365 | g_warning ("'%s::%s' is not a valid property name; '%s' is not a GObject subtype", |
||
1366 | g_type_name (pspec->owner_type), pspec->name, g_type_name (pspec->owner_type)); |
||
1367 | return; |
||
1368 | } |
||
1369 | |||
1370 | redirect = g_param_spec_get_redirect_target (pspec); |
||
1371 | if (redirect) |
||
1372 | pspec = redirect; |
||
1373 | |||
1374 | consider_issuing_property_deprecation_warning (pspec); |
||
1375 | |||
1376 | class->get_property (object, param_id, value, pspec); |
||
1377 | } |
||
1378 | |||
1379 | static inline void |
||
1380 | object_set_property (GObject *object, |
||
1381 | GParamSpec *pspec, |
||
1382 | const GValue *value, |
||
1383 | GObjectNotifyQueue *nqueue) |
||
1384 | { |
||
1385 | GValue tmp_value = G_VALUE_INIT; |
||
1386 | GObjectClass *class = g_type_class_peek (pspec->owner_type); |
||
1387 | guint param_id = PARAM_SPEC_PARAM_ID (pspec); |
||
1388 | GParamSpec *redirect; |
||
1389 | |||
1390 | if (class == NULL) |
||
1391 | { |
||
1392 | g_warning ("'%s::%s' is not a valid property name; '%s' is not a GObject subtype", |
||
1393 | g_type_name (pspec->owner_type), pspec->name, g_type_name (pspec->owner_type)); |
||
1394 | return; |
||
1395 | } |
||
1396 | |||
1397 | redirect = g_param_spec_get_redirect_target (pspec); |
||
1398 | if (redirect) |
||
1399 | pspec = redirect; |
||
1400 | |||
1401 | /* provide a copy to work from, convert (if necessary) and validate */ |
||
1402 | g_value_init (&tmp_value, pspec->value_type); |
||
1403 | if (!g_value_transform (value, &tmp_value)) |
||
1404 | g_warning ("unable to set property '%s' of type '%s' from value of type '%s'", |
||
1405 | pspec->name, |
||
1406 | g_type_name (pspec->value_type), |
||
1407 | G_VALUE_TYPE_NAME (value)); |
||
1408 | else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION)) |
||
1409 | { |
||
1410 | gchar *contents = g_strdup_value_contents (value); |
||
1411 | |||
1412 | g_warning ("value \"%s\" of type '%s' is invalid or out of range for property '%s' of type '%s'", |
||
1413 | contents, |
||
1414 | G_VALUE_TYPE_NAME (value), |
||
1415 | pspec->name, |
||
1416 | g_type_name (pspec->value_type)); |
||
1417 | g_free (contents); |
||
1418 | } |
||
1419 | else |
||
1420 | { |
||
1421 | class->set_property (object, param_id, &tmp_value, pspec); |
||
1422 | |||
1423 | if (~pspec->flags & G_PARAM_EXPLICIT_NOTIFY) |
||
1424 | { |
||
1425 | GParamSpec *notify_pspec; |
||
1426 | |||
1427 | notify_pspec = get_notify_pspec (pspec); |
||
1428 | |||
1429 | if (notify_pspec != NULL) |
||
1430 | g_object_notify_queue_add (object, nqueue, notify_pspec); |
||
1431 | } |
||
1432 | } |
||
1433 | g_value_unset (&tmp_value); |
||
1434 | } |
||
1435 | |||
1436 | static void |
||
1437 | object_interface_check_properties (gpointer check_data, |
||
1438 | gpointer g_iface) |
||
1439 | { |
||
1440 | GTypeInterface *iface_class = g_iface; |
||
1441 | GObjectClass *class; |
||
1442 | GType iface_type = iface_class->g_type; |
||
1443 | GParamSpec **pspecs; |
||
1444 | guint n; |
||
1445 | |||
1446 | class = g_type_class_ref (iface_class->g_instance_type); |
||
1447 | |||
1448 | if (class == NULL) |
||
1449 | return; |
||
1450 | |||
1451 | if (!G_IS_OBJECT_CLASS (class)) |
||
1452 | goto out; |
||
1453 | |||
1454 | pspecs = g_param_spec_pool_list (pspec_pool, iface_type, &n); |
||
1455 | |||
1456 | while (n--) |
||
1457 | { |
||
1458 | GParamSpec *class_pspec = g_param_spec_pool_lookup (pspec_pool, |
||
1459 | pspecs[n]->name, |
||
1460 | G_OBJECT_CLASS_TYPE (class), |
||
1461 | TRUE); |
||
1462 | |||
1463 | if (!class_pspec) |
||
1464 | { |
||
1465 | g_critical ("Object class %s doesn't implement property " |
||
1466 | "'%s' from interface '%s'", |
||
1467 | g_type_name (G_OBJECT_CLASS_TYPE (class)), |
||
1468 | pspecs[n]->name, |
||
1469 | g_type_name (iface_type)); |
||
1470 | |||
1471 | continue; |
||
1472 | } |
||
1473 | |||
1474 | /* We do a number of checks on the properties of an interface to |
||
1475 | * make sure that all classes implementing the interface are |
||
1476 | * overriding the properties in a sane way. |
||
1477 | * |
||
1478 | * We do the checks in order of importance so that we can give |
||
1479 | * more useful error messages first. |
||
1480 | * |
||
1481 | * First, we check that the implementation doesn't remove the |
||
1482 | * basic functionality (readability, writability) advertised by |
||
1483 | * the interface. Next, we check that it doesn't introduce |
||
1484 | * additional restrictions (such as construct-only). Finally, we |
||
1485 | * make sure the types are compatible. |
||
1486 | */ |
||
1487 | |||
1488 | #define SUBSET(a,b,mask) (((a) & ~(b) & (mask)) == 0) |
||
1489 | /* If the property on the interface is readable then the |
||
1490 | * implementation must be readable. If the interface is writable |
||
1491 | * then the implementation must be writable. |
||
1492 | */ |
||
1493 | if (!SUBSET (pspecs[n]->flags, class_pspec->flags, G_PARAM_READABLE | G_PARAM_WRITABLE)) |
||
1494 | { |
||
1495 | g_critical ("Flags for property '%s' on class '%s' remove functionality compared with the " |
||
1496 | "property on interface '%s'\n", pspecs[n]->name, |
||
1497 | g_type_name (G_OBJECT_CLASS_TYPE (class)), g_type_name (iface_type)); |
||
1498 | continue; |
||
1499 | } |
||
1500 | |||
1501 | /* If the property on the interface is writable then we need to |
||
1502 | * make sure the implementation doesn't introduce new restrictions |
||
1503 | * on that writability (ie: construct-only). |
||
1504 | * |
||
1505 | * If the interface was not writable to begin with then we don't |
||
1506 | * really have any problems here because "writable at construct |
||
1507 | * time only" is still more permissive than "read only". |
||
1508 | */ |
||
1509 | if (pspecs[n]->flags & G_PARAM_WRITABLE) |
||
1510 | { |
||
1511 | if (!SUBSET (class_pspec->flags, pspecs[n]->flags, G_PARAM_CONSTRUCT_ONLY)) |
||
1512 | { |
||
1513 | g_critical ("Flags for property '%s' on class '%s' introduce additional restrictions on " |
||
1514 | "writability compared with the property on interface '%s'\n", pspecs[n]->name, |
||
1515 | g_type_name (G_OBJECT_CLASS_TYPE (class)), g_type_name (iface_type)); |
||
1516 | continue; |
||
1517 | } |
||
1518 | } |
||
1519 | #undef SUBSET |
||
1520 | |||
1521 | /* If the property on the interface is readable then we are |
||
1522 | * effectively advertising that reading the property will return a |
||
1523 | * value of a specific type. All implementations of the interface |
||
1524 | * need to return items of this type -- but may be more |
||
1525 | * restrictive. For example, it is legal to have: |
||
1526 | * |
||
1527 | * GtkWidget *get_item(); |
||
1528 | * |
||
1529 | * that is implemented by a function that always returns a |
||
1530 | * GtkEntry. In short: readability implies that the |
||
1531 | * implementation value type must be equal or more restrictive. |
||
1532 | * |
||
1533 | * Similarly, if the property on the interface is writable then |
||
1534 | * must be able to accept the property being set to any value of |
||
1535 | * that type, including subclasses. In this case, we may also be |
||
1536 | * less restrictive. For example, it is legal to have: |
||
1537 | * |
||
1538 | * set_item (GtkEntry *); |
||
1539 | * |
||
1540 | * that is implemented by a function that will actually work with |
||
1541 | * any GtkWidget. In short: writability implies that the |
||
1542 | * implementation value type must be equal or less restrictive. |
||
1543 | * |
||
1544 | * In the case that the property is both readable and writable |
||
1545 | * then the only way that both of the above can be satisfied is |
||
1546 | * with a type that is exactly equal. |
||
1547 | */ |
||
1548 | switch (pspecs[n]->flags & (G_PARAM_READABLE | G_PARAM_WRITABLE)) |
||
1549 | { |
||
1550 | case G_PARAM_READABLE | G_PARAM_WRITABLE: |
||
1551 | /* class pspec value type must have exact equality with interface */ |
||
1552 | if (pspecs[n]->value_type != class_pspec->value_type) |
||
1553 | g_critical ("Read/writable property '%s' on class '%s' has type '%s' which is not exactly equal to the " |
||
1554 | "type '%s' of the property on the interface '%s'\n", pspecs[n]->name, |
||
1555 | g_type_name (G_OBJECT_CLASS_TYPE (class)), g_type_name (G_PARAM_SPEC_VALUE_TYPE (class_pspec)), |
||
1556 | g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspecs[n])), g_type_name (iface_type)); |
||
1557 | break; |
||
1558 | |||
1559 | case G_PARAM_READABLE: |
||
1560 | /* class pspec value type equal or more restrictive than interface */ |
||
1561 | if (!g_type_is_a (class_pspec->value_type, pspecs[n]->value_type)) |
||
1562 | g_critical ("Read-only property '%s' on class '%s' has type '%s' which is not equal to or more " |
||
1563 | "restrictive than the type '%s' of the property on the interface '%s'\n", pspecs[n]->name, |
||
1564 | g_type_name (G_OBJECT_CLASS_TYPE (class)), g_type_name (G_PARAM_SPEC_VALUE_TYPE (class_pspec)), |
||
1565 | g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspecs[n])), g_type_name (iface_type)); |
||
1566 | break; |
||
1567 | |||
1568 | case G_PARAM_WRITABLE: |
||
1569 | /* class pspec value type equal or less restrictive than interface */ |
||
1570 | if (!g_type_is_a (pspecs[n]->value_type, class_pspec->value_type)) |
||
1571 | g_critical ("Write-only property '%s' on class '%s' has type '%s' which is not equal to or less " |
||
1572 | "restrictive than the type '%s' of the property on the interface '%s' \n", pspecs[n]->name, |
||
1573 | g_type_name (G_OBJECT_CLASS_TYPE (class)), g_type_name (G_PARAM_SPEC_VALUE_TYPE (class_pspec)), |
||
1574 | g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspecs[n])), g_type_name (iface_type)); |
||
1575 | break; |
||
1576 | |||
1577 | default: |
||
1578 | g_assert_not_reached (); |
||
1579 | } |
||
1580 | } |
||
1581 | |||
1582 | g_free (pspecs); |
||
1583 | |||
1584 | out: |
||
1585 | g_type_class_unref (class); |
||
1586 | } |
||
1587 | |||
1588 | GType |
||
1589 | g_object_get_type (void) |
||
1590 | { |
||
1591 | return G_TYPE_OBJECT; |
||
1592 | } |
||
1593 | |||
1594 | /** |
||
1595 | * g_object_new: (skip) |
||
1596 | * @object_type: the type id of the #GObject subtype to instantiate |
||
1597 | * @first_property_name: the name of the first property |
||
1598 | * @...: the value of the first property, followed optionally by more |
||
1599 | * name/value pairs, followed by %NULL |
||
1600 | * |
||
1601 | * Creates a new instance of a #GObject subtype and sets its properties. |
||
1602 | * |
||
1603 | * Construction parameters (see #G_PARAM_CONSTRUCT, #G_PARAM_CONSTRUCT_ONLY) |
||
1604 | * which are not explicitly specified are set to their default values. |
||
1605 | * |
||
1606 | * Returns: (transfer full) (type GObject.Object) : a new instance of |
||
1607 | * @object_type |
||
1608 | */ |
||
1609 | gpointer |
||
1610 | g_object_new (GType object_type, |
||
1611 | const gchar *first_property_name, |
||
1612 | ...) |
||
1613 | { |
||
1614 | GObject *object; |
||
1615 | va_list var_args; |
||
1616 | |||
1617 | g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL); |
||
1618 | |||
1619 | /* short circuit for calls supplying no properties */ |
||
1620 | if (!first_property_name) |
||
1621 | return g_object_newv (object_type, 0, NULL); |
||
1622 | |||
1623 | va_start (var_args, first_property_name); |
||
1624 | object = g_object_new_valist (object_type, first_property_name, var_args); |
||
1625 | va_end (var_args); |
||
1626 | |||
1627 | return object; |
||
1628 | } |
||
1629 | |||
1630 | static gpointer |
||
1631 | g_object_new_with_custom_constructor (GObjectClass *class, |
||
1632 | GObjectConstructParam *params, |
||
1633 | guint n_params) |
||
1634 | { |
||
1635 | GObjectNotifyQueue *nqueue = NULL; |
||
1636 | gboolean newly_constructed; |
||
1637 | GObjectConstructParam *cparams; |
||
1638 | GObject *object; |
||
1639 | GValue *cvalues; |
||
1640 | gint n_cparams; |
||
1641 | gint cvals_used; |
||
1642 | GSList *node; |
||
1643 | gint i; |
||
1644 | |||
1645 | /* If we have ->constructed() then we have to do a lot more work. |
||
1646 | * It's possible that this is a singleton and it's also possible |
||
1647 | * that the user's constructor() will attempt to modify the values |
||
1648 | * that we pass in, so we'll need to allocate copies of them. |
||
1649 | * It's also possible that the user may attempt to call |
||
1650 | * g_object_set() from inside of their constructor, so we need to |
||
1651 | * add ourselves to a list of objects for which that is allowed |
||
1652 | * while their constructor() is running. |
||
1653 | */ |
||
1654 | |||
1655 | /* Create the array of GObjectConstructParams for constructor() */ |
||
1656 | n_cparams = g_slist_length (class->construct_properties); |
||
1657 | cparams = g_new (GObjectConstructParam, n_cparams); |
||
1658 | cvalues = g_new0 (GValue, n_cparams); |
||
1659 | cvals_used = 0; |
||
1660 | i = 0; |
||
1661 | |||
1662 | /* As above, we may find the value in the passed-in params list. |
||
1663 | * |
||
1664 | * If we have the value passed in then we can use the GValue from |
||
1665 | * it directly because it is safe to modify. If we use the |
||
1666 | * default value from the class, we had better not pass that in |
||
1667 | * and risk it being modified, so we create a new one. |
||
1668 | * */ |
||
1669 | for (node = class->construct_properties; node; node = node->next) |
||
1670 | { |
||
1671 | GParamSpec *pspec; |
||
1672 | GValue *value; |
||
1673 | gint j; |
||
1674 | |||
1675 | pspec = node->data; |
||
1676 | value = NULL; /* to silence gcc... */ |
||
1677 | |||
1678 | for (j = 0; j < n_params; j++) |
||
1679 | if (params[j].pspec == pspec) |
||
1680 | { |
||
1681 | consider_issuing_property_deprecation_warning (pspec); |
||
1682 | value = params[j].value; |
||
1683 | break; |
||
1684 | } |
||
1685 | |||
1686 | if (j == n_params) |
||
1687 | { |
||
1688 | value = &cvalues[cvals_used++]; |
||
1689 | g_value_init (value, pspec->value_type); |
||
1690 | g_param_value_set_default (pspec, value); |
||
1691 | } |
||
1692 | |||
1693 | cparams[i].pspec = pspec; |
||
1694 | cparams[i].value = value; |
||
1695 | i++; |
||
1696 | } |
||
1697 | |||
1698 | /* construct object from construction parameters */ |
||
1699 | object = class->constructor (class->g_type_class.g_type, n_cparams, cparams); |
||
1700 | /* free construction values */ |
||
1701 | g_free (cparams); |
||
1702 | while (cvals_used--) |
||
1703 | g_value_unset (&cvalues[cvals_used]); |
||
1704 | g_free (cvalues); |
||
1705 | |||
1706 | /* There is code in the wild that relies on being able to return NULL |
||
1707 | * from its custom constructor. This was never a supported operation, |
||
1708 | * but since the code is already out there... |
||
1709 | */ |
||
1710 | if (object == NULL) |
||
1711 | { |
||
1712 | g_critical ("Custom constructor for class %s returned NULL (which is invalid). " |
||
1713 | "Please use GInitable instead.", G_OBJECT_CLASS_NAME (class)); |
||
1714 | return NULL; |
||
1715 | } |
||
1716 | |||
1717 | /* g_object_init() will have marked the object as being in-construction. |
||
1718 | * Check if the returned object still is so marked, or if this is an |
||
1719 | * already-existing singleton (in which case we should not do 'constructed'). |
||
1720 | */ |
||
1721 | newly_constructed = object_in_construction (object); |
||
1722 | if (newly_constructed) |
||
1723 | g_datalist_id_set_data (&object->qdata, quark_in_construction, NULL); |
||
1724 | |||
1725 | if (CLASS_HAS_PROPS (class)) |
||
1726 | { |
||
1727 | /* If this object was newly_constructed then g_object_init() |
||
1728 | * froze the queue. We need to freeze it here in order to get |
||
1729 | * the handle so that we can thaw it below (otherwise it will |
||
1730 | * be frozen forever). |
||
1731 | * |
||
1732 | * We also want to do a freeze if we have any params to set, |
||
1733 | * even on a non-newly_constructed object. |
||
1734 | * |
||
1735 | * It's possible that we have the case of non-newly created |
||
1736 | * singleton and all of the passed-in params were construct |
||
1737 | * properties so n_params > 0 but we will actually set no |
||
1738 | * properties. This is a pretty lame case to optimise, so |
||
1739 | * just ignore it and freeze anyway. |
||
1740 | */ |
||
1741 | if (newly_constructed || n_params) |
||
1742 | nqueue = g_object_notify_queue_freeze (object, FALSE); |
||
1743 | |||
1744 | /* Remember: if it was newly_constructed then g_object_init() |
||
1745 | * already did a freeze, so we now have two. Release one. |
||
1746 | */ |
||
1747 | if (newly_constructed) |
||
1748 | g_object_notify_queue_thaw (object, nqueue); |
||
1749 | } |
||
1750 | |||
1751 | /* run 'constructed' handler if there is a custom one */ |
||
1752 | if (newly_constructed && CLASS_HAS_CUSTOM_CONSTRUCTED (class)) |
||
1753 | class->constructed (object); |
||
1754 | |||
1755 | /* set remaining properties */ |
||
1756 | for (i = 0; i < n_params; i++) |
||
1757 | if (!(params[i].pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))) |
||
1758 | { |
||
1759 | consider_issuing_property_deprecation_warning (params[i].pspec); |
||
1760 | object_set_property (object, params[i].pspec, params[i].value, nqueue); |
||
1761 | } |
||
1762 | |||
1763 | /* If nqueue is non-NULL then we are frozen. Thaw it. */ |
||
1764 | if (nqueue) |
||
1765 | g_object_notify_queue_thaw (object, nqueue); |
||
1766 | |||
1767 | return object; |
||
1768 | } |
||
1769 | |||
1770 | static gpointer |
||
1771 | g_object_new_internal (GObjectClass *class, |
||
1772 | GObjectConstructParam *params, |
||
1773 | guint n_params) |
||
1774 | { |
||
1775 | GObjectNotifyQueue *nqueue = NULL; |
||
1776 | GObject *object; |
||
1777 | |||
1778 | if G_UNLIKELY (CLASS_HAS_CUSTOM_CONSTRUCTOR (class)) |
||
1779 | return g_object_new_with_custom_constructor (class, params, n_params); |
||
1780 | |||
1781 | object = (GObject *) g_type_create_instance (class->g_type_class.g_type); |
||
1782 | |||
1783 | if (CLASS_HAS_PROPS (class)) |
||
1784 | { |
||
1785 | GSList *node; |
||
1786 | |||
1787 | /* This will have been setup in g_object_init() */ |
||
1788 | nqueue = g_datalist_id_get_data (&object->qdata, quark_notify_queue); |
||
1789 | g_assert (nqueue != NULL); |
||
1790 | |||
1791 | /* We will set exactly n_construct_properties construct |
||
1792 | * properties, but they may come from either the class default |
||
1793 | * values or the passed-in parameter list. |
||
1794 | */ |
||
1795 | for (node = class->construct_properties; node; node = node->next) |
||
1796 | { |
||
1797 | const GValue *value; |
||
1798 | GParamSpec *pspec; |
||
1799 | gint j; |
||
1800 | |||
1801 | pspec = node->data; |
||
1802 | value = NULL; /* to silence gcc... */ |
||
1803 | |||
1804 | for (j = 0; j < n_params; j++) |
||
1805 | if (params[j].pspec == pspec) |
||
1806 | { |
||
1807 | consider_issuing_property_deprecation_warning (pspec); |
||
1808 | value = params[j].value; |
||
1809 | break; |
||
1810 | } |
||
1811 | |||
1812 | if (j == n_params) |
||
1813 | value = g_param_spec_get_default_value (pspec); |
||
1814 | |||
1815 | object_set_property (object, pspec, value, nqueue); |
||
1816 | } |
||
1817 | } |
||
1818 | |||
1819 | /* run 'constructed' handler if there is a custom one */ |
||
1820 | if (CLASS_HAS_CUSTOM_CONSTRUCTED (class)) |
||
1821 | class->constructed (object); |
||
1822 | |||
1823 | if (nqueue) |
||
1824 | { |
||
1825 | gint i; |
||
1826 | |||
1827 | /* Set remaining properties. The construct properties will |
||
1828 | * already have been taken, so set only the non-construct |
||
1829 | * ones. |
||
1830 | */ |
||
1831 | for (i = 0; i < n_params; i++) |
||
1832 | if (!(params[i].pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))) |
||
1833 | { |
||
1834 | consider_issuing_property_deprecation_warning (params[i].pspec); |
||
1835 | object_set_property (object, params[i].pspec, params[i].value, nqueue); |
||
1836 | } |
||
1837 | |||
1838 | g_object_notify_queue_thaw (object, nqueue); |
||
1839 | } |
||
1840 | |||
1841 | return object; |
||
1842 | } |
||
1843 | |||
1844 | /** |
||
1845 | * g_object_newv: (rename-to g_object_new) |
||
1846 | * @object_type: the type id of the #GObject subtype to instantiate |
||
1847 | * @n_parameters: the length of the @parameters array |
||
1848 | * @parameters: (array length=n_parameters): an array of #GParameter |
||
1849 | * |
||
1850 | * Creates a new instance of a #GObject subtype and sets its properties. |
||
1851 | * |
||
1852 | * Construction parameters (see #G_PARAM_CONSTRUCT, #G_PARAM_CONSTRUCT_ONLY) |
||
1853 | * which are not explicitly specified are set to their default values. |
||
1854 | * |
||
1855 | * Returns: (type GObject.Object) (transfer full): a new instance of |
||
1856 | * @object_type |
||
1857 | */ |
||
1858 | gpointer |
||
1859 | g_object_newv (GType object_type, |
||
1860 | guint n_parameters, |
||
1861 | GParameter *parameters) |
||
1862 | { |
||
1863 | GObjectClass *class, *unref_class = NULL; |
||
1864 | GObject *object; |
||
1865 | |||
1866 | g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL); |
||
1867 | g_return_val_if_fail (n_parameters == 0 || parameters != NULL, NULL); |
||
1868 | |||
1869 | /* Try to avoid thrashing the ref_count if we don't need to (since |
||
1870 | * it's a locked operation). |
||
1871 | */ |
||
1872 | class = g_type_class_peek_static (object_type); |
||
1873 | |||
1874 | if (!class) |
||
1875 | class = unref_class = g_type_class_ref (object_type); |
||
1876 | |||
1877 | if (n_parameters) |
||
1878 | { |
||
1879 | GObjectConstructParam *cparams; |
||
1880 | guint i, j; |
||
1881 | |||
1882 | cparams = g_newa (GObjectConstructParam, n_parameters); |
||
1883 | j = 0; |
||
1884 | |||
1885 | for (i = 0; i < n_parameters; i++) |
||
1886 | { |
||
1887 | GParamSpec *pspec; |
||
1888 | gint k; |
||
1889 | |||
1890 | pspec = g_param_spec_pool_lookup (pspec_pool, parameters[i].name, object_type, TRUE); |
||
1891 | |||
1892 | if G_UNLIKELY (!pspec) |
||
1893 | { |
||
1894 | g_critical ("%s: object class '%s' has no property named '%s'", |
||
1895 | G_STRFUNC, g_type_name (object_type), parameters[i].name); |
||
1896 | continue; |
||
1897 | } |
||
1898 | |||
1899 | if G_UNLIKELY (~pspec->flags & G_PARAM_WRITABLE) |
||
1900 | { |
||
1901 | g_critical ("%s: property '%s' of object class '%s' is not writable", |
||
1902 | G_STRFUNC, pspec->name, g_type_name (object_type)); |
||
1903 | continue; |
||
1904 | } |
||
1905 | |||
1906 | if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) |
||
1907 | { |
||
1908 | for (k = 0; k < j; k++) |
||
1909 | if (cparams[k].pspec == pspec) |
||
1910 | break; |
||
1911 | if G_UNLIKELY (k != j) |
||
1912 | { |
||
1913 | g_critical ("%s: construct property '%s' for type '%s' cannot be set twice", |
||
1914 | G_STRFUNC, parameters[i].name, g_type_name (object_type)); |
||
1915 | continue; |
||
1916 | } |
||
1917 | } |
||
1918 | |||
1919 | cparams[j].pspec = pspec; |
||
1920 | cparams[j].value = ¶meters[i].value; |
||
1921 | j++; |
||
1922 | } |
||
1923 | |||
1924 | object = g_object_new_internal (class, cparams, j); |
||
1925 | } |
||
1926 | else |
||
1927 | /* Fast case: no properties passed in. */ |
||
1928 | object = g_object_new_internal (class, NULL, 0); |
||
1929 | |||
1930 | if (unref_class) |
||
1931 | g_type_class_unref (unref_class); |
||
1932 | |||
1933 | return object; |
||
1934 | } |
||
1935 | |||
1936 | /** |
||
1937 | * g_object_new_valist: (skip) |
||
1938 | * @object_type: the type id of the #GObject subtype to instantiate |
||
1939 | * @first_property_name: the name of the first property |
||
1940 | * @var_args: the value of the first property, followed optionally by more |
||
1941 | * name/value pairs, followed by %NULL |
||
1942 | * |
||
1943 | * Creates a new instance of a #GObject subtype and sets its properties. |
||
1944 | * |
||
1945 | * Construction parameters (see #G_PARAM_CONSTRUCT, #G_PARAM_CONSTRUCT_ONLY) |
||
1946 | * which are not explicitly specified are set to their default values. |
||
1947 | * |
||
1948 | * Returns: a new instance of @object_type |
||
1949 | */ |
||
1950 | GObject* |
||
1951 | g_object_new_valist (GType object_type, |
||
1952 | const gchar *first_property_name, |
||
1953 | va_list var_args) |
||
1954 | { |
||
1955 | GObjectClass *class, *unref_class = NULL; |
||
1956 | GObject *object; |
||
1957 | |||
1958 | g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL); |
||
1959 | |||
1960 | /* Try to avoid thrashing the ref_count if we don't need to (since |
||
1961 | * it's a locked operation). |
||
1962 | */ |
||
1963 | class = g_type_class_peek_static (object_type); |
||
1964 | |||
1965 | if (!class) |
||
1966 | class = unref_class = g_type_class_ref (object_type); |
||
1967 | |||
1968 | if (first_property_name) |
||
1969 | { |
||
1970 | GObjectConstructParam stack_params[16]; |
||
1971 | GObjectConstructParam *params; |
||
1972 | const gchar *name; |
||
1973 | gint n_params = 0; |
||
1974 | |||
1975 | name = first_property_name; |
||
1976 | params = stack_params; |
||
1977 | |||
1978 | do |
||
1979 | { |
||
1980 | gchar *error = NULL; |
||
1981 | GParamSpec *pspec; |
||
1982 | gint i; |
||
1983 | |||
1984 | pspec = g_param_spec_pool_lookup (pspec_pool, name, object_type, TRUE); |
||
1985 | |||
1986 | if G_UNLIKELY (!pspec) |
||
1987 | { |
||
1988 | g_critical ("%s: object class '%s' has no property named '%s'", |
||
1989 | G_STRFUNC, g_type_name (object_type), name); |
||
1990 | /* Can't continue because arg list will be out of sync. */ |
||
1991 | break; |
||
1992 | } |
||
1993 | |||
1994 | if G_UNLIKELY (~pspec->flags & G_PARAM_WRITABLE) |
||
1995 | { |
||
1996 | g_critical ("%s: property '%s' of object class '%s' is not writable", |
||
1997 | G_STRFUNC, pspec->name, g_type_name (object_type)); |
||
1998 | break; |
||
1999 | } |
||
2000 | |||
2001 | if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) |
||
2002 | { |
||
2003 | for (i = 0; i < n_params; i++) |
||
2004 | if (params[i].pspec == pspec) |
||
2005 | break; |
||
2006 | if G_UNLIKELY (i != n_params) |
||
2007 | { |
||
2008 | g_critical ("%s: property '%s' for type '%s' cannot be set twice", |
||
2009 | G_STRFUNC, name, g_type_name (object_type)); |
||
2010 | break; |
||
2011 | } |
||
2012 | } |
||
2013 | |||
2014 | if (n_params == 16) |
||
2015 | { |
||
2016 | params = g_new (GObjectConstructParam, n_params + 1); |
||
2017 | memcpy (params, stack_params, sizeof stack_params); |
||
2018 | } |
||
2019 | else if (n_params > 16) |
||
2020 | params = g_renew (GObjectConstructParam, params, n_params + 1); |
||
2021 | |||
2022 | params[n_params].pspec = pspec; |
||
2023 | params[n_params].value = g_newa (GValue, 1); |
||
2024 | memset (params[n_params].value, 0, sizeof (GValue)); |
||
2025 | |||
2026 | G_VALUE_COLLECT_INIT (params[n_params].value, pspec->value_type, var_args, 0, &error); |
||
2027 | |||
2028 | if (error) |
||
2029 | { |
||
2030 | g_critical ("%s: %s", G_STRFUNC, error); |
||
2031 | g_value_unset (params[n_params].value); |
||
2032 | g_free (error); |
||
2033 | break; |
||
2034 | } |
||
2035 | |||
2036 | n_params++; |
||
2037 | } |
||
2038 | while ((name = va_arg (var_args, const gchar *))); |
||
2039 | |||
2040 | object = g_object_new_internal (class, params, n_params); |
||
2041 | |||
2042 | while (n_params--) |
||
2043 | g_value_unset (params[n_params].value); |
||
2044 | |||
2045 | if (params != stack_params) |
||
2046 | g_free (params); |
||
2047 | } |
||
2048 | else |
||
2049 | /* Fast case: no properties passed in. */ |
||
2050 | object = g_object_new_internal (class, NULL, 0); |
||
2051 | |||
2052 | if (unref_class) |
||
2053 | g_type_class_unref (unref_class); |
||
2054 | |||
2055 | return object; |
||
2056 | } |
||
2057 | |||
2058 | static GObject* |
||
2059 | g_object_constructor (GType type, |
||
2060 | guint n_construct_properties, |
||
2061 | GObjectConstructParam *construct_params) |
||
2062 | { |
||
2063 | GObject *object; |
||
2064 | |||
2065 | /* create object */ |
||
2066 | object = (GObject*) g_type_create_instance (type); |
||
2067 | |||
2068 | /* set construction parameters */ |
||
2069 | if (n_construct_properties) |
||
2070 | { |
||
2071 | GObjectNotifyQueue *nqueue = g_object_notify_queue_freeze (object, FALSE); |
||
2072 | |||
2073 | /* set construct properties */ |
||
2074 | while (n_construct_properties--) |
||
2075 | { |
||
2076 | GValue *value = construct_params->value; |
||
2077 | GParamSpec *pspec = construct_params->pspec; |
||
2078 | |||
2079 | construct_params++; |
||
2080 | object_set_property (object, pspec, value, nqueue); |
||
2081 | } |
||
2082 | g_object_notify_queue_thaw (object, nqueue); |
||
2083 | /* the notification queue is still frozen from g_object_init(), so |
||
2084 | * we don't need to handle it here, g_object_newv() takes |
||
2085 | * care of that |
||
2086 | */ |
||
2087 | } |
||
2088 | |||
2089 | return object; |
||
2090 | } |
||
2091 | |||
2092 | static void |
||
2093 | g_object_constructed (GObject *object) |
||
2094 | { |
||
2095 | /* empty default impl to allow unconditional upchaining */ |
||
2096 | } |
||
2097 | |||
2098 | /** |
||
2099 | * g_object_set_valist: (skip) |
||
2100 | * @object: a #GObject |
||
2101 | * @first_property_name: name of the first property to set |
||
2102 | * @var_args: value for the first property, followed optionally by more |
||
2103 | * name/value pairs, followed by %NULL |
||
2104 | * |
||
2105 | * Sets properties on an object. |
||
2106 | */ |
||
2107 | void |
||
2108 | g_object_set_valist (GObject *object, |
||
2109 | const gchar *first_property_name, |
||
2110 | va_list var_args) |
||
2111 | { |
||
2112 | GObjectNotifyQueue *nqueue; |
||
2113 | const gchar *name; |
||
2114 | |||
2115 | g_return_if_fail (G_IS_OBJECT (object)); |
||
2116 | |||
2117 | g_object_ref (object); |
||
2118 | nqueue = g_object_notify_queue_freeze (object, FALSE); |
||
2119 | |||
2120 | name = first_property_name; |
||
2121 | while (name) |
||
2122 | { |
||
2123 | GValue value = G_VALUE_INIT; |
||
2124 | GParamSpec *pspec; |
||
2125 | gchar *error = NULL; |
||
2126 | |||
2127 | pspec = g_param_spec_pool_lookup (pspec_pool, |
||
2128 | name, |
||
2129 | G_OBJECT_TYPE (object), |
||
2130 | TRUE); |
||
2131 | if (!pspec) |
||
2132 | { |
||
2133 | g_warning ("%s: object class '%s' has no property named '%s'", |
||
2134 | G_STRFUNC, |
||
2135 | G_OBJECT_TYPE_NAME (object), |
||
2136 | name); |
||
2137 | break; |
||
2138 | } |
||
2139 | if (!(pspec->flags & G_PARAM_WRITABLE)) |
||
2140 | { |
||
2141 | g_warning ("%s: property '%s' of object class '%s' is not writable", |
||
2142 | G_STRFUNC, |
||
2143 | pspec->name, |
||
2144 | G_OBJECT_TYPE_NAME (object)); |
||
2145 | break; |
||
2146 | } |
||
2147 | if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) && !object_in_construction (object)) |
||
2148 | { |
||
2149 | g_warning ("%s: construct property \"%s\" for object '%s' can't be set after construction", |
||
2150 | G_STRFUNC, pspec->name, G_OBJECT_TYPE_NAME (object)); |
||
2151 | break; |
||
2152 | } |
||
2153 | |||
2154 | G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args, |
||
2155 | 0, &error); |
||
2156 | if (error) |
||
2157 | { |
||
2158 | g_warning ("%s: %s", G_STRFUNC, error); |
||
2159 | g_free (error); |
||
2160 | g_value_unset (&value); |
||
2161 | break; |
||
2162 | } |
||
2163 | |||
2164 | consider_issuing_property_deprecation_warning (pspec); |
||
2165 | object_set_property (object, pspec, &value, nqueue); |
||
2166 | g_value_unset (&value); |
||
2167 | |||
2168 | name = va_arg (var_args, gchar*); |
||
2169 | } |
||
2170 | |||
2171 | g_object_notify_queue_thaw (object, nqueue); |
||
2172 | g_object_unref (object); |
||
2173 | } |
||
2174 | |||
2175 | /** |
||
2176 | * g_object_get_valist: (skip) |
||
2177 | * @object: a #GObject |
||
2178 | * @first_property_name: name of the first property to get |
||
2179 | * @var_args: return location for the first property, followed optionally by more |
||
2180 | * name/return location pairs, followed by %NULL |
||
2181 | * |
||
2182 | * Gets properties of an object. |
||
2183 | * |
||
2184 | * In general, a copy is made of the property contents and the caller |
||
2185 | * is responsible for freeing the memory in the appropriate manner for |
||
2186 | * the type, for instance by calling g_free() or g_object_unref(). |
||
2187 | * |
||
2188 | * See g_object_get(). |
||
2189 | */ |
||
2190 | void |
||
2191 | g_object_get_valist (GObject *object, |
||
2192 | const gchar *first_property_name, |
||
2193 | va_list var_args) |
||
2194 | { |
||
2195 | const gchar *name; |
||
2196 | |||
2197 | g_return_if_fail (G_IS_OBJECT (object)); |
||
2198 | |||
2199 | g_object_ref (object); |
||
2200 | |||
2201 | name = first_property_name; |
||
2202 | |||
2203 | while (name) |
||
2204 | { |
||
2205 | GValue value = G_VALUE_INIT; |
||
2206 | GParamSpec *pspec; |
||
2207 | gchar *error; |
||
2208 | |||
2209 | pspec = g_param_spec_pool_lookup (pspec_pool, |
||
2210 | name, |
||
2211 | G_OBJECT_TYPE (object), |
||
2212 | TRUE); |
||
2213 | if (!pspec) |
||
2214 | { |
||
2215 | g_warning ("%s: object class '%s' has no property named '%s'", |
||
2216 | G_STRFUNC, |
||
2217 | G_OBJECT_TYPE_NAME (object), |
||
2218 | name); |
||
2219 | break; |
||
2220 | } |
||
2221 | if (!(pspec->flags & G_PARAM_READABLE)) |
||
2222 | { |
||
2223 | g_warning ("%s: property '%s' of object class '%s' is not readable", |
||
2224 | G_STRFUNC, |
||
2225 | pspec->name, |
||
2226 | G_OBJECT_TYPE_NAME (object)); |
||
2227 | break; |
||
2228 | } |
||
2229 | |||
2230 | g_value_init (&value, pspec->value_type); |
||
2231 | |||
2232 | object_get_property (object, pspec, &value); |
||
2233 | |||
2234 | G_VALUE_LCOPY (&value, var_args, 0, &error); |
||
2235 | if (error) |
||
2236 | { |
||
2237 | g_warning ("%s: %s", G_STRFUNC, error); |
||
2238 | g_free (error); |
||
2239 | g_value_unset (&value); |
||
2240 | break; |
||
2241 | } |
||
2242 | |||
2243 | g_value_unset (&value); |
||
2244 | |||
2245 | name = va_arg (var_args, gchar*); |
||
2246 | } |
||
2247 | |||
2248 | g_object_unref (object); |
||
2249 | } |
||
2250 | |||
2251 | /** |
||
2252 | * g_object_set: (skip) |
||
2253 | * @object: (type GObject.Object): a #GObject |
||
2254 | * @first_property_name: name of the first property to set |
||
2255 | * @...: value for the first property, followed optionally by more |
||
2256 | * name/value pairs, followed by %NULL |
||
2257 | * |
||
2258 | * Sets properties on an object. |
||
2259 | * |
||
2260 | * Note that the "notify" signals are queued and only emitted (in |
||
2261 | * reverse order) after all properties have been set. See |
||
2262 | * g_object_freeze_notify(). |
||
2263 | */ |
||
2264 | void |
||
2265 | g_object_set (gpointer _object, |
||
2266 | const gchar *first_property_name, |
||
2267 | ...) |
||
2268 | { |
||
2269 | GObject *object = _object; |
||
2270 | va_list var_args; |
||
2271 | |||
2272 | g_return_if_fail (G_IS_OBJECT (object)); |
||
2273 | |||
2274 | va_start (var_args, first_property_name); |
||
2275 | g_object_set_valist (object, first_property_name, var_args); |
||
2276 | va_end (var_args); |
||
2277 | } |
||
2278 | |||
2279 | /** |
||
2280 | * g_object_get: (skip) |
||
2281 | * @object: (type GObject.Object): a #GObject |
||
2282 | * @first_property_name: name of the first property to get |
||
2283 | * @...: return location for the first property, followed optionally by more |
||
2284 | * name/return location pairs, followed by %NULL |
||
2285 | * |
||
2286 | * Gets properties of an object. |
||
2287 | * |
||
2288 | * In general, a copy is made of the property contents and the caller |
||
2289 | * is responsible for freeing the memory in the appropriate manner for |
||
2290 | * the type, for instance by calling g_free() or g_object_unref(). |
||
2291 | * |
||
2292 | * Here is an example of using g_object_get() to get the contents |
||
2293 | * of three properties: an integer, a string and an object: |
||
2294 | * |[<!-- language="C" --> |
||
2295 | * gint intval; |
||
2296 | * gchar *strval; |
||
2297 | * GObject *objval; |
||
2298 | * |
||
2299 | * g_object_get (my_object, |
||
2300 | * "int-property", &intval, |
||
2301 | * "str-property", &strval, |
||
2302 | * "obj-property", &objval, |
||
2303 | * NULL); |
||
2304 | * |
||
2305 | * // Do something with intval, strval, objval |
||
2306 | * |
||
2307 | * g_free (strval); |
||
2308 | * g_object_unref (objval); |
||
2309 | * ]| |
||
2310 | */ |
||
2311 | void |
||
2312 | g_object_get (gpointer _object, |
||
2313 | const gchar *first_property_name, |
||
2314 | ...) |
||
2315 | { |
||
2316 | GObject *object = _object; |
||
2317 | va_list var_args; |
||
2318 | |||
2319 | g_return_if_fail (G_IS_OBJECT (object)); |
||
2320 | |||
2321 | va_start (var_args, first_property_name); |
||
2322 | g_object_get_valist (object, first_property_name, var_args); |
||
2323 | va_end (var_args); |
||
2324 | } |
||
2325 | |||
2326 | /** |
||
2327 | * g_object_set_property: |
||
2328 | * @object: a #GObject |
||
2329 | * @property_name: the name of the property to set |
||
2330 | * @value: the value |
||
2331 | * |
||
2332 | * Sets a property on an object. |
||
2333 | */ |
||
2334 | void |
||
2335 | g_object_set_property (GObject *object, |
||
2336 | const gchar *property_name, |
||
2337 | const GValue *value) |
||
2338 | { |
||
2339 | GObjectNotifyQueue *nqueue; |
||
2340 | GParamSpec *pspec; |
||
2341 | |||
2342 | g_return_if_fail (G_IS_OBJECT (object)); |
||
2343 | g_return_if_fail (property_name != NULL); |
||
2344 | g_return_if_fail (G_IS_VALUE (value)); |
||
2345 | |||
2346 | g_object_ref (object); |
||
2347 | nqueue = g_object_notify_queue_freeze (object, FALSE); |
||
2348 | |||
2349 | pspec = g_param_spec_pool_lookup (pspec_pool, |
||
2350 | property_name, |
||
2351 | G_OBJECT_TYPE (object), |
||
2352 | TRUE); |
||
2353 | if (!pspec) |
||
2354 | g_warning ("%s: object class '%s' has no property named '%s'", |
||
2355 | G_STRFUNC, |
||
2356 | G_OBJECT_TYPE_NAME (object), |
||
2357 | property_name); |
||
2358 | else if (!(pspec->flags & G_PARAM_WRITABLE)) |
||
2359 | g_warning ("%s: property '%s' of object class '%s' is not writable", |
||
2360 | G_STRFUNC, |
||
2361 | pspec->name, |
||
2362 | G_OBJECT_TYPE_NAME (object)); |
||
2363 | else if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) && !object_in_construction (object)) |
||
2364 | g_warning ("%s: construct property \"%s\" for object '%s' can't be set after construction", |
||
2365 | G_STRFUNC, pspec->name, G_OBJECT_TYPE_NAME (object)); |
||
2366 | else |
||
2367 | { |
||
2368 | consider_issuing_property_deprecation_warning (pspec); |
||
2369 | object_set_property (object, pspec, value, nqueue); |
||
2370 | } |
||
2371 | |||
2372 | g_object_notify_queue_thaw (object, nqueue); |
||
2373 | g_object_unref (object); |
||
2374 | } |
||
2375 | |||
2376 | /** |
||
2377 | * g_object_get_property: |
||
2378 | * @object: a #GObject |
||
2379 | * @property_name: the name of the property to get |
||
2380 | * @value: return location for the property value |
||
2381 | * |
||
2382 | * Gets a property of an object. @value must have been initialized to the |
||
2383 | * expected type of the property (or a type to which the expected type can be |
||
2384 | * transformed) using g_value_init(). |
||
2385 | * |
||
2386 | * In general, a copy is made of the property contents and the caller is |
||
2387 | * responsible for freeing the memory by calling g_value_unset(). |
||
2388 | * |
||
2389 | * Note that g_object_get_property() is really intended for language |
||
2390 | * bindings, g_object_get() is much more convenient for C programming. |
||
2391 | */ |
||
2392 | void |
||
2393 | g_object_get_property (GObject *object, |
||
2394 | const gchar *property_name, |
||
2395 | GValue *value) |
||
2396 | { |
||
2397 | GParamSpec *pspec; |
||
2398 | |||
2399 | g_return_if_fail (G_IS_OBJECT (object)); |
||
2400 | g_return_if_fail (property_name != NULL); |
||
2401 | g_return_if_fail (G_IS_VALUE (value)); |
||
2402 | |||
2403 | g_object_ref (object); |
||
2404 | |||
2405 | pspec = g_param_spec_pool_lookup (pspec_pool, |
||
2406 | property_name, |
||
2407 | G_OBJECT_TYPE (object), |
||
2408 | TRUE); |
||
2409 | if (!pspec) |
||
2410 | g_warning ("%s: object class '%s' has no property named '%s'", |
||
2411 | G_STRFUNC, |
||
2412 | G_OBJECT_TYPE_NAME (object), |
||
2413 | property_name); |
||
2414 | else if (!(pspec->flags & G_PARAM_READABLE)) |
||
2415 | g_warning ("%s: property '%s' of object class '%s' is not readable", |
||
2416 | G_STRFUNC, |
||
2417 | pspec->name, |
||
2418 | G_OBJECT_TYPE_NAME (object)); |
||
2419 | else |
||
2420 | { |
||
2421 | GValue *prop_value, tmp_value = G_VALUE_INIT; |
||
2422 | |||
2423 | /* auto-conversion of the callers value type |
||
2424 | */ |
||
2425 | if (G_VALUE_TYPE (value) == pspec->value_type) |
||
2426 | { |
||
2427 | g_value_reset (value); |
||
2428 | prop_value = value; |
||
2429 | } |
||
2430 | else if (!g_value_type_transformable (pspec->value_type, G_VALUE_TYPE (value))) |
||
2431 | { |
||
2432 | g_warning ("%s: can't retrieve property '%s' of type '%s' as value of type '%s'", |
||
2433 | G_STRFUNC, pspec->name, |
||
2434 | g_type_name (pspec->value_type), |
||
2435 | G_VALUE_TYPE_NAME (value)); |
||
2436 | g_object_unref (object); |
||
2437 | return; |
||
2438 | } |
||
2439 | else |
||
2440 | { |
||
2441 | g_value_init (&tmp_value, pspec->value_type); |
||
2442 | prop_value = &tmp_value; |
||
2443 | } |
||
2444 | object_get_property (object, pspec, prop_value); |
||
2445 | if (prop_value != value) |
||
2446 | { |
||
2447 | g_value_transform (prop_value, value); |
||
2448 | g_value_unset (&tmp_value); |
||
2449 | } |
||
2450 | } |
||
2451 | |||
2452 | g_object_unref (object); |
||
2453 | } |
||
2454 | |||
2455 | /** |
||
2456 | * g_object_connect: (skip) |
||
2457 | * @object: (type GObject.Object): a #GObject |
||
2458 | * @signal_spec: the spec for the first signal |
||
2459 | * @...: #GCallback for the first signal, followed by data for the |
||
2460 | * first signal, followed optionally by more signal |
||
2461 | * spec/callback/data triples, followed by %NULL |
||
2462 | * |
||
2463 | * A convenience function to connect multiple signals at once. |
||
2464 | * |
||
2465 | * The signal specs expected by this function have the form |
||
2466 | * "modifier::signal_name", where modifier can be one of the following: |
||
2467 | * * - signal: equivalent to g_signal_connect_data (..., NULL, 0) |
||
2468 | * - object-signal, object_signal: equivalent to g_signal_connect_object (..., 0) |
||
2469 | * - swapped-signal, swapped_signal: equivalent to g_signal_connect_data (..., NULL, G_CONNECT_SWAPPED) |
||
2470 | * - swapped_object_signal, swapped-object-signal: equivalent to g_signal_connect_object (..., G_CONNECT_SWAPPED) |
||
2471 | * - signal_after, signal-after: equivalent to g_signal_connect_data (..., NULL, G_CONNECT_AFTER) |
||
2472 | * - object_signal_after, object-signal-after: equivalent to g_signal_connect_object (..., G_CONNECT_AFTER) |
||
2473 | * - swapped_signal_after, swapped-signal-after: equivalent to g_signal_connect_data (..., NULL, G_CONNECT_SWAPPED | G_CONNECT_AFTER) |
||
2474 | * - swapped_object_signal_after, swapped-object-signal-after: equivalent to g_signal_connect_object (..., G_CONNECT_SWAPPED | G_CONNECT_AFTER) |
||
2475 | * |
||
2476 | * |[<!-- language="C" --> |
||
2477 | * menu->toplevel = g_object_connect (g_object_new (GTK_TYPE_WINDOW, |
||
2478 | * "type", GTK_WINDOW_POPUP, |
||
2479 | * "child", menu, |
||
2480 | * NULL), |
||
2481 | * "signal::event", gtk_menu_window_event, menu, |
||
2482 | * "signal::size_request", gtk_menu_window_size_request, menu, |
||
2483 | * "signal::destroy", gtk_widget_destroyed, &menu->toplevel, |
||
2484 | * NULL); |
||
2485 | * ]| |
||
2486 | * |
||
2487 | * Returns: (transfer none) (type GObject.Object): @object |
||
2488 | */ |
||
2489 | gpointer |
||
2490 | g_object_connect (gpointer _object, |
||
2491 | const gchar *signal_spec, |
||
2492 | ...) |
||
2493 | { |
||
2494 | GObject *object = _object; |
||
2495 | va_list var_args; |
||
2496 | |||
2497 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
||
2498 | g_return_val_if_fail (object->ref_count > 0, object); |
||
2499 | |||
2500 | va_start (var_args, signal_spec); |
||
2501 | while (signal_spec) |
||
2502 | { |
||
2503 | GCallback callback = va_arg (var_args, GCallback); |
||
2504 | gpointer data = va_arg (var_args, gpointer); |
||
2505 | |||
2506 | if (strncmp (signal_spec, "signal::", 8) == 0) |
||
2507 | g_signal_connect_data (object, signal_spec + 8, |
||
2508 | callback, data, NULL, |
||
2509 | 0); |
||
2510 | else if (strncmp (signal_spec, "object_signal::", 15) == 0 || |
||
2511 | strncmp (signal_spec, "object-signal::", 15) == 0) |
||
2512 | g_signal_connect_object (object, signal_spec + 15, |
||
2513 | callback, data, |
||
2514 | 0); |
||
2515 | else if (strncmp (signal_spec, "swapped_signal::", 16) == 0 || |
||
2516 | strncmp (signal_spec, "swapped-signal::", 16) == 0) |
||
2517 | g_signal_connect_data (object, signal_spec + 16, |
||
2518 | callback, data, NULL, |
||
2519 | G_CONNECT_SWAPPED); |
||
2520 | else if (strncmp (signal_spec, "swapped_object_signal::", 23) == 0 || |
||
2521 | strncmp (signal_spec, "swapped-object-signal::", 23) == 0) |
||
2522 | g_signal_connect_object (object, signal_spec + 23, |
||
2523 | callback, data, |
||
2524 | G_CONNECT_SWAPPED); |
||
2525 | else if (strncmp (signal_spec, "signal_after::", 14) == 0 || |
||
2526 | strncmp (signal_spec, "signal-after::", 14) == 0) |
||
2527 | g_signal_connect_data (object, signal_spec + 14, |
||
2528 | callback, data, NULL, |
||
2529 | G_CONNECT_AFTER); |
||
2530 | else if (strncmp (signal_spec, "object_signal_after::", 21) == 0 || |
||
2531 | strncmp (signal_spec, "object-signal-after::", 21) == 0) |
||
2532 | g_signal_connect_object (object, signal_spec + 21, |
||
2533 | callback, data, |
||
2534 | G_CONNECT_AFTER); |
||
2535 | else if (strncmp (signal_spec, "swapped_signal_after::", 22) == 0 || |
||
2536 | strncmp (signal_spec, "swapped-signal-after::", 22) == 0) |
||
2537 | g_signal_connect_data (object, signal_spec + 22, |
||
2538 | callback, data, NULL, |
||
2539 | G_CONNECT_SWAPPED | G_CONNECT_AFTER); |
||
2540 | else if (strncmp (signal_spec, "swapped_object_signal_after::", 29) == 0 || |
||
2541 | strncmp (signal_spec, "swapped-object-signal-after::", 29) == 0) |
||
2542 | g_signal_connect_object (object, signal_spec + 29, |
||
2543 | callback, data, |
||
2544 | G_CONNECT_SWAPPED | G_CONNECT_AFTER); |
||
2545 | else |
||
2546 | { |
||
2547 | g_warning ("%s: invalid signal spec \"%s\"", G_STRFUNC, signal_spec); |
||
2548 | break; |
||
2549 | } |
||
2550 | signal_spec = va_arg (var_args, gchar*); |
||
2551 | } |
||
2552 | va_end (var_args); |
||
2553 | |||
2554 | return object; |
||
2555 | } |
||
2556 | |||
2557 | /** |
||
2558 | * g_object_disconnect: (skip) |
||
2559 | * @object: (type GObject.Object): a #GObject |
||
2560 | * @signal_spec: the spec for the first signal |
||
2561 | * @...: #GCallback for the first signal, followed by data for the first signal, |
||
2562 | * followed optionally by more signal spec/callback/data triples, |
||
2563 | * followed by %NULL |
||
2564 | * |
||
2565 | * A convenience function to disconnect multiple signals at once. |
||
2566 | * |
||
2567 | * The signal specs expected by this function have the form |
||
2568 | * "any_signal", which means to disconnect any signal with matching |
||
2569 | * callback and data, or "any_signal::signal_name", which only |
||
2570 | * disconnects the signal named "signal_name". |
||
2571 | */ |
||
2572 | void |
||
2573 | g_object_disconnect (gpointer _object, |
||
2574 | const gchar *signal_spec, |
||
2575 | ...) |
||
2576 | { |
||
2577 | GObject *object = _object; |
||
2578 | va_list var_args; |
||
2579 | |||
2580 | g_return_if_fail (G_IS_OBJECT (object)); |
||
2581 | g_return_if_fail (object->ref_count > 0); |
||
2582 | |||
2583 | va_start (var_args, signal_spec); |
||
2584 | while (signal_spec) |
||
2585 | { |
||
2586 | GCallback callback = va_arg (var_args, GCallback); |
||
2587 | gpointer data = va_arg (var_args, gpointer); |
||
2588 | guint sid = 0, detail = 0, mask = 0; |
||
2589 | |||
2590 | if (strncmp (signal_spec, "any_signal::", 12) == 0 || |
||
2591 | strncmp (signal_spec, "any-signal::", 12) == 0) |
||
2592 | { |
||
2593 | signal_spec += 12; |
||
2594 | mask = G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA; |
||
2595 | } |
||
2596 | else if (strcmp (signal_spec, "any_signal") == 0 || |
||
2597 | strcmp (signal_spec, "any-signal") == 0) |
||
2598 | { |
||
2599 | signal_spec += 10; |
||
2600 | mask = G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA; |
||
2601 | } |
||
2602 | else |
||
2603 | { |
||
2604 | g_warning ("%s: invalid signal spec \"%s\"", G_STRFUNC, signal_spec); |
||
2605 | break; |
||
2606 | } |
||
2607 | |||
2608 | if ((mask & G_SIGNAL_MATCH_ID) && |
||
2609 | !g_signal_parse_name (signal_spec, G_OBJECT_TYPE (object), &sid, &detail, FALSE)) |
||
2610 | g_warning ("%s: invalid signal name \"%s\"", G_STRFUNC, signal_spec); |
||
2611 | else if (!g_signal_handlers_disconnect_matched (object, mask | (detail ? G_SIGNAL_MATCH_DETAIL : 0), |
||
2612 | sid, detail, |
||
2613 | NULL, (gpointer)callback, data)) |
||
2614 | g_warning ("%s: signal handler %p(%p) is not connected", G_STRFUNC, callback, data); |
||
2615 | signal_spec = va_arg (var_args, gchar*); |
||
2616 | } |
||
2617 | va_end (var_args); |
||
2618 | } |
||
2619 | |||
2620 | typedef struct { |
||
2621 | GObject *object; |
||
2622 | guint n_weak_refs; |
||
2623 | struct { |
||
2624 | GWeakNotify notify; |
||
2625 | gpointer data; |
||
2626 | } weak_refs[1]; /* flexible array */ |
||
2627 | } WeakRefStack; |
||
2628 | |||
2629 | static void |
||
2630 | weak_refs_notify (gpointer data) |
||
2631 | { |
||
2632 | WeakRefStack *wstack = data; |
||
2633 | guint i; |
||
2634 | |||
2635 | for (i = 0; i < wstack->n_weak_refs; i++) |
||
2636 | wstack->weak_refs[i].notify (wstack->weak_refs[i].data, wstack->object); |
||
2637 | g_free (wstack); |
||
2638 | } |
||
2639 | |||
2640 | /** |
||
2641 | * g_object_weak_ref: (skip) |
||
2642 | * @object: #GObject to reference weakly |
||
2643 | * @notify: callback to invoke before the object is freed |
||
2644 | * @data: extra data to pass to notify |
||
2645 | * |
||
2646 | * Adds a weak reference callback to an object. Weak references are |
||
2647 | * used for notification when an object is finalized. They are called |
||
2648 | * "weak references" because they allow you to safely hold a pointer |
||
2649 | * to an object without calling g_object_ref() (g_object_ref() adds a |
||
2650 | * strong reference, that is, forces the object to stay alive). |
||
2651 | * |
||
2652 | * Note that the weak references created by this method are not |
||
2653 | * thread-safe: they cannot safely be used in one thread if the |
||
2654 | * object's last g_object_unref() might happen in another thread. |
||
2655 | * Use #GWeakRef if thread-safety is required. |
||
2656 | */ |
||
2657 | void |
||
2658 | g_object_weak_ref (GObject *object, |
||
2659 | GWeakNotify notify, |
||
2660 | gpointer data) |
||
2661 | { |
||
2662 | WeakRefStack *wstack; |
||
2663 | guint i; |
||
2664 | |||
2665 | g_return_if_fail (G_IS_OBJECT (object)); |
||
2666 | g_return_if_fail (notify != NULL); |
||
2667 | g_return_if_fail (object->ref_count >= 1); |
||
2668 | |||
2669 | G_LOCK (weak_refs_mutex); |
||
2670 | wstack = g_datalist_id_remove_no_notify (&object->qdata, quark_weak_refs); |
||
2671 | if (wstack) |
||
2672 | { |
||
2673 | i = wstack->n_weak_refs++; |
||
2674 | wstack = g_realloc (wstack, sizeof (*wstack) + sizeof (wstack->weak_refs[0]) * i); |
||
2675 | } |
||
2676 | else |
||
2677 | { |
||
2678 | wstack = g_renew (WeakRefStack, NULL, 1); |
||
2679 | wstack->object = object; |
||
2680 | wstack->n_weak_refs = 1; |
||
2681 | i = 0; |
||
2682 | } |
||
2683 | wstack->weak_refs[i].notify = notify; |
||
2684 | wstack->weak_refs[i].data = data; |
||
2685 | g_datalist_id_set_data_full (&object->qdata, quark_weak_refs, wstack, weak_refs_notify); |
||
2686 | G_UNLOCK (weak_refs_mutex); |
||
2687 | } |
||
2688 | |||
2689 | /** |
||
2690 | * g_object_weak_unref: (skip) |
||
2691 | * @object: #GObject to remove a weak reference from |
||
2692 | * @notify: callback to search for |
||
2693 | * @data: data to search for |
||
2694 | * |
||
2695 | * Removes a weak reference callback to an object. |
||
2696 | */ |
||
2697 | void |
||
2698 | g_object_weak_unref (GObject *object, |
||
2699 | GWeakNotify notify, |
||
2700 | gpointer data) |
||
2701 | { |
||
2702 | WeakRefStack *wstack; |
||
2703 | gboolean found_one = FALSE; |
||
2704 | |||
2705 | g_return_if_fail (G_IS_OBJECT (object)); |
||
2706 | g_return_if_fail (notify != NULL); |
||
2707 | |||
2708 | G_LOCK (weak_refs_mutex); |
||
2709 | wstack = g_datalist_id_get_data (&object->qdata, quark_weak_refs); |
||
2710 | if (wstack) |
||
2711 | { |
||
2712 | guint i; |
||
2713 | |||
2714 | for (i = 0; i < wstack->n_weak_refs; i++) |
||
2715 | if (wstack->weak_refs[i].notify == notify && |
||
2716 | wstack->weak_refs[i].data == data) |
||
2717 | { |
||
2718 | found_one = TRUE; |
||
2719 | wstack->n_weak_refs -= 1; |
||
2720 | if (i != wstack->n_weak_refs) |
||
2721 | wstack->weak_refs[i] = wstack->weak_refs[wstack->n_weak_refs]; |
||
2722 | |||
2723 | break; |
||
2724 | } |
||
2725 | } |
||
2726 | G_UNLOCK (weak_refs_mutex); |
||
2727 | if (!found_one) |
||
2728 | g_warning ("%s: couldn't find weak ref %p(%p)", G_STRFUNC, notify, data); |
||
2729 | } |
||
2730 | |||
2731 | /** |
||
2732 | * g_object_add_weak_pointer: (skip) |
||
2733 | * @object: The object that should be weak referenced. |
||
2734 | * @weak_pointer_location: (inout) (not optional) (nullable): The memory address |
||
2735 | * of a pointer. |
||
2736 | * |
||
2737 | * Adds a weak reference from weak_pointer to @object to indicate that |
||
2738 | * the pointer located at @weak_pointer_location is only valid during |
||
2739 | * the lifetime of @object. When the @object is finalized, |
||
2740 | * @weak_pointer will be set to %NULL. |
||
2741 | * |
||
2742 | * Note that as with g_object_weak_ref(), the weak references created by |
||
2743 | * this method are not thread-safe: they cannot safely be used in one |
||
2744 | * thread if the object's last g_object_unref() might happen in another |
||
2745 | * thread. Use #GWeakRef if thread-safety is required. |
||
2746 | */ |
||
2747 | void |
||
2748 | g_object_add_weak_pointer (GObject *object, |
||
2749 | gpointer *weak_pointer_location) |
||
2750 | { |
||
2751 | g_return_if_fail (G_IS_OBJECT (object)); |
||
2752 | g_return_if_fail (weak_pointer_location != NULL); |
||
2753 | |||
2754 | g_object_weak_ref (object, |
||
2755 | (GWeakNotify) g_nullify_pointer, |
||
2756 | weak_pointer_location); |
||
2757 | } |
||
2758 | |||
2759 | /** |
||
2760 | * g_object_remove_weak_pointer: (skip) |
||
2761 | * @object: The object that is weak referenced. |
||
2762 | * @weak_pointer_location: (inout) (not optional) (nullable): The memory address |
||
2763 | * of a pointer. |
||
2764 | * |
||
2765 | * Removes a weak reference from @object that was previously added |
||
2766 | * using g_object_add_weak_pointer(). The @weak_pointer_location has |
||
2767 | * to match the one used with g_object_add_weak_pointer(). |
||
2768 | */ |
||
2769 | void |
||
2770 | g_object_remove_weak_pointer (GObject *object, |
||
2771 | gpointer *weak_pointer_location) |
||
2772 | { |
||
2773 | g_return_if_fail (G_IS_OBJECT (object)); |
||
2774 | g_return_if_fail (weak_pointer_location != NULL); |
||
2775 | |||
2776 | g_object_weak_unref (object, |
||
2777 | (GWeakNotify) g_nullify_pointer, |
||
2778 | weak_pointer_location); |
||
2779 | } |
||
2780 | |||
2781 | static guint |
||
2782 | object_floating_flag_handler (GObject *object, |
||
2783 | gint job) |
||
2784 | { |
||
2785 | switch (job) |
||
2786 | { |
||
2787 | gpointer oldvalue; |
||
2788 | case +1: /* force floating if possible */ |
||
2789 | do |
||
2790 | oldvalue = g_atomic_pointer_get (&object->qdata); |
||
2791 | while (!g_atomic_pointer_compare_and_exchange ((void**) &object->qdata, oldvalue, |
||
2792 | (gpointer) ((gsize) oldvalue | OBJECT_FLOATING_FLAG))); |
||
2793 | return (gsize) oldvalue & OBJECT_FLOATING_FLAG; |
||
2794 | case -1: /* sink if possible */ |
||
2795 | do |
||
2796 | oldvalue = g_atomic_pointer_get (&object->qdata); |
||
2797 | while (!g_atomic_pointer_compare_and_exchange ((void**) &object->qdata, oldvalue, |
||
2798 | (gpointer) ((gsize) oldvalue & ~(gsize) OBJECT_FLOATING_FLAG))); |
||
2799 | return (gsize) oldvalue & OBJECT_FLOATING_FLAG; |
||
2800 | default: /* check floating */ |
||
2801 | return 0 != ((gsize) g_atomic_pointer_get (&object->qdata) & OBJECT_FLOATING_FLAG); |
||
2802 | } |
||
2803 | } |
||
2804 | |||
2805 | /** |
||
2806 | * g_object_is_floating: |
||
2807 | * @object: (type GObject.Object): a #GObject |
||
2808 | * |
||
2809 | * Checks whether @object has a [floating][floating-ref] reference. |
||
2810 | * |
||
2811 | * Since: 2.10 |
||
2812 | * |
||
2813 | * Returns: %TRUE if @object has a floating reference |
||
2814 | */ |
||
2815 | gboolean |
||
2816 | g_object_is_floating (gpointer _object) |
||
2817 | { |
||
2818 | GObject *object = _object; |
||
2819 | g_return_val_if_fail (G_IS_OBJECT (object), FALSE); |
||
2820 | return floating_flag_handler (object, 0); |
||
2821 | } |
||
2822 | |||
2823 | /** |
||
2824 | * g_object_ref_sink: |
||
2825 | * @object: (type GObject.Object): a #GObject |
||
2826 | * |
||
2827 | * Increase the reference count of @object, and possibly remove the |
||
2828 | * [floating][floating-ref] reference, if @object has a floating reference. |
||
2829 | * |
||
2830 | * In other words, if the object is floating, then this call "assumes |
||
2831 | * ownership" of the floating reference, converting it to a normal |
||
2832 | * reference by clearing the floating flag while leaving the reference |
||
2833 | * count unchanged. If the object is not floating, then this call |
||
2834 | * adds a new normal reference increasing the reference count by one. |
||
2835 | * |
||
2836 | * Since: 2.10 |
||
2837 | * |
||
2838 | * Returns: (type GObject.Object) (transfer none): @object |
||
2839 | */ |
||
2840 | gpointer |
||
2841 | g_object_ref_sink (gpointer _object) |
||
2842 | { |
||
2843 | GObject *object = _object; |
||
2844 | gboolean was_floating; |
||
2845 | g_return_val_if_fail (G_IS_OBJECT (object), object); |
||
2846 | g_return_val_if_fail (object->ref_count >= 1, object); |
||
2847 | g_object_ref (object); |
||
2848 | was_floating = floating_flag_handler (object, -1); |
||
2849 | if (was_floating) |
||
2850 | g_object_unref (object); |
||
2851 | return object; |
||
2852 | } |
||
2853 | |||
2854 | /** |
||
2855 | * g_object_force_floating: |
||
2856 | * @object: a #GObject |
||
2857 | * |
||
2858 | * This function is intended for #GObject implementations to re-enforce |
||
2859 | * a [floating][floating-ref] object reference. Doing this is seldom |
||
2860 | * required: all #GInitiallyUnowneds are created with a floating reference |
||
2861 | * which usually just needs to be sunken by calling g_object_ref_sink(). |
||
2862 | * |
||
2863 | * Since: 2.10 |
||
2864 | */ |
||
2865 | void |
||
2866 | g_object_force_floating (GObject *object) |
||
2867 | { |
||
2868 | g_return_if_fail (G_IS_OBJECT (object)); |
||
2869 | g_return_if_fail (object->ref_count >= 1); |
||
2870 | |||
2871 | floating_flag_handler (object, +1); |
||
2872 | } |
||
2873 | |||
2874 | typedef struct { |
||
2875 | GObject *object; |
||
2876 | guint n_toggle_refs; |
||
2877 | struct { |
||
2878 | GToggleNotify notify; |
||
2879 | gpointer data; |
||
2880 | } toggle_refs[1]; /* flexible array */ |
||
2881 | } ToggleRefStack; |
||
2882 | |||
2883 | static void |
||
2884 | toggle_refs_notify (GObject *object, |
||
2885 | gboolean is_last_ref) |
||
2886 | { |
||
2887 | ToggleRefStack tstack, *tstackptr; |
||
2888 | |||
2889 | G_LOCK (toggle_refs_mutex); |
||
2890 | tstackptr = g_datalist_id_get_data (&object->qdata, quark_toggle_refs); |
||
2891 | tstack = *tstackptr; |
||
2892 | G_UNLOCK (toggle_refs_mutex); |
||
2893 | |||
2894 | /* Reentrancy here is not as tricky as it seems, because a toggle reference |
||
2895 | * will only be notified when there is exactly one of them. |
||
2896 | */ |
||
2897 | g_assert (tstack.n_toggle_refs == 1); |
||
2898 | tstack.toggle_refs[0].notify (tstack.toggle_refs[0].data, tstack.object, is_last_ref); |
||
2899 | } |
||
2900 | |||
2901 | /** |
||
2902 | * g_object_add_toggle_ref: (skip) |
||
2903 | * @object: a #GObject |
||
2904 | * @notify: a function to call when this reference is the |
||
2905 | * last reference to the object, or is no longer |
||
2906 | * the last reference. |
||
2907 | * @data: data to pass to @notify |
||
2908 | * |
||
2909 | * Increases the reference count of the object by one and sets a |
||
2910 | * callback to be called when all other references to the object are |
||
2911 | * dropped, or when this is already the last reference to the object |
||
2912 | * and another reference is established. |
||
2913 | * |
||
2914 | * This functionality is intended for binding @object to a proxy |
||
2915 | * object managed by another memory manager. This is done with two |
||
2916 | * paired references: the strong reference added by |
||
2917 | * g_object_add_toggle_ref() and a reverse reference to the proxy |
||
2918 | * object which is either a strong reference or weak reference. |
||
2919 | * |
||
2920 | * The setup is that when there are no other references to @object, |
||
2921 | * only a weak reference is held in the reverse direction from @object |
||
2922 | * to the proxy object, but when there are other references held to |
||
2923 | * @object, a strong reference is held. The @notify callback is called |
||
2924 | * when the reference from @object to the proxy object should be |
||
2925 | * "toggled" from strong to weak (@is_last_ref true) or weak to strong |
||
2926 | * (@is_last_ref false). |
||
2927 | * |
||
2928 | * Since a (normal) reference must be held to the object before |
||
2929 | * calling g_object_add_toggle_ref(), the initial state of the reverse |
||
2930 | * link is always strong. |
||
2931 | * |
||
2932 | * Multiple toggle references may be added to the same gobject, |
||
2933 | * however if there are multiple toggle references to an object, none |
||
2934 | * of them will ever be notified until all but one are removed. For |
||
2935 | * this reason, you should only ever use a toggle reference if there |
||
2936 | * is important state in the proxy object. |
||
2937 | * |
||
2938 | * Since: 2.8 |
||
2939 | */ |
||
2940 | void |
||
2941 | g_object_add_toggle_ref (GObject *object, |
||
2942 | GToggleNotify notify, |
||
2943 | gpointer data) |
||
2944 | { |
||
2945 | ToggleRefStack *tstack; |
||
2946 | guint i; |
||
2947 | |||
2948 | g_return_if_fail (G_IS_OBJECT (object)); |
||
2949 | g_return_if_fail (notify != NULL); |
||
2950 | g_return_if_fail (object->ref_count >= 1); |
||
2951 | |||
2952 | g_object_ref (object); |
||
2953 | |||
2954 | G_LOCK (toggle_refs_mutex); |
||
2955 | tstack = g_datalist_id_remove_no_notify (&object->qdata, quark_toggle_refs); |
||
2956 | if (tstack) |
||
2957 | { |
||
2958 | i = tstack->n_toggle_refs++; |
||
2959 | /* allocate i = tstate->n_toggle_refs - 1 positions beyond the 1 declared |
||
2960 | * in tstate->toggle_refs */ |
||
2961 | tstack = g_realloc (tstack, sizeof (*tstack) + sizeof (tstack->toggle_refs[0]) * i); |
||
2962 | } |
||
2963 | else |
||
2964 | { |
||
2965 | tstack = g_renew (ToggleRefStack, NULL, 1); |
||
2966 | tstack->object = object; |
||
2967 | tstack->n_toggle_refs = 1; |
||
2968 | i = 0; |
||
2969 | } |
||
2970 | |||
2971 | /* Set a flag for fast lookup after adding the first toggle reference */ |
||
2972 | if (tstack->n_toggle_refs == 1) |
||
2973 | g_datalist_set_flags (&object->qdata, OBJECT_HAS_TOGGLE_REF_FLAG); |
||
2974 | |||
2975 | tstack->toggle_refs[i].notify = notify; |
||
2976 | tstack->toggle_refs[i].data = data; |
||
2977 | g_datalist_id_set_data_full (&object->qdata, quark_toggle_refs, tstack, |
||
2978 | (GDestroyNotify)g_free); |
||
2979 | G_UNLOCK (toggle_refs_mutex); |
||
2980 | } |
||
2981 | |||
2982 | /** |
||
2983 | * g_object_remove_toggle_ref: (skip) |
||
2984 | * @object: a #GObject |
||
2985 | * @notify: a function to call when this reference is the |
||
2986 | * last reference to the object, or is no longer |
||
2987 | * the last reference. |
||
2988 | * @data: data to pass to @notify |
||
2989 | * |
||
2990 | * Removes a reference added with g_object_add_toggle_ref(). The |
||
2991 | * reference count of the object is decreased by one. |
||
2992 | * |
||
2993 | * Since: 2.8 |
||
2994 | */ |
||
2995 | void |
||
2996 | g_object_remove_toggle_ref (GObject *object, |
||
2997 | GToggleNotify notify, |
||
2998 | gpointer data) |
||
2999 | { |
||
3000 | ToggleRefStack *tstack; |
||
3001 | gboolean found_one = FALSE; |
||
3002 | |||
3003 | g_return_if_fail (G_IS_OBJECT (object)); |
||
3004 | g_return_if_fail (notify != NULL); |
||
3005 | |||
3006 | G_LOCK (toggle_refs_mutex); |
||
3007 | tstack = g_datalist_id_get_data (&object->qdata, quark_toggle_refs); |
||
3008 | if (tstack) |
||
3009 | { |
||
3010 | guint i; |
||
3011 | |||
3012 | for (i = 0; i < tstack->n_toggle_refs; i++) |
||
3013 | if (tstack->toggle_refs[i].notify == notify && |
||
3014 | tstack->toggle_refs[i].data == data) |
||
3015 | { |
||
3016 | found_one = TRUE; |
||
3017 | tstack->n_toggle_refs -= 1; |
||
3018 | if (i != tstack->n_toggle_refs) |
||
3019 | tstack->toggle_refs[i] = tstack->toggle_refs[tstack->n_toggle_refs]; |
||
3020 | |||
3021 | if (tstack->n_toggle_refs == 0) |
||
3022 | g_datalist_unset_flags (&object->qdata, OBJECT_HAS_TOGGLE_REF_FLAG); |
||
3023 | |||
3024 | break; |
||
3025 | } |
||
3026 | } |
||
3027 | G_UNLOCK (toggle_refs_mutex); |
||
3028 | |||
3029 | if (found_one) |
||
3030 | g_object_unref (object); |
||
3031 | else |
||
3032 | g_warning ("%s: couldn't find toggle ref %p(%p)", G_STRFUNC, notify, data); |
||
3033 | } |
||
3034 | |||
3035 | /** |
||
3036 | * g_object_ref: |
||
3037 | * @object: (type GObject.Object): a #GObject |
||
3038 | * |
||
3039 | * Increases the reference count of @object. |
||
3040 | * |
||
3041 | * Returns: (type GObject.Object) (transfer none): the same @object |
||
3042 | */ |
||
3043 | gpointer |
||
3044 | g_object_ref (gpointer _object) |
||
3045 | { |
||
3046 | GObject *object = _object; |
||
3047 | gint old_val; |
||
3048 | |||
3049 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
||
3050 | g_return_val_if_fail (object->ref_count > 0, NULL); |
||
3051 | |||
3052 | old_val = g_atomic_int_add (&object->ref_count, 1); |
||
3053 | |||
3054 | if (old_val == 1 && OBJECT_HAS_TOGGLE_REF (object)) |
||
3055 | toggle_refs_notify (object, FALSE); |
||
3056 | |||
3057 | TRACE (GOBJECT_OBJECT_REF(object,G_TYPE_FROM_INSTANCE(object),old_val)); |
||
3058 | |||
3059 | return object; |
||
3060 | } |
||
3061 | |||
3062 | /** |
||
3063 | * g_object_unref: |
||
3064 | * @object: (type GObject.Object): a #GObject |
||
3065 | * |
||
3066 | * Decreases the reference count of @object. When its reference count |
||
3067 | * drops to 0, the object is finalized (i.e. its memory is freed). |
||
3068 | * |
||
3069 | * If the pointer to the #GObject may be reused in future (for example, if it is |
||
3070 | * an instance variable of another object), it is recommended to clear the |
||
3071 | * pointer to %NULL rather than retain a dangling pointer to a potentially |
||
3072 | * invalid #GObject instance. Use g_clear_object() for this. |
||
3073 | */ |
||
3074 | void |
||
3075 | g_object_unref (gpointer _object) |
||
3076 | { |
||
3077 | GObject *object = _object; |
||
3078 | gint old_ref; |
||
3079 | |||
3080 | g_return_if_fail (G_IS_OBJECT (object)); |
||
3081 | g_return_if_fail (object->ref_count > 0); |
||
3082 | |||
3083 | /* here we want to atomically do: if (ref_count>1) { ref_count--; return; } */ |
||
3084 | retry_atomic_decrement1: |
||
3085 | old_ref = g_atomic_int_get (&object->ref_count); |
||
3086 | if (old_ref > 1) |
||
3087 | { |
||
3088 | /* valid if last 2 refs are owned by this call to unref and the toggle_ref */ |
||
3089 | gboolean has_toggle_ref = OBJECT_HAS_TOGGLE_REF (object); |
||
3090 | |||
3091 | if (!g_atomic_int_compare_and_exchange ((int *)&object->ref_count, old_ref, old_ref - 1)) |
||
3092 | goto retry_atomic_decrement1; |
||
3093 | |||
3094 | TRACE (GOBJECT_OBJECT_UNREF(object,G_TYPE_FROM_INSTANCE(object),old_ref)); |
||
3095 | |||
3096 | /* if we went from 2->1 we need to notify toggle refs if any */ |
||
3097 | if (old_ref == 2 && has_toggle_ref) /* The last ref being held in this case is owned by the toggle_ref */ |
||
3098 | toggle_refs_notify (object, TRUE); |
||
3099 | } |
||
3100 | else |
||
3101 | { |
||
3102 | GSList **weak_locations; |
||
3103 | |||
3104 | /* The only way that this object can live at this point is if |
||
3105 | * there are outstanding weak references already established |
||
3106 | * before we got here. |
||
3107 | * |
||
3108 | * If there were not already weak references then no more can be |
||
3109 | * established at this time, because the other thread would have |
||
3110 | * to hold a strong ref in order to call |
||
3111 | * g_object_add_weak_pointer() and then we wouldn't be here. |
||
3112 | */ |
||
3113 | weak_locations = g_datalist_id_get_data (&object->qdata, quark_weak_locations); |
||
3114 | |||
3115 | if (weak_locations != NULL) |
||
3116 | { |
||
3117 | g_rw_lock_writer_lock (&weak_locations_lock); |
||
3118 | |||
3119 | /* It is possible that one of the weak references beat us to |
||
3120 | * the lock. Make sure the refcount is still what we expected |
||
3121 | * it to be. |
||
3122 | */ |
||
3123 | old_ref = g_atomic_int_get (&object->ref_count); |
||
3124 | if (old_ref != 1) |
||
3125 | { |
||
3126 | g_rw_lock_writer_unlock (&weak_locations_lock); |
||
3127 | goto retry_atomic_decrement1; |
||
3128 | } |
||
3129 | |||
3130 | /* We got the lock first, so the object will definitely die |
||
3131 | * now. Clear out all the weak references. |
||
3132 | */ |
||
3133 | while (*weak_locations) |
||
3134 | { |
||
3135 | GWeakRef *weak_ref_location = (*weak_locations)->data; |
||
3136 | |||
3137 | weak_ref_location->priv.p = NULL; |
||
3138 | *weak_locations = g_slist_delete_link (*weak_locations, *weak_locations); |
||
3139 | } |
||
3140 | |||
3141 | g_rw_lock_writer_unlock (&weak_locations_lock); |
||
3142 | } |
||
3143 | |||
3144 | /* we are about to remove the last reference */ |
||
3145 | TRACE (GOBJECT_OBJECT_DISPOSE(object,G_TYPE_FROM_INSTANCE(object), 1)); |
||
3146 | G_OBJECT_GET_CLASS (object)->dispose (object); |
||
3147 | TRACE (GOBJECT_OBJECT_DISPOSE_END(object,G_TYPE_FROM_INSTANCE(object), 1)); |
||
3148 | |||
3149 | /* may have been re-referenced meanwhile */ |
||
3150 | retry_atomic_decrement2: |
||
3151 | old_ref = g_atomic_int_get ((int *)&object->ref_count); |
||
3152 | if (old_ref > 1) |
||
3153 | { |
||
3154 | /* valid if last 2 refs are owned by this call to unref and the toggle_ref */ |
||
3155 | gboolean has_toggle_ref = OBJECT_HAS_TOGGLE_REF (object); |
||
3156 | |||
3157 | if (!g_atomic_int_compare_and_exchange ((int *)&object->ref_count, old_ref, old_ref - 1)) |
||
3158 | goto retry_atomic_decrement2; |
||
3159 | |||
3160 | TRACE (GOBJECT_OBJECT_UNREF(object,G_TYPE_FROM_INSTANCE(object),old_ref)); |
||
3161 | |||
3162 | /* if we went from 2->1 we need to notify toggle refs if any */ |
||
3163 | if (old_ref == 2 && has_toggle_ref) /* The last ref being held in this case is owned by the toggle_ref */ |
||
3164 | toggle_refs_notify (object, TRUE); |
||
3165 | |||
3166 | return; |
||
3167 | } |
||
3168 | |||
3169 | /* we are still in the process of taking away the last ref */ |
||
3170 | g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL); |
||
3171 | g_signal_handlers_destroy (object); |
||
3172 | g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL); |
||
3173 | |||
3174 | /* decrement the last reference */ |
||
3175 | old_ref = g_atomic_int_add (&object->ref_count, -1); |
||
3176 | |||
3177 | TRACE (GOBJECT_OBJECT_UNREF(object,G_TYPE_FROM_INSTANCE(object),old_ref)); |
||
3178 | |||
3179 | /* may have been re-referenced meanwhile */ |
||
3180 | if (G_LIKELY (old_ref == 1)) |
||
3181 | { |
||
3182 | TRACE (GOBJECT_OBJECT_FINALIZE(object,G_TYPE_FROM_INSTANCE(object))); |
||
3183 | G_OBJECT_GET_CLASS (object)->finalize (object); |
||
3184 | |||
3185 | TRACE (GOBJECT_OBJECT_FINALIZE_END(object,G_TYPE_FROM_INSTANCE(object))); |
||
3186 | |||
3187 | #ifdef G_ENABLE_DEBUG |
||
3188 | IF_DEBUG (OBJECTS) |
||
3189 | { |
||
3190 | /* catch objects not chaining finalize handlers */ |
||
3191 | G_LOCK (debug_objects); |
||
3192 | g_assert (g_hash_table_lookup (debug_objects_ht, object) == NULL); |
||
3193 | G_UNLOCK (debug_objects); |
||
3194 | } |
||
3195 | #endif /* G_ENABLE_DEBUG */ |
||
3196 | g_type_free_instance ((GTypeInstance*) object); |
||
3197 | } |
||
3198 | } |
||
3199 | } |
||
3200 | |||
3201 | /** |
||
3202 | * g_clear_object: (skip) |
||
3203 | * @object_ptr: a pointer to a #GObject reference |
||
3204 | * |
||
3205 | * Clears a reference to a #GObject. |
||
3206 | * |
||
3207 | * @object_ptr must not be %NULL. |
||
3208 | * |
||
3209 | * If the reference is %NULL then this function does nothing. |
||
3210 | * Otherwise, the reference count of the object is decreased and the |
||
3211 | * pointer is set to %NULL. |
||
3212 | * |
||
3213 | * A macro is also included that allows this function to be used without |
||
3214 | * pointer casts. |
||
3215 | * |
||
3216 | * Since: 2.28 |
||
3217 | **/ |
||
3218 | #undef g_clear_object |
||
3219 | void |
||
3220 | g_clear_object (volatile GObject **object_ptr) |
||
3221 | { |
||
3222 | g_clear_pointer (object_ptr, g_object_unref); |
||
3223 | } |
||
3224 | |||
3225 | /** |
||
3226 | * g_object_get_qdata: |
||
3227 | * @object: The GObject to get a stored user data pointer from |
||
3228 | * @quark: A #GQuark, naming the user data pointer |
||
3229 | * |
||
3230 | * This function gets back user data pointers stored via |
||
3231 | * g_object_set_qdata(). |
||
3232 | * |
||
3233 | * Returns: (transfer none): The user data pointer set, or %NULL |
||
3234 | */ |
||
3235 | gpointer |
||
3236 | g_object_get_qdata (GObject *object, |
||
3237 | GQuark quark) |
||
3238 | { |
||
3239 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
||
3240 | |||
3241 | return quark ? g_datalist_id_get_data (&object->qdata, quark) : NULL; |
||
3242 | } |
||
3243 | |||
3244 | /** |
||
3245 | * g_object_set_qdata: (skip) |
||
3246 | * @object: The GObject to set store a user data pointer |
||
3247 | * @quark: A #GQuark, naming the user data pointer |
||
3248 | * @data: An opaque user data pointer |
||
3249 | * |
||
3250 | * This sets an opaque, named pointer on an object. |
||
3251 | * The name is specified through a #GQuark (retrived e.g. via |
||
3252 | * g_quark_from_static_string()), and the pointer |
||
3253 | * can be gotten back from the @object with g_object_get_qdata() |
||
3254 | * until the @object is finalized. |
||
3255 | * Setting a previously set user data pointer, overrides (frees) |
||
3256 | * the old pointer set, using #NULL as pointer essentially |
||
3257 | * removes the data stored. |
||
3258 | */ |
||
3259 | void |
||
3260 | g_object_set_qdata (GObject *object, |
||
3261 | GQuark quark, |
||
3262 | gpointer data) |
||
3263 | { |
||
3264 | g_return_if_fail (G_IS_OBJECT (object)); |
||
3265 | g_return_if_fail (quark > 0); |
||
3266 | |||
3267 | g_datalist_id_set_data (&object->qdata, quark, data); |
||
3268 | } |
||
3269 | |||
3270 | /** |
||
3271 | * g_object_dup_qdata: |
||
3272 | * @object: the #GObject to store user data on |
||
3273 | * @quark: a #GQuark, naming the user data pointer |
||
3274 | * @dup_func: (allow-none): function to dup the value |
||
3275 | * @user_data: (allow-none): passed as user_data to @dup_func |
||
3276 | * |
||
3277 | * This is a variant of g_object_get_qdata() which returns |
||
3278 | * a 'duplicate' of the value. @dup_func defines the |
||
3279 | * meaning of 'duplicate' in this context, it could e.g. |
||
3280 | * take a reference on a ref-counted object. |
||
3281 | * |
||
3282 | * If the @quark is not set on the object then @dup_func |
||
3283 | * will be called with a %NULL argument. |
||
3284 | * |
||
3285 | * Note that @dup_func is called while user data of @object |
||
3286 | * is locked. |
||
3287 | * |
||
3288 | * This function can be useful to avoid races when multiple |
||
3289 | * threads are using object data on the same key on the same |
||
3290 | * object. |
||
3291 | * |
||
3292 | * Returns: the result of calling @dup_func on the value |
||
3293 | * associated with @quark on @object, or %NULL if not set. |
||
3294 | * If @dup_func is %NULL, the value is returned |
||
3295 | * unmodified. |
||
3296 | * |
||
3297 | * Since: 2.34 |
||
3298 | */ |
||
3299 | gpointer |
||
3300 | g_object_dup_qdata (GObject *object, |
||
3301 | GQuark quark, |
||
3302 | GDuplicateFunc dup_func, |
||
3303 | gpointer user_data) |
||
3304 | { |
||
3305 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
||
3306 | g_return_val_if_fail (quark > 0, NULL); |
||
3307 | |||
3308 | return g_datalist_id_dup_data (&object->qdata, quark, dup_func, user_data); |
||
3309 | } |
||
3310 | |||
3311 | /** |
||
3312 | * g_object_replace_qdata: |
||
3313 | * @object: the #GObject to store user data on |
||
3314 | * @quark: a #GQuark, naming the user data pointer |
||
3315 | * @oldval: (allow-none): the old value to compare against |
||
3316 | * @newval: (allow-none): the new value |
||
3317 | * @destroy: (allow-none): a destroy notify for the new value |
||
3318 | * @old_destroy: (allow-none): destroy notify for the existing value |
||
3319 | * |
||
3320 | * Compares the user data for the key @quark on @object with |
||
3321 | * @oldval, and if they are the same, replaces @oldval with |
||
3322 | * @newval. |
||
3323 | * |
||
3324 | * This is like a typical atomic compare-and-exchange |
||
3325 | * operation, for user data on an object. |
||
3326 | * |
||
3327 | * If the previous value was replaced then ownership of the |
||
3328 | * old value (@oldval) is passed to the caller, including |
||
3329 | * the registered destroy notify for it (passed out in @old_destroy). |
||
3330 | * Its up to the caller to free this as he wishes, which may |
||
3331 | * or may not include using @old_destroy as sometimes replacement |
||
3332 | * should not destroy the object in the normal way. |
||
3333 | * |
||
3334 | * Returns: %TRUE if the existing value for @quark was replaced |
||
3335 | * by @newval, %FALSE otherwise. |
||
3336 | * |
||
3337 | * Since: 2.34 |
||
3338 | */ |
||
3339 | gboolean |
||
3340 | g_object_replace_qdata (GObject *object, |
||
3341 | GQuark quark, |
||
3342 | gpointer oldval, |
||
3343 | gpointer newval, |
||
3344 | GDestroyNotify destroy, |
||
3345 | GDestroyNotify *old_destroy) |
||
3346 | { |
||
3347 | g_return_val_if_fail (G_IS_OBJECT (object), FALSE); |
||
3348 | g_return_val_if_fail (quark > 0, FALSE); |
||
3349 | |||
3350 | return g_datalist_id_replace_data (&object->qdata, quark, |
||
3351 | oldval, newval, destroy, |
||
3352 | old_destroy); |
||
3353 | } |
||
3354 | |||
3355 | /** |
||
3356 | * g_object_set_qdata_full: (skip) |
||
3357 | * @object: The GObject to set store a user data pointer |
||
3358 | * @quark: A #GQuark, naming the user data pointer |
||
3359 | * @data: An opaque user data pointer |
||
3360 | * @destroy: Function to invoke with @data as argument, when @data |
||
3361 | * needs to be freed |
||
3362 | * |
||
3363 | * This function works like g_object_set_qdata(), but in addition, |
||
3364 | * a void (*destroy) (gpointer) function may be specified which is |
||
3365 | * called with @data as argument when the @object is finalized, or |
||
3366 | * the data is being overwritten by a call to g_object_set_qdata() |
||
3367 | * with the same @quark. |
||
3368 | */ |
||
3369 | void |
||
3370 | g_object_set_qdata_full (GObject *object, |
||
3371 | GQuark quark, |
||
3372 | gpointer data, |
||
3373 | GDestroyNotify destroy) |
||
3374 | { |
||
3375 | g_return_if_fail (G_IS_OBJECT (object)); |
||
3376 | g_return_if_fail (quark > 0); |
||
3377 | |||
3378 | g_datalist_id_set_data_full (&object->qdata, quark, data, |
||
3379 | data ? destroy : (GDestroyNotify) NULL); |
||
3380 | } |
||
3381 | |||
3382 | /** |
||
3383 | * g_object_steal_qdata: |
||
3384 | * @object: The GObject to get a stored user data pointer from |
||
3385 | * @quark: A #GQuark, naming the user data pointer |
||
3386 | * |
||
3387 | * This function gets back user data pointers stored via |
||
3388 | * g_object_set_qdata() and removes the @data from object |
||
3389 | * without invoking its destroy() function (if any was |
||
3390 | * set). |
||
3391 | * Usually, calling this function is only required to update |
||
3392 | * user data pointers with a destroy notifier, for example: |
||
3393 | * |[<!-- language="C" --> |
||
3394 | * void |
||
3395 | * object_add_to_user_list (GObject *object, |
||
3396 | * const gchar *new_string) |
||
3397 | * { |
||
3398 | * // the quark, naming the object data |
||
3399 | * GQuark quark_string_list = g_quark_from_static_string ("my-string-list"); |
||
3400 | * // retrive the old string list |
||
3401 | * GList *list = g_object_steal_qdata (object, quark_string_list); |
||
3402 | * |
||
3403 | * // prepend new string |
||
3404 | * list = g_list_prepend (list, g_strdup (new_string)); |
||
3405 | * // this changed 'list', so we need to set it again |
||
3406 | * g_object_set_qdata_full (object, quark_string_list, list, free_string_list); |
||
3407 | * } |
||
3408 | * static void |
||
3409 | * free_string_list (gpointer data) |
||
3410 | * { |
||
3411 | * GList *node, *list = data; |
||
3412 | * |
||
3413 | * for (node = list; node; node = node->next) |
||
3414 | * g_free (node->data); |
||
3415 | * g_list_free (list); |
||
3416 | * } |
||
3417 | * ]| |
||
3418 | * Using g_object_get_qdata() in the above example, instead of |
||
3419 | * g_object_steal_qdata() would have left the destroy function set, |
||
3420 | * and thus the partial string list would have been freed upon |
||
3421 | * g_object_set_qdata_full(). |
||
3422 | * |
||
3423 | * Returns: (transfer full): The user data pointer set, or %NULL |
||
3424 | */ |
||
3425 | gpointer |
||
3426 | g_object_steal_qdata (GObject *object, |
||
3427 | GQuark quark) |
||
3428 | { |
||
3429 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
||
3430 | g_return_val_if_fail (quark > 0, NULL); |
||
3431 | |||
3432 | return g_datalist_id_remove_no_notify (&object->qdata, quark); |
||
3433 | } |
||
3434 | |||
3435 | /** |
||
3436 | * g_object_get_data: |
||
3437 | * @object: #GObject containing the associations |
||
3438 | * @key: name of the key for that association |
||
3439 | * |
||
3440 | * Gets a named field from the objects table of associations (see g_object_set_data()). |
||
3441 | * |
||
3442 | * Returns: (transfer none): the data if found, or %NULL if no such data exists. |
||
3443 | */ |
||
3444 | gpointer |
||
3445 | g_object_get_data (GObject *object, |
||
3446 | const gchar *key) |
||
3447 | { |
||
3448 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
||
3449 | g_return_val_if_fail (key != NULL, NULL); |
||
3450 | |||
3451 | return g_datalist_get_data (&object->qdata, key); |
||
3452 | } |
||
3453 | |||
3454 | /** |
||
3455 | * g_object_set_data: |
||
3456 | * @object: #GObject containing the associations. |
||
3457 | * @key: name of the key |
||
3458 | * @data: data to associate with that key |
||
3459 | * |
||
3460 | * Each object carries around a table of associations from |
||
3461 | * strings to pointers. This function lets you set an association. |
||
3462 | * |
||
3463 | * If the object already had an association with that name, |
||
3464 | * the old association will be destroyed. |
||
3465 | */ |
||
3466 | void |
||
3467 | g_object_set_data (GObject *object, |
||
3468 | const gchar *key, |
||
3469 | gpointer data) |
||
3470 | { |
||
3471 | g_return_if_fail (G_IS_OBJECT (object)); |
||
3472 | g_return_if_fail (key != NULL); |
||
3473 | |||
3474 | g_datalist_id_set_data (&object->qdata, g_quark_from_string (key), data); |
||
3475 | } |
||
3476 | |||
3477 | /** |
||
3478 | * g_object_dup_data: |
||
3479 | * @object: the #GObject to store user data on |
||
3480 | * @key: a string, naming the user data pointer |
||
3481 | * @dup_func: (allow-none): function to dup the value |
||
3482 | * @user_data: (allow-none): passed as user_data to @dup_func |
||
3483 | * |
||
3484 | * This is a variant of g_object_get_data() which returns |
||
3485 | * a 'duplicate' of the value. @dup_func defines the |
||
3486 | * meaning of 'duplicate' in this context, it could e.g. |
||
3487 | * take a reference on a ref-counted object. |
||
3488 | * |
||
3489 | * If the @key is not set on the object then @dup_func |
||
3490 | * will be called with a %NULL argument. |
||
3491 | * |
||
3492 | * Note that @dup_func is called while user data of @object |
||
3493 | * is locked. |
||
3494 | * |
||
3495 | * This function can be useful to avoid races when multiple |
||
3496 | * threads are using object data on the same key on the same |
||
3497 | * object. |
||
3498 | * |
||
3499 | * Returns: the result of calling @dup_func on the value |
||
3500 | * associated with @key on @object, or %NULL if not set. |
||
3501 | * If @dup_func is %NULL, the value is returned |
||
3502 | * unmodified. |
||
3503 | * |
||
3504 | * Since: 2.34 |
||
3505 | */ |
||
3506 | gpointer |
||
3507 | g_object_dup_data (GObject *object, |
||
3508 | const gchar *key, |
||
3509 | GDuplicateFunc dup_func, |
||
3510 | gpointer user_data) |
||
3511 | { |
||
3512 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
||
3513 | g_return_val_if_fail (key != NULL, NULL); |
||
3514 | |||
3515 | return g_datalist_id_dup_data (&object->qdata, |
||
3516 | g_quark_from_string (key), |
||
3517 | dup_func, user_data); |
||
3518 | } |
||
3519 | |||
3520 | /** |
||
3521 | * g_object_replace_data: |
||
3522 | * @object: the #GObject to store user data on |
||
3523 | * @key: a string, naming the user data pointer |
||
3524 | * @oldval: (allow-none): the old value to compare against |
||
3525 | * @newval: (allow-none): the new value |
||
3526 | * @destroy: (allow-none): a destroy notify for the new value |
||
3527 | * @old_destroy: (allow-none): destroy notify for the existing value |
||
3528 | * |
||
3529 | * Compares the user data for the key @key on @object with |
||
3530 | * @oldval, and if they are the same, replaces @oldval with |
||
3531 | * @newval. |
||
3532 | * |
||
3533 | * This is like a typical atomic compare-and-exchange |
||
3534 | * operation, for user data on an object. |
||
3535 | * |
||
3536 | * If the previous value was replaced then ownership of the |
||
3537 | * old value (@oldval) is passed to the caller, including |
||
3538 | * the registered destroy notify for it (passed out in @old_destroy). |
||
3539 | * Its up to the caller to free this as he wishes, which may |
||
3540 | * or may not include using @old_destroy as sometimes replacement |
||
3541 | * should not destroy the object in the normal way. |
||
3542 | * |
||
3543 | * Returns: %TRUE if the existing value for @key was replaced |
||
3544 | * by @newval, %FALSE otherwise. |
||
3545 | * |
||
3546 | * Since: 2.34 |
||
3547 | */ |
||
3548 | gboolean |
||
3549 | g_object_replace_data (GObject *object, |
||
3550 | const gchar *key, |
||
3551 | gpointer oldval, |
||
3552 | gpointer newval, |
||
3553 | GDestroyNotify destroy, |
||
3554 | GDestroyNotify *old_destroy) |
||
3555 | { |
||
3556 | g_return_val_if_fail (G_IS_OBJECT (object), FALSE); |
||
3557 | g_return_val_if_fail (key != NULL, FALSE); |
||
3558 | |||
3559 | return g_datalist_id_replace_data (&object->qdata, |
||
3560 | g_quark_from_string (key), |
||
3561 | oldval, newval, destroy, |
||
3562 | old_destroy); |
||
3563 | } |
||
3564 | |||
3565 | /** |
||
3566 | * g_object_set_data_full: (skip) |
||
3567 | * @object: #GObject containing the associations |
||
3568 | * @key: name of the key |
||
3569 | * @data: data to associate with that key |
||
3570 | * @destroy: function to call when the association is destroyed |
||
3571 | * |
||
3572 | * Like g_object_set_data() except it adds notification |
||
3573 | * for when the association is destroyed, either by setting it |
||
3574 | * to a different value or when the object is destroyed. |
||
3575 | * |
||
3576 | * Note that the @destroy callback is not called if @data is %NULL. |
||
3577 | */ |
||
3578 | void |
||
3579 | g_object_set_data_full (GObject *object, |
||
3580 | const gchar *key, |
||
3581 | gpointer data, |
||
3582 | GDestroyNotify destroy) |
||
3583 | { |
||
3584 | g_return_if_fail (G_IS_OBJECT (object)); |
||
3585 | g_return_if_fail (key != NULL); |
||
3586 | |||
3587 | g_datalist_id_set_data_full (&object->qdata, g_quark_from_string (key), data, |
||
3588 | data ? destroy : (GDestroyNotify) NULL); |
||
3589 | } |
||
3590 | |||
3591 | /** |
||
3592 | * g_object_steal_data: |
||
3593 | * @object: #GObject containing the associations |
||
3594 | * @key: name of the key |
||
3595 | * |
||
3596 | * Remove a specified datum from the object's data associations, |
||
3597 | * without invoking the association's destroy handler. |
||
3598 | * |
||
3599 | * Returns: (transfer full): the data if found, or %NULL if no such data exists. |
||
3600 | */ |
||
3601 | gpointer |
||
3602 | g_object_steal_data (GObject *object, |
||
3603 | const gchar *key) |
||
3604 | { |
||
3605 | GQuark quark; |
||
3606 | |||
3607 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
||
3608 | g_return_val_if_fail (key != NULL, NULL); |
||
3609 | |||
3610 | quark = g_quark_try_string (key); |
||
3611 | |||
3612 | return quark ? g_datalist_id_remove_no_notify (&object->qdata, quark) : NULL; |
||
3613 | } |
||
3614 | |||
3615 | static void |
||
3616 | g_value_object_init (GValue *value) |
||
3617 | { |
||
3618 | value->data[0].v_pointer = NULL; |
||
3619 | } |
||
3620 | |||
3621 | static void |
||
3622 | g_value_object_free_value (GValue *value) |
||
3623 | { |
||
3624 | if (value->data[0].v_pointer) |
||
3625 | g_object_unref (value->data[0].v_pointer); |
||
3626 | } |
||
3627 | |||
3628 | static void |
||
3629 | g_value_object_copy_value (const GValue *src_value, |
||
3630 | GValue *dest_value) |
||
3631 | { |
||
3632 | if (src_value->data[0].v_pointer) |
||
3633 | dest_value->data[0].v_pointer = g_object_ref (src_value->data[0].v_pointer); |
||
3634 | else |
||
3635 | dest_value->data[0].v_pointer = NULL; |
||
3636 | } |
||
3637 | |||
3638 | static void |
||
3639 | g_value_object_transform_value (const GValue *src_value, |
||
3640 | GValue *dest_value) |
||
3641 | { |
||
3642 | 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))) |
||
3643 | dest_value->data[0].v_pointer = g_object_ref (src_value->data[0].v_pointer); |
||
3644 | else |
||
3645 | dest_value->data[0].v_pointer = NULL; |
||
3646 | } |
||
3647 | |||
3648 | static gpointer |
||
3649 | g_value_object_peek_pointer (const GValue *value) |
||
3650 | { |
||
3651 | return value->data[0].v_pointer; |
||
3652 | } |
||
3653 | |||
3654 | static gchar* |
||
3655 | g_value_object_collect_value (GValue *value, |
||
3656 | guint n_collect_values, |
||
3657 | GTypeCValue *collect_values, |
||
3658 | guint collect_flags) |
||
3659 | { |
||
3660 | if (collect_values[0].v_pointer) |
||
3661 | { |
||
3662 | GObject *object = collect_values[0].v_pointer; |
||
3663 | |||
3664 | if (object->g_type_instance.g_class == NULL) |
||
3665 | return g_strconcat ("invalid unclassed object pointer for value type '", |
||
3666 | G_VALUE_TYPE_NAME (value), |
||
3667 | "'", |
||
3668 | NULL); |
||
3669 | else if (!g_value_type_compatible (G_OBJECT_TYPE (object), G_VALUE_TYPE (value))) |
||
3670 | return g_strconcat ("invalid object type '", |
||
3671 | G_OBJECT_TYPE_NAME (object), |
||
3672 | "' for value type '", |
||
3673 | G_VALUE_TYPE_NAME (value), |
||
3674 | "'", |
||
3675 | NULL); |
||
3676 | /* never honour G_VALUE_NOCOPY_CONTENTS for ref-counted types */ |
||
3677 | value->data[0].v_pointer = g_object_ref (object); |
||
3678 | } |
||
3679 | else |
||
3680 | value->data[0].v_pointer = NULL; |
||
3681 | |||
3682 | return NULL; |
||
3683 | } |
||
3684 | |||
3685 | static gchar* |
||
3686 | g_value_object_lcopy_value (const GValue *value, |
||
3687 | guint n_collect_values, |
||
3688 | GTypeCValue *collect_values, |
||
3689 | guint collect_flags) |
||
3690 | { |
||
3691 | GObject **object_p = collect_values[0].v_pointer; |
||
3692 | |||
3693 | if (!object_p) |
||
3694 | return g_strdup_printf ("value location for '%s' passed as NULL", G_VALUE_TYPE_NAME (value)); |
||
3695 | |||
3696 | if (!value->data[0].v_pointer) |
||
3697 | *object_p = NULL; |
||
3698 | else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) |
||
3699 | *object_p = value->data[0].v_pointer; |
||
3700 | else |
||
3701 | *object_p = g_object_ref (value->data[0].v_pointer); |
||
3702 | |||
3703 | return NULL; |
||
3704 | } |
||
3705 | |||
3706 | /** |
||
3707 | * g_value_set_object: |
||
3708 | * @value: a valid #GValue of %G_TYPE_OBJECT derived type |
||
3709 | * @v_object: (type GObject.Object) (allow-none): object value to be set |
||
3710 | * |
||
3711 | * Set the contents of a %G_TYPE_OBJECT derived #GValue to @v_object. |
||
3712 | * |
||
3713 | * g_value_set_object() increases the reference count of @v_object |
||
3714 | * (the #GValue holds a reference to @v_object). If you do not wish |
||
3715 | * to increase the reference count of the object (i.e. you wish to |
||
3716 | * pass your current reference to the #GValue because you no longer |
||
3717 | * need it), use g_value_take_object() instead. |
||
3718 | * |
||
3719 | * It is important that your #GValue holds a reference to @v_object (either its |
||
3720 | * own, or one it has taken) to ensure that the object won't be destroyed while |
||
3721 | * the #GValue still exists). |
||
3722 | */ |
||
3723 | void |
||
3724 | g_value_set_object (GValue *value, |
||
3725 | gpointer v_object) |
||
3726 | { |
||
3727 | GObject *old; |
||
3728 | |||
3729 | g_return_if_fail (G_VALUE_HOLDS_OBJECT (value)); |
||
3730 | |||
3731 | old = value->data[0].v_pointer; |
||
3732 | |||
3733 | if (v_object) |
||
3734 | { |
||
3735 | g_return_if_fail (G_IS_OBJECT (v_object)); |
||
3736 | g_return_if_fail (g_value_type_compatible (G_OBJECT_TYPE (v_object), G_VALUE_TYPE (value))); |
||
3737 | |||
3738 | value->data[0].v_pointer = v_object; |
||
3739 | g_object_ref (value->data[0].v_pointer); |
||
3740 | } |
||
3741 | else |
||
3742 | value->data[0].v_pointer = NULL; |
||
3743 | |||
3744 | if (old) |
||
3745 | g_object_unref (old); |
||
3746 | } |
||
3747 | |||
3748 | /** |
||
3749 | * g_value_set_object_take_ownership: (skip) |
||
3750 | * @value: a valid #GValue of %G_TYPE_OBJECT derived type |
||
3751 | * @v_object: (allow-none): object value to be set |
||
3752 | * |
||
3753 | * This is an internal function introduced mainly for C marshallers. |
||
3754 | * |
||
3755 | * Deprecated: 2.4: Use g_value_take_object() instead. |
||
3756 | */ |
||
3757 | void |
||
3758 | g_value_set_object_take_ownership (GValue *value, |
||
3759 | gpointer v_object) |
||
3760 | { |
||
3761 | g_value_take_object (value, v_object); |
||
3762 | } |
||
3763 | |||
3764 | /** |
||
3765 | * g_value_take_object: (skip) |
||
3766 | * @value: a valid #GValue of %G_TYPE_OBJECT derived type |
||
3767 | * @v_object: (allow-none): object value to be set |
||
3768 | * |
||
3769 | * Sets the contents of a %G_TYPE_OBJECT derived #GValue to @v_object |
||
3770 | * and takes over the ownership of the callers reference to @v_object; |
||
3771 | * the caller doesn't have to unref it any more (i.e. the reference |
||
3772 | * count of the object is not increased). |
||
3773 | * |
||
3774 | * If you want the #GValue to hold its own reference to @v_object, use |
||
3775 | * g_value_set_object() instead. |
||
3776 | * |
||
3777 | * Since: 2.4 |
||
3778 | */ |
||
3779 | void |
||
3780 | g_value_take_object (GValue *value, |
||
3781 | gpointer v_object) |
||
3782 | { |
||
3783 | g_return_if_fail (G_VALUE_HOLDS_OBJECT (value)); |
||
3784 | |||
3785 | if (value->data[0].v_pointer) |
||
3786 | { |
||
3787 | g_object_unref (value->data[0].v_pointer); |
||
3788 | value->data[0].v_pointer = NULL; |
||
3789 | } |
||
3790 | |||
3791 | if (v_object) |
||
3792 | { |
||
3793 | g_return_if_fail (G_IS_OBJECT (v_object)); |
||
3794 | g_return_if_fail (g_value_type_compatible (G_OBJECT_TYPE (v_object), G_VALUE_TYPE (value))); |
||
3795 | |||
3796 | value->data[0].v_pointer = v_object; /* we take over the reference count */ |
||
3797 | } |
||
3798 | } |
||
3799 | |||
3800 | /** |
||
3801 | * g_value_get_object: |
||
3802 | * @value: a valid #GValue of %G_TYPE_OBJECT derived type |
||
3803 | * |
||
3804 | * Get the contents of a %G_TYPE_OBJECT derived #GValue. |
||
3805 | * |
||
3806 | * Returns: (type GObject.Object) (transfer none): object contents of @value |
||
3807 | */ |
||
3808 | gpointer |
||
3809 | g_value_get_object (const GValue *value) |
||
3810 | { |
||
3811 | g_return_val_if_fail (G_VALUE_HOLDS_OBJECT (value), NULL); |
||
3812 | |||
3813 | return value->data[0].v_pointer; |
||
3814 | } |
||
3815 | |||
3816 | /** |
||
3817 | * g_value_dup_object: |
||
3818 | * @value: a valid #GValue whose type is derived from %G_TYPE_OBJECT |
||
3819 | * |
||
3820 | * Get the contents of a %G_TYPE_OBJECT derived #GValue, increasing |
||
3821 | * its reference count. If the contents of the #GValue are %NULL, then |
||
3822 | * %NULL will be returned. |
||
3823 | * |
||
3824 | * Returns: (type GObject.Object) (transfer full): object content of @value, |
||
3825 | * should be unreferenced when no longer needed. |
||
3826 | */ |
||
3827 | gpointer |
||
3828 | g_value_dup_object (const GValue *value) |
||
3829 | { |
||
3830 | g_return_val_if_fail (G_VALUE_HOLDS_OBJECT (value), NULL); |
||
3831 | |||
3832 | return value->data[0].v_pointer ? g_object_ref (value->data[0].v_pointer) : NULL; |
||
3833 | } |
||
3834 | |||
3835 | /** |
||
3836 | * g_signal_connect_object: (skip) |
||
3837 | * @instance: (type GObject.TypeInstance): the instance to connect to. |
||
3838 | * @detailed_signal: a string of the form "signal-name::detail". |
||
3839 | * @c_handler: the #GCallback to connect. |
||
3840 | * @gobject: (type GObject.Object) (nullable): the object to pass as data |
||
3841 | * to @c_handler. |
||
3842 | * @connect_flags: a combination of #GConnectFlags. |
||
3843 | * |
||
3844 | * This is similar to g_signal_connect_data(), but uses a closure which |
||
3845 | * ensures that the @gobject stays alive during the call to @c_handler |
||
3846 | * by temporarily adding a reference count to @gobject. |
||
3847 | * |
||
3848 | * When the @gobject is destroyed the signal handler will be automatically |
||
3849 | * disconnected. Note that this is not currently threadsafe (ie: |
||
3850 | * emitting a signal while @gobject is being destroyed in another thread |
||
3851 | * is not safe). |
||
3852 | * |
||
3853 | * Returns: the handler id. |
||
3854 | */ |
||
3855 | gulong |
||
3856 | g_signal_connect_object (gpointer instance, |
||
3857 | const gchar *detailed_signal, |
||
3858 | GCallback c_handler, |
||
3859 | gpointer gobject, |
||
3860 | GConnectFlags connect_flags) |
||
3861 | { |
||
3862 | g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0); |
||
3863 | g_return_val_if_fail (detailed_signal != NULL, 0); |
||
3864 | g_return_val_if_fail (c_handler != NULL, 0); |
||
3865 | |||
3866 | if (gobject) |
||
3867 | { |
||
3868 | GClosure *closure; |
||
3869 | |||
3870 | g_return_val_if_fail (G_IS_OBJECT (gobject), 0); |
||
3871 | |||
3872 | closure = ((connect_flags & G_CONNECT_SWAPPED) ? g_cclosure_new_object_swap : g_cclosure_new_object) (c_handler, gobject); |
||
3873 | |||
3874 | return g_signal_connect_closure (instance, detailed_signal, closure, connect_flags & G_CONNECT_AFTER); |
||
3875 | } |
||
3876 | else |
||
3877 | return g_signal_connect_data (instance, detailed_signal, c_handler, NULL, NULL, connect_flags); |
||
3878 | } |
||
3879 | |||
3880 | typedef struct { |
||
3881 | GObject *object; |
||
3882 | guint n_closures; |
||
3883 | GClosure *closures[1]; /* flexible array */ |
||
3884 | } CArray; |
||
3885 | /* don't change this structure without supplying an accessor for |
||
3886 | * watched closures, e.g.: |
||
3887 | * GSList* g_object_list_watched_closures (GObject *object) |
||
3888 | * { |
||
3889 | * CArray *carray; |
||
3890 | * g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
||
3891 | * carray = g_object_get_data (object, "GObject-closure-array"); |
||
3892 | * if (carray) |
||
3893 | * { |
||
3894 | * GSList *slist = NULL; |
||
3895 | * guint i; |
||
3896 | * for (i = 0; i < carray->n_closures; i++) |
||
3897 | * slist = g_slist_prepend (slist, carray->closures[i]); |
||
3898 | * return slist; |
||
3899 | * } |
||
3900 | * return NULL; |
||
3901 | * } |
||
3902 | */ |
||
3903 | |||
3904 | static void |
||
3905 | object_remove_closure (gpointer data, |
||
3906 | GClosure *closure) |
||
3907 | { |
||
3908 | GObject *object = data; |
||
3909 | CArray *carray; |
||
3910 | guint i; |
||
3911 | |||
3912 | G_LOCK (closure_array_mutex); |
||
3913 | carray = g_object_get_qdata (object, quark_closure_array); |
||
3914 | for (i = 0; i < carray->n_closures; i++) |
||
3915 | if (carray->closures[i] == closure) |
||
3916 | { |
||
3917 | carray->n_closures--; |
||
3918 | if (i < carray->n_closures) |
||
3919 | carray->closures[i] = carray->closures[carray->n_closures]; |
||
3920 | G_UNLOCK (closure_array_mutex); |
||
3921 | return; |
||
3922 | } |
||
3923 | G_UNLOCK (closure_array_mutex); |
||
3924 | g_assert_not_reached (); |
||
3925 | } |
||
3926 | |||
3927 | static void |
||
3928 | destroy_closure_array (gpointer data) |
||
3929 | { |
||
3930 | CArray *carray = data; |
||
3931 | GObject *object = carray->object; |
||
3932 | guint i, n = carray->n_closures; |
||
3933 | |||
3934 | for (i = 0; i < n; i++) |
||
3935 | { |
||
3936 | GClosure *closure = carray->closures[i]; |
||
3937 | |||
3938 | /* removing object_remove_closure() upfront is probably faster than |
||
3939 | * letting it fiddle with quark_closure_array which is empty anyways |
||
3940 | */ |
||
3941 | g_closure_remove_invalidate_notifier (closure, object, object_remove_closure); |
||
3942 | g_closure_invalidate (closure); |
||
3943 | } |
||
3944 | g_free (carray); |
||
3945 | } |
||
3946 | |||
3947 | /** |
||
3948 | * g_object_watch_closure: |
||
3949 | * @object: GObject restricting lifetime of @closure |
||
3950 | * @closure: GClosure to watch |
||
3951 | * |
||
3952 | * This function essentially limits the life time of the @closure to |
||
3953 | * the life time of the object. That is, when the object is finalized, |
||
3954 | * the @closure is invalidated by calling g_closure_invalidate() on |
||
3955 | * it, in order to prevent invocations of the closure with a finalized |
||
3956 | * (nonexisting) object. Also, g_object_ref() and g_object_unref() are |
||
3957 | * added as marshal guards to the @closure, to ensure that an extra |
||
3958 | * reference count is held on @object during invocation of the |
||
3959 | * @closure. Usually, this function will be called on closures that |
||
3960 | * use this @object as closure data. |
||
3961 | */ |
||
3962 | void |
||
3963 | g_object_watch_closure (GObject *object, |
||
3964 | GClosure *closure) |
||
3965 | { |
||
3966 | CArray *carray; |
||
3967 | guint i; |
||
3968 | |||
3969 | g_return_if_fail (G_IS_OBJECT (object)); |
||
3970 | g_return_if_fail (closure != NULL); |
||
3971 | g_return_if_fail (closure->is_invalid == FALSE); |
||
3972 | g_return_if_fail (closure->in_marshal == FALSE); |
||
3973 | g_return_if_fail (object->ref_count > 0); /* this doesn't work on finalizing objects */ |
||
3974 | |||
3975 | g_closure_add_invalidate_notifier (closure, object, object_remove_closure); |
||
3976 | g_closure_add_marshal_guards (closure, |
||
3977 | object, (GClosureNotify) g_object_ref, |
||
3978 | object, (GClosureNotify) g_object_unref); |
||
3979 | G_LOCK (closure_array_mutex); |
||
3980 | carray = g_datalist_id_remove_no_notify (&object->qdata, quark_closure_array); |
||
3981 | if (!carray) |
||
3982 | { |
||
3983 | carray = g_renew (CArray, NULL, 1); |
||
3984 | carray->object = object; |
||
3985 | carray->n_closures = 1; |
||
3986 | i = 0; |
||
3987 | } |
||
3988 | else |
||
3989 | { |
||
3990 | i = carray->n_closures++; |
||
3991 | carray = g_realloc (carray, sizeof (*carray) + sizeof (carray->closures[0]) * i); |
||
3992 | } |
||
3993 | carray->closures[i] = closure; |
||
3994 | g_datalist_id_set_data_full (&object->qdata, quark_closure_array, carray, destroy_closure_array); |
||
3995 | G_UNLOCK (closure_array_mutex); |
||
3996 | } |
||
3997 | |||
3998 | /** |
||
3999 | * g_closure_new_object: |
||
4000 | * @sizeof_closure: the size of the structure to allocate, must be at least |
||
4001 | * `sizeof (GClosure)` |
||
4002 | * @object: a #GObject pointer to store in the @data field of the newly |
||
4003 | * allocated #GClosure |
||
4004 | * |
||
4005 | * A variant of g_closure_new_simple() which stores @object in the |
||
4006 | * @data field of the closure and calls g_object_watch_closure() on |
||
4007 | * @object and the created closure. This function is mainly useful |
||
4008 | * when implementing new types of closures. |
||
4009 | * |
||
4010 | * Returns: (transfer full): a newly allocated #GClosure |
||
4011 | */ |
||
4012 | GClosure* |
||
4013 | g_closure_new_object (guint sizeof_closure, |
||
4014 | GObject *object) |
||
4015 | { |
||
4016 | GClosure *closure; |
||
4017 | |||
4018 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
||
4019 | g_return_val_if_fail (object->ref_count > 0, NULL); /* this doesn't work on finalizing objects */ |
||
4020 | |||
4021 | closure = g_closure_new_simple (sizeof_closure, object); |
||
4022 | g_object_watch_closure (object, closure); |
||
4023 | |||
4024 | return closure; |
||
4025 | } |
||
4026 | |||
4027 | /** |
||
4028 | * g_cclosure_new_object: (skip) |
||
4029 | * @callback_func: the function to invoke |
||
4030 | * @object: a #GObject pointer to pass to @callback_func |
||
4031 | * |
||
4032 | * A variant of g_cclosure_new() which uses @object as @user_data and |
||
4033 | * calls g_object_watch_closure() on @object and the created |
||
4034 | * closure. This function is useful when you have a callback closely |
||
4035 | * associated with a #GObject, and want the callback to no longer run |
||
4036 | * after the object is is freed. |
||
4037 | * |
||
4038 | * Returns: a new #GCClosure |
||
4039 | */ |
||
4040 | GClosure* |
||
4041 | g_cclosure_new_object (GCallback callback_func, |
||
4042 | GObject *object) |
||
4043 | { |
||
4044 | GClosure *closure; |
||
4045 | |||
4046 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
||
4047 | g_return_val_if_fail (object->ref_count > 0, NULL); /* this doesn't work on finalizing objects */ |
||
4048 | g_return_val_if_fail (callback_func != NULL, NULL); |
||
4049 | |||
4050 | closure = g_cclosure_new (callback_func, object, NULL); |
||
4051 | g_object_watch_closure (object, closure); |
||
4052 | |||
4053 | return closure; |
||
4054 | } |
||
4055 | |||
4056 | /** |
||
4057 | * g_cclosure_new_object_swap: (skip) |
||
4058 | * @callback_func: the function to invoke |
||
4059 | * @object: a #GObject pointer to pass to @callback_func |
||
4060 | * |
||
4061 | * A variant of g_cclosure_new_swap() which uses @object as @user_data |
||
4062 | * and calls g_object_watch_closure() on @object and the created |
||
4063 | * closure. This function is useful when you have a callback closely |
||
4064 | * associated with a #GObject, and want the callback to no longer run |
||
4065 | * after the object is is freed. |
||
4066 | * |
||
4067 | * Returns: a new #GCClosure |
||
4068 | */ |
||
4069 | GClosure* |
||
4070 | g_cclosure_new_object_swap (GCallback callback_func, |
||
4071 | GObject *object) |
||
4072 | { |
||
4073 | GClosure *closure; |
||
4074 | |||
4075 | g_return_val_if_fail (G_IS_OBJECT (object), NULL); |
||
4076 | g_return_val_if_fail (object->ref_count > 0, NULL); /* this doesn't work on finalizing objects */ |
||
4077 | g_return_val_if_fail (callback_func != NULL, NULL); |
||
4078 | |||
4079 | closure = g_cclosure_new_swap (callback_func, object, NULL); |
||
4080 | g_object_watch_closure (object, closure); |
||
4081 | |||
4082 | return closure; |
||
4083 | } |
||
4084 | |||
4085 | gsize |
||
4086 | g_object_compat_control (gsize what, |
||
4087 | gpointer data) |
||
4088 | { |
||
4089 | switch (what) |
||
4090 | { |
||
4091 | gpointer *pp; |
||
4092 | case 1: /* floating base type */ |
||
4093 | return G_TYPE_INITIALLY_UNOWNED; |
||
4094 | case 2: /* FIXME: remove this once GLib/Gtk+ break ABI again */ |
||
4095 | floating_flag_handler = (guint(*)(GObject*,gint)) data; |
||
4096 | return 1; |
||
4097 | case 3: /* FIXME: remove this once GLib/Gtk+ break ABI again */ |
||
4098 | pp = data; |
||
4099 | *pp = floating_flag_handler; |
||
4100 | return 1; |
||
4101 | default: |
||
4102 | return 0; |
||
4103 | } |
||
4104 | } |
||
4105 | |||
4106 | G_DEFINE_TYPE (GInitiallyUnowned, g_initially_unowned, G_TYPE_OBJECT); |
||
4107 | |||
4108 | static void |
||
4109 | g_initially_unowned_init (GInitiallyUnowned *object) |
||
4110 | { |
||
4111 | g_object_force_floating (object); |
||
4112 | } |
||
4113 | |||
4114 | static void |
||
4115 | g_initially_unowned_class_init (GInitiallyUnownedClass *klass) |
||
4116 | { |
||
4117 | } |
||
4118 | |||
4119 | /** |
||
4120 | * GWeakRef: |
||
4121 | * |
||
4122 | * A structure containing a weak reference to a #GObject. It can either |
||
4123 | * be empty (i.e. point to %NULL), or point to an object for as long as |
||
4124 | * at least one "strong" reference to that object exists. Before the |
||
4125 | * object's #GObjectClass.dispose method is called, every #GWeakRef |
||
4126 | * associated with becomes empty (i.e. points to %NULL). |
||
4127 | * |
||
4128 | * Like #GValue, #GWeakRef can be statically allocated, stack- or |
||
4129 | * heap-allocated, or embedded in larger structures. |
||
4130 | * |
||
4131 | * Unlike g_object_weak_ref() and g_object_add_weak_pointer(), this weak |
||
4132 | * reference is thread-safe: converting a weak pointer to a reference is |
||
4133 | * atomic with respect to invalidation of weak pointers to destroyed |
||
4134 | * objects. |
||
4135 | * |
||
4136 | * If the object's #GObjectClass.dispose method results in additional |
||
4137 | * references to the object being held, any #GWeakRefs taken |
||
4138 | * before it was disposed will continue to point to %NULL. If |
||
4139 | * #GWeakRefs are taken after the object is disposed and |
||
4140 | * re-referenced, they will continue to point to it until its refcount |
||
4141 | * goes back to zero, at which point they too will be invalidated. |
||
4142 | */ |
||
4143 | |||
4144 | /** |
||
4145 | * g_weak_ref_init: (skip) |
||
4146 | * @weak_ref: (inout): uninitialized or empty location for a weak |
||
4147 | * reference |
||
4148 | * @object: (type GObject.Object) (nullable): a #GObject or %NULL |
||
4149 | * |
||
4150 | * Initialise a non-statically-allocated #GWeakRef. |
||
4151 | * |
||
4152 | * This function also calls g_weak_ref_set() with @object on the |
||
4153 | * freshly-initialised weak reference. |
||
4154 | * |
||
4155 | * This function should always be matched with a call to |
||
4156 | * g_weak_ref_clear(). It is not necessary to use this function for a |
||
4157 | * #GWeakRef in static storage because it will already be |
||
4158 | * properly initialised. Just use g_weak_ref_set() directly. |
||
4159 | * |
||
4160 | * Since: 2.32 |
||
4161 | */ |
||
4162 | void |
||
4163 | g_weak_ref_init (GWeakRef *weak_ref, |
||
4164 | gpointer object) |
||
4165 | { |
||
4166 | weak_ref->priv.p = NULL; |
||
4167 | |||
4168 | g_weak_ref_set (weak_ref, object); |
||
4169 | } |
||
4170 | |||
4171 | /** |
||
4172 | * g_weak_ref_clear: (skip) |
||
4173 | * @weak_ref: (inout): location of a weak reference, which |
||
4174 | * may be empty |
||
4175 | * |
||
4176 | * Frees resources associated with a non-statically-allocated #GWeakRef. |
||
4177 | * After this call, the #GWeakRef is left in an undefined state. |
||
4178 | * |
||
4179 | * You should only call this on a #GWeakRef that previously had |
||
4180 | * g_weak_ref_init() called on it. |
||
4181 | * |
||
4182 | * Since: 2.32 |
||
4183 | */ |
||
4184 | void |
||
4185 | g_weak_ref_clear (GWeakRef *weak_ref) |
||
4186 | { |
||
4187 | g_weak_ref_set (weak_ref, NULL); |
||
4188 | |||
4189 | /* be unkind */ |
||
4190 | weak_ref->priv.p = (void *) 0xccccccccu; |
||
4191 | } |
||
4192 | |||
4193 | /** |
||
4194 | * g_weak_ref_get: (skip) |
||
4195 | * @weak_ref: (inout): location of a weak reference to a #GObject |
||
4196 | * |
||
4197 | * If @weak_ref is not empty, atomically acquire a strong |
||
4198 | * reference to the object it points to, and return that reference. |
||
4199 | * |
||
4200 | * This function is needed because of the potential race between taking |
||
4201 | * the pointer value and g_object_ref() on it, if the object was losing |
||
4202 | * its last reference at the same time in a different thread. |
||
4203 | * |
||
4204 | * The caller should release the resulting reference in the usual way, |
||
4205 | * by using g_object_unref(). |
||
4206 | * |
||
4207 | * Returns: (transfer full) (type GObject.Object): the object pointed to |
||
4208 | * by @weak_ref, or %NULL if it was empty |
||
4209 | * |
||
4210 | * Since: 2.32 |
||
4211 | */ |
||
4212 | gpointer |
||
4213 | g_weak_ref_get (GWeakRef *weak_ref) |
||
4214 | { |
||
4215 | gpointer object_or_null; |
||
4216 | |||
4217 | g_return_val_if_fail (weak_ref!= NULL, NULL); |
||
4218 | |||
4219 | g_rw_lock_reader_lock (&weak_locations_lock); |
||
4220 | |||
4221 | object_or_null = weak_ref->priv.p; |
||
4222 | |||
4223 | if (object_or_null != NULL) |
||
4224 | g_object_ref (object_or_null); |
||
4225 | |||
4226 | g_rw_lock_reader_unlock (&weak_locations_lock); |
||
4227 | |||
4228 | return object_or_null; |
||
4229 | } |
||
4230 | |||
4231 | /** |
||
4232 | * g_weak_ref_set: (skip) |
||
4233 | * @weak_ref: location for a weak reference |
||
4234 | * @object: (type GObject.Object) (nullable): a #GObject or %NULL |
||
4235 | * |
||
4236 | * Change the object to which @weak_ref points, or set it to |
||
4237 | * %NULL. |
||
4238 | * |
||
4239 | * You must own a strong reference on @object while calling this |
||
4240 | * function. |
||
4241 | * |
||
4242 | * Since: 2.32 |
||
4243 | */ |
||
4244 | void |
||
4245 | g_weak_ref_set (GWeakRef *weak_ref, |
||
4246 | gpointer object) |
||
4247 | { |
||
4248 | GSList **weak_locations; |
||
4249 | GObject *new_object; |
||
4250 | GObject *old_object; |
||
4251 | |||
4252 | g_return_if_fail (weak_ref != NULL); |
||
4253 | g_return_if_fail (object == NULL || G_IS_OBJECT (object)); |
||
4254 | |||
4255 | new_object = object; |
||
4256 | |||
4257 | g_rw_lock_writer_lock (&weak_locations_lock); |
||
4258 | |||
4259 | /* We use the extra level of indirection here so that if we have ever |
||
4260 | * had a weak pointer installed at any point in time on this object, |
||
4261 | * we can see that there is a non-NULL value associated with the |
||
4262 | * weak-pointer quark and know that this value will not change at any |
||
4263 | * point in the object's lifetime. |
||
4264 | * |
||
4265 | * Both properties are important for reducing the amount of times we |
||
4266 | * need to acquire locks and for decreasing the duration of time the |
||
4267 | * lock is held while avoiding some rather tricky races. |
||
4268 | * |
||
4269 | * Specifically: we can avoid having to do an extra unconditional lock |
||
4270 | * in g_object_unref() without worrying about some extremely tricky |
||
4271 | * races. |
||
4272 | */ |
||
4273 | |||
4274 | old_object = weak_ref->priv.p; |
||
4275 | if (new_object != old_object) |
||
4276 | { |
||
4277 | weak_ref->priv.p = new_object; |
||
4278 | |||
4279 | /* Remove the weak ref from the old object */ |
||
4280 | if (old_object != NULL) |
||
4281 | { |
||
4282 | weak_locations = g_datalist_id_get_data (&old_object->qdata, quark_weak_locations); |
||
4283 | /* for it to point to an object, the object must have had it added once */ |
||
4284 | g_assert (weak_locations != NULL); |
||
4285 | |||
4286 | *weak_locations = g_slist_remove (*weak_locations, weak_ref); |
||
4287 | } |
||
4288 | |||
4289 | /* Add the weak ref to the new object */ |
||
4290 | if (new_object != NULL) |
||
4291 | { |
||
4292 | weak_locations = g_datalist_id_get_data (&new_object->qdata, quark_weak_locations); |
||
4293 | |||
4294 | if (weak_locations == NULL) |
||
4295 | { |
||
4296 | weak_locations = g_new0 (GSList *, 1); |
||
4297 | g_datalist_id_set_data_full (&new_object->qdata, quark_weak_locations, weak_locations, g_free); |
||
4298 | } |
||
4299 | |||
4300 | *weak_locations = g_slist_prepend (*weak_locations, weak_ref); |
||
4301 | } |
||
4302 | } |
||
4303 | |||
4304 | g_rw_lock_writer_unlock (&weak_locations_lock); |
||
4305 | } |