/src/gstreamer/subprojects/glib-2.82.5/gobject/gbinding.c
Line | Count | Source |
1 | | /* gbinding.c: Binding for object properties |
2 | | * |
3 | | * Copyright (C) 2010 Intel Corp. |
4 | | * |
5 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * This library is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General |
18 | | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
19 | | * |
20 | | * Author: Emmanuele Bassi <ebassi@linux.intel.com> |
21 | | */ |
22 | | |
23 | | /** |
24 | | * GBinding: |
25 | | * |
26 | | * `GObject` instance (or source) and another property on another `GObject` |
27 | | * instance (or target). |
28 | | * |
29 | | * Whenever the source property changes, the same value is applied to the |
30 | | * target property; for instance, the following binding: |
31 | | * |
32 | | * ```c |
33 | | * g_object_bind_property (object1, "property-a", |
34 | | * object2, "property-b", |
35 | | * G_BINDING_DEFAULT); |
36 | | * ``` |
37 | | * |
38 | | * will cause the property named "property-b" of @object2 to be updated |
39 | | * every time [method@GObject.set] or the specific accessor changes the value of |
40 | | * the property "property-a" of @object1. |
41 | | * |
42 | | * It is possible to create a bidirectional binding between two properties |
43 | | * of two `GObject` instances, so that if either property changes, the |
44 | | * other is updated as well, for instance: |
45 | | * |
46 | | * ```c |
47 | | * g_object_bind_property (object1, "property-a", |
48 | | * object2, "property-b", |
49 | | * G_BINDING_BIDIRECTIONAL); |
50 | | * ``` |
51 | | * |
52 | | * will keep the two properties in sync. |
53 | | * |
54 | | * It is also possible to set a custom transformation function (in both |
55 | | * directions, in case of a bidirectional binding) to apply a custom |
56 | | * transformation from the source value to the target value before |
57 | | * applying it; for instance, the following binding: |
58 | | * |
59 | | * ```c |
60 | | * g_object_bind_property_full (adjustment1, "value", |
61 | | * adjustment2, "value", |
62 | | * G_BINDING_BIDIRECTIONAL, |
63 | | * celsius_to_fahrenheit, |
64 | | * fahrenheit_to_celsius, |
65 | | * NULL, NULL); |
66 | | * ``` |
67 | | * |
68 | | * will keep the "value" property of the two adjustments in sync; the |
69 | | * @celsius_to_fahrenheit function will be called whenever the "value" |
70 | | * property of @adjustment1 changes and will transform the current value |
71 | | * of the property before applying it to the "value" property of @adjustment2. |
72 | | * |
73 | | * Vice versa, the @fahrenheit_to_celsius function will be called whenever |
74 | | * the "value" property of @adjustment2 changes, and will transform the |
75 | | * current value of the property before applying it to the "value" property |
76 | | * of @adjustment1. |
77 | | * |
78 | | * Note that #GBinding does not resolve cycles by itself; a cycle like |
79 | | * |
80 | | * ``` |
81 | | * object1:propertyA -> object2:propertyB |
82 | | * object2:propertyB -> object3:propertyC |
83 | | * object3:propertyC -> object1:propertyA |
84 | | * ``` |
85 | | * |
86 | | * might lead to an infinite loop. The loop, in this particular case, |
87 | | * can be avoided if the objects emit the `GObject::notify` signal only |
88 | | * if the value has effectively been changed. A binding is implemented |
89 | | * using the `GObject::notify` signal, so it is susceptible to all the |
90 | | * various ways of blocking a signal emission, like [func@GObject.signal_stop_emission] |
91 | | * or [func@GObject.signal_handler_block]. |
92 | | * |
93 | | * A binding will be severed, and the resources it allocates freed, whenever |
94 | | * either one of the `GObject` instances it refers to are finalized, or when |
95 | | * the #GBinding instance loses its last reference. |
96 | | * |
97 | | * Bindings for languages with garbage collection can use |
98 | | * [method@GObject.Binding.unbind] to explicitly release a binding between the source |
99 | | * and target properties, instead of relying on the last reference on the |
100 | | * binding, source, and target instances to drop. |
101 | | * |
102 | | * Since: 2.26 |
103 | | */ |
104 | | |
105 | | #include "config.h" |
106 | | |
107 | | #include <string.h> |
108 | | |
109 | | #include "gbinding.h" |
110 | | #include "genums.h" |
111 | | #include "gmarshal.h" |
112 | | #include "gobject.h" |
113 | | #include "gsignal.h" |
114 | | #include "gparamspecs.h" |
115 | | #include "gvaluetypes.h" |
116 | | |
117 | | #include "glibintl.h" |
118 | | |
119 | | |
120 | | GType |
121 | | g_binding_flags_get_type (void) |
122 | 0 | { |
123 | 0 | static GType static_g_define_type_id = 0; |
124 | |
|
125 | 0 | if (g_once_init_enter_pointer (&static_g_define_type_id)) |
126 | 0 | { |
127 | 0 | static const GFlagsValue values[] = { |
128 | 0 | { G_BINDING_DEFAULT, "G_BINDING_DEFAULT", "default" }, |
129 | 0 | { G_BINDING_BIDIRECTIONAL, "G_BINDING_BIDIRECTIONAL", "bidirectional" }, |
130 | 0 | { G_BINDING_SYNC_CREATE, "G_BINDING_SYNC_CREATE", "sync-create" }, |
131 | 0 | { G_BINDING_INVERT_BOOLEAN, "G_BINDING_INVERT_BOOLEAN", "invert-boolean" }, |
132 | 0 | { 0, NULL, NULL } |
133 | 0 | }; |
134 | 0 | GType g_define_type_id = |
135 | 0 | g_flags_register_static (g_intern_static_string ("GBindingFlags"), values); |
136 | 0 | g_once_init_leave_pointer (&static_g_define_type_id, g_define_type_id); |
137 | 0 | } |
138 | |
|
139 | 0 | return static_g_define_type_id; |
140 | 0 | } |
141 | | |
142 | | /* Reference counted helper struct that is passed to all callbacks to ensure |
143 | | * that they never work with already freed objects without having to store |
144 | | * strong references for them. |
145 | | * |
146 | | * Using strong references anywhere is not possible because of the API |
147 | | * requirements of GBinding, specifically that the initial reference of the |
148 | | * GBinding is owned by the source/target and the caller and can be released |
149 | | * either by the source/target being finalized or calling g_binding_unbind(). |
150 | | * |
151 | | * As such, the only strong reference has to be owned by both weak notifies of |
152 | | * the source and target and the first to be called has to release it. |
153 | | */ |
154 | | typedef struct { |
155 | | GWeakRef binding; |
156 | | GWeakRef source; |
157 | | GWeakRef target; |
158 | | gboolean binding_removed; |
159 | | } BindingContext; |
160 | | |
161 | | static BindingContext * |
162 | | binding_context_ref (BindingContext *context) |
163 | 0 | { |
164 | 0 | return g_atomic_rc_box_acquire (context); |
165 | 0 | } |
166 | | |
167 | | static void |
168 | | binding_context_clear (BindingContext *context) |
169 | 0 | { |
170 | 0 | g_weak_ref_clear (&context->binding); |
171 | 0 | g_weak_ref_clear (&context->source); |
172 | 0 | g_weak_ref_clear (&context->target); |
173 | 0 | } |
174 | | |
175 | | static void |
176 | | binding_context_unref (BindingContext *context) |
177 | 0 | { |
178 | 0 | g_atomic_rc_box_release_full (context, (GDestroyNotify) binding_context_clear); |
179 | 0 | } |
180 | | |
181 | | /* Reference counting for the transform functions to ensure that they're always |
182 | | * valid while making use of them in the property notify callbacks. |
183 | | * |
184 | | * The transform functions are released when unbinding but unbinding can happen |
185 | | * while the transform functions are currently in use inside the notify callbacks. |
186 | | */ |
187 | | typedef struct { |
188 | | GBindingTransformFunc transform_s2t; |
189 | | GBindingTransformFunc transform_t2s; |
190 | | |
191 | | gpointer transform_data; |
192 | | GDestroyNotify destroy_notify; |
193 | | } TransformFunc; |
194 | | |
195 | | static TransformFunc * |
196 | | transform_func_new (GBindingTransformFunc transform_s2t, |
197 | | GBindingTransformFunc transform_t2s, |
198 | | gpointer transform_data, |
199 | | GDestroyNotify destroy_notify) |
200 | 0 | { |
201 | 0 | TransformFunc *func = g_atomic_rc_box_new0 (TransformFunc); |
202 | |
|
203 | 0 | func->transform_s2t = transform_s2t; |
204 | 0 | func->transform_t2s = transform_t2s; |
205 | 0 | func->transform_data = transform_data; |
206 | 0 | func->destroy_notify = destroy_notify; |
207 | |
|
208 | 0 | return func; |
209 | 0 | } |
210 | | |
211 | | static TransformFunc * |
212 | | transform_func_ref (TransformFunc *func) |
213 | 0 | { |
214 | 0 | return g_atomic_rc_box_acquire (func); |
215 | 0 | } |
216 | | |
217 | | static void |
218 | | transform_func_clear (TransformFunc *func) |
219 | 0 | { |
220 | 0 | if (func->destroy_notify) |
221 | 0 | func->destroy_notify (func->transform_data); |
222 | 0 | } |
223 | | |
224 | | static void |
225 | | transform_func_unref (TransformFunc *func) |
226 | 0 | { |
227 | 0 | g_atomic_rc_box_release_full (func, (GDestroyNotify) transform_func_clear); |
228 | 0 | } |
229 | | |
230 | | #define G_BINDING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_BINDING, GBindingClass)) |
231 | | #define G_IS_BINDING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_BINDING)) |
232 | | #define G_BINDING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_BINDING, GBindingClass)) |
233 | | |
234 | | typedef struct _GBindingClass GBindingClass; |
235 | | |
236 | | struct _GBinding |
237 | | { |
238 | | GObject parent_instance; |
239 | | |
240 | | /* no reference is held on the objects, to avoid cycles */ |
241 | | BindingContext *context; |
242 | | |
243 | | /* protects transform_func, source, target property notify and |
244 | | * target_weak_notify_installed for unbinding */ |
245 | | GMutex unbind_lock; |
246 | | |
247 | | /* transform functions, only NULL after unbinding */ |
248 | | TransformFunc *transform_func; /* LOCK: unbind_lock */ |
249 | | |
250 | | /* the property names are interned, so they should not be freed */ |
251 | | const gchar *source_property; |
252 | | const gchar *target_property; |
253 | | |
254 | | GParamSpec *source_pspec; |
255 | | GParamSpec *target_pspec; |
256 | | |
257 | | GBindingFlags flags; |
258 | | |
259 | | guint source_notify; /* LOCK: unbind_lock */ |
260 | | guint target_notify; /* LOCK: unbind_lock */ |
261 | | gboolean target_weak_notify_installed; /* LOCK: unbind_lock */ |
262 | | |
263 | | /* a guard, to avoid loops */ |
264 | | guint is_frozen : 1; |
265 | | }; |
266 | | |
267 | | struct _GBindingClass |
268 | | { |
269 | | GObjectClass parent_class; |
270 | | }; |
271 | | |
272 | | enum |
273 | | { |
274 | | PROP_0, |
275 | | |
276 | | PROP_SOURCE, |
277 | | PROP_TARGET, |
278 | | PROP_SOURCE_PROPERTY, |
279 | | PROP_TARGET_PROPERTY, |
280 | | PROP_FLAGS |
281 | | }; |
282 | | |
283 | | static guint gobject_notify_signal_id; |
284 | | |
285 | 0 | G_DEFINE_TYPE (GBinding, g_binding, G_TYPE_OBJECT) |
286 | 0 |
|
287 | 0 | static void weak_unbind (gpointer user_data, GObject *where_the_object_was); |
288 | 0 |
|
289 | 0 | /* Must be called with the unbind lock held, context/binding != NULL and strong |
290 | 0 | * references to source/target or NULL. |
291 | 0 | * Return TRUE if the binding was actually removed and FALSE if it was already |
292 | 0 | * removed before. */ |
293 | 0 | static gboolean |
294 | 0 | unbind_internal_locked (BindingContext *context, GBinding *binding, GObject *source, GObject *target) |
295 | 0 | { |
296 | 0 | gboolean binding_was_removed = FALSE; |
297 | |
|
298 | 0 | g_assert (context != NULL); |
299 | 0 | g_assert (binding != NULL); |
300 | | |
301 | | /* If the target went away we still have a strong reference to the source |
302 | | * here and can clear it from the binding. Otherwise if the source went away |
303 | | * we can clear the target from the binding. Finalizing an object clears its |
304 | | * signal handlers and all weak references pointing to it before calling |
305 | | * weak notify callbacks. |
306 | | * |
307 | | * If both still exist we clean up everything set up by the binding. |
308 | | */ |
309 | 0 | if (source) |
310 | 0 | { |
311 | | /* We always add/remove the source property notify and the weak notify |
312 | | * of the source at the same time, and should only ever do that once. */ |
313 | 0 | if (binding->source_notify != 0) |
314 | 0 | { |
315 | 0 | g_signal_handler_disconnect (source, binding->source_notify); |
316 | |
|
317 | 0 | g_object_weak_unref (source, weak_unbind, context); |
318 | 0 | binding_context_unref (context); |
319 | |
|
320 | 0 | binding->source_notify = 0; |
321 | 0 | } |
322 | 0 | g_weak_ref_set (&context->source, NULL); |
323 | 0 | } |
324 | | |
325 | | /* As above, but with the target. If source==target then no weak notify was |
326 | | * installed for the target, which is why that is stored as a separate |
327 | | * boolean inside the binding. */ |
328 | 0 | if (target) |
329 | 0 | { |
330 | | /* There might be a target property notify without a weak notify on the |
331 | | * target or the other way around, so these have to be handled |
332 | | * independently here unlike for the source. */ |
333 | 0 | if (binding->target_notify != 0) |
334 | 0 | { |
335 | 0 | g_signal_handler_disconnect (target, binding->target_notify); |
336 | |
|
337 | 0 | binding->target_notify = 0; |
338 | 0 | } |
339 | 0 | g_weak_ref_set (&context->target, NULL); |
340 | | |
341 | | /* Remove the weak notify from the target, at most once */ |
342 | 0 | if (binding->target_weak_notify_installed) |
343 | 0 | { |
344 | 0 | g_object_weak_unref (target, weak_unbind, context); |
345 | 0 | binding_context_unref (context); |
346 | 0 | binding->target_weak_notify_installed = FALSE; |
347 | 0 | } |
348 | 0 | } |
349 | | |
350 | | /* Make sure to remove the binding only once and return to the caller that |
351 | | * this was the call that actually removed it. */ |
352 | 0 | if (!context->binding_removed) |
353 | 0 | { |
354 | 0 | context->binding_removed = TRUE; |
355 | 0 | binding_was_removed = TRUE; |
356 | 0 | } |
357 | |
|
358 | 0 | return binding_was_removed; |
359 | 0 | } |
360 | | |
361 | | /* the basic assumption is that if either the source or the target |
362 | | * goes away then the binding does not exist any more and it should |
363 | | * be reaped as well. Each weak notify owns a strong reference to the |
364 | | * binding that should be dropped here. */ |
365 | | static void |
366 | | weak_unbind (gpointer user_data, |
367 | | GObject *where_the_object_was) |
368 | 0 | { |
369 | 0 | BindingContext *context = user_data; |
370 | 0 | GBinding *binding; |
371 | 0 | GObject *source, *target; |
372 | 0 | gboolean binding_was_removed = FALSE; |
373 | 0 | TransformFunc *transform_func; |
374 | |
|
375 | 0 | binding = g_weak_ref_get (&context->binding); |
376 | 0 | if (!binding) |
377 | 0 | { |
378 | | /* The binding was already destroyed before so there's nothing to do */ |
379 | 0 | binding_context_unref (context); |
380 | 0 | return; |
381 | 0 | } |
382 | | |
383 | 0 | g_mutex_lock (&binding->unbind_lock); |
384 | |
|
385 | 0 | transform_func = g_steal_pointer (&binding->transform_func); |
386 | |
|
387 | 0 | source = g_weak_ref_get (&context->source); |
388 | 0 | target = g_weak_ref_get (&context->target); |
389 | | |
390 | | /* If this is called then either the source or target or both must be in the |
391 | | * process of being disposed. If this happens as part of g_object_unref() |
392 | | * then the weak references are actually cleared, otherwise if disposing |
393 | | * happens as part of g_object_run_dispose() then they would still point to |
394 | | * the disposed object. |
395 | | * |
396 | | * If the object this is being called for is either the source or the target |
397 | | * and we actually got a strong reference to it nonetheless (see above), |
398 | | * then signal handlers and weak notifies for it are already disconnected |
399 | | * and they must not be disconnected a second time. Instead simply clear the |
400 | | * weak reference and be done with it. |
401 | | * |
402 | | * See https://gitlab.gnome.org/GNOME/glib/-/issues/2266 */ |
403 | |
|
404 | 0 | if (source == where_the_object_was) |
405 | 0 | { |
406 | 0 | g_weak_ref_set (&context->source, NULL); |
407 | 0 | g_clear_object (&source); |
408 | 0 | } |
409 | |
|
410 | 0 | if (target == where_the_object_was) |
411 | 0 | { |
412 | 0 | g_weak_ref_set (&context->target, NULL); |
413 | 0 | g_clear_object (&target); |
414 | 0 | } |
415 | |
|
416 | 0 | binding_was_removed = unbind_internal_locked (context, binding, source, target); |
417 | |
|
418 | 0 | g_mutex_unlock (&binding->unbind_lock); |
419 | | |
420 | | /* Unref source, target and transform_func after the mutex is unlocked as it |
421 | | * might release the last reference, which then accesses the mutex again */ |
422 | 0 | g_clear_object (&target); |
423 | 0 | g_clear_object (&source); |
424 | |
|
425 | 0 | g_clear_pointer (&transform_func, transform_func_unref); |
426 | | |
427 | | /* This releases the strong reference we got from the weak ref above */ |
428 | 0 | g_object_unref (binding); |
429 | | |
430 | | /* This will take care of the binding itself. */ |
431 | 0 | if (binding_was_removed) |
432 | 0 | g_object_unref (binding); |
433 | | |
434 | | /* Each weak notify owns a reference to the binding context. */ |
435 | 0 | binding_context_unref (context); |
436 | 0 | } |
437 | | |
438 | | static gboolean |
439 | | default_transform (GBinding *binding, |
440 | | const GValue *value_a, |
441 | | GValue *value_b, |
442 | | gpointer user_data G_GNUC_UNUSED) |
443 | 0 | { |
444 | | /* if it's not the same type, try to convert it using the GValue |
445 | | * transformation API; otherwise just copy it |
446 | | */ |
447 | 0 | if (!g_type_is_a (G_VALUE_TYPE (value_a), G_VALUE_TYPE (value_b))) |
448 | 0 | { |
449 | | /* are these two types compatible (can be directly copied)? */ |
450 | 0 | if (g_value_type_compatible (G_VALUE_TYPE (value_a), |
451 | 0 | G_VALUE_TYPE (value_b))) |
452 | 0 | { |
453 | 0 | g_value_copy (value_a, value_b); |
454 | 0 | return TRUE; |
455 | 0 | } |
456 | | |
457 | 0 | if (g_value_type_transformable (G_VALUE_TYPE (value_a), |
458 | 0 | G_VALUE_TYPE (value_b))) |
459 | 0 | { |
460 | 0 | if (g_value_transform (value_a, value_b)) |
461 | 0 | return TRUE; |
462 | 0 | } |
463 | | |
464 | 0 | g_critical ("%s: Unable to convert a value of type %s to a " |
465 | 0 | "value of type %s", |
466 | 0 | G_STRLOC, |
467 | 0 | g_type_name (G_VALUE_TYPE (value_a)), |
468 | 0 | g_type_name (G_VALUE_TYPE (value_b))); |
469 | |
|
470 | 0 | return FALSE; |
471 | 0 | } |
472 | | |
473 | 0 | g_value_copy (value_a, value_b); |
474 | 0 | return TRUE; |
475 | 0 | } |
476 | | |
477 | | static gboolean |
478 | | default_invert_boolean_transform (GBinding *binding, |
479 | | const GValue *value_a, |
480 | | GValue *value_b, |
481 | | gpointer user_data G_GNUC_UNUSED) |
482 | 0 | { |
483 | 0 | gboolean value; |
484 | |
|
485 | 0 | g_assert (G_VALUE_HOLDS_BOOLEAN (value_a)); |
486 | 0 | g_assert (G_VALUE_HOLDS_BOOLEAN (value_b)); |
487 | | |
488 | 0 | value = g_value_get_boolean (value_a); |
489 | 0 | value = !value; |
490 | |
|
491 | 0 | g_value_set_boolean (value_b, value); |
492 | |
|
493 | 0 | return TRUE; |
494 | 0 | } |
495 | | |
496 | | static void |
497 | | on_source_notify (GObject *source, |
498 | | GParamSpec *pspec, |
499 | | BindingContext *context) |
500 | 0 | { |
501 | 0 | GBinding *binding; |
502 | 0 | GObject *target; |
503 | 0 | TransformFunc *transform_func; |
504 | 0 | GValue from_value = G_VALUE_INIT; |
505 | 0 | GValue to_value = G_VALUE_INIT; |
506 | 0 | gboolean res; |
507 | |
|
508 | 0 | binding = g_weak_ref_get (&context->binding); |
509 | 0 | if (!binding) |
510 | 0 | return; |
511 | | |
512 | 0 | if (binding->is_frozen) |
513 | 0 | { |
514 | 0 | g_object_unref (binding); |
515 | 0 | return; |
516 | 0 | } |
517 | | |
518 | 0 | target = g_weak_ref_get (&context->target); |
519 | 0 | if (!target) |
520 | 0 | { |
521 | 0 | g_object_unref (binding); |
522 | 0 | return; |
523 | 0 | } |
524 | | |
525 | | /* Get the transform function safely */ |
526 | 0 | g_mutex_lock (&binding->unbind_lock); |
527 | 0 | if (!binding->transform_func) |
528 | 0 | { |
529 | | /* it was released already during unbinding, nothing to do here */ |
530 | 0 | g_mutex_unlock (&binding->unbind_lock); |
531 | 0 | return; |
532 | 0 | } |
533 | 0 | transform_func = transform_func_ref (binding->transform_func); |
534 | 0 | g_mutex_unlock (&binding->unbind_lock); |
535 | |
|
536 | 0 | g_value_init (&from_value, G_PARAM_SPEC_VALUE_TYPE (binding->source_pspec)); |
537 | 0 | g_value_init (&to_value, G_PARAM_SPEC_VALUE_TYPE (binding->target_pspec)); |
538 | |
|
539 | 0 | g_object_get_property (source, binding->source_pspec->name, &from_value); |
540 | |
|
541 | 0 | res = transform_func->transform_s2t (binding, |
542 | 0 | &from_value, |
543 | 0 | &to_value, |
544 | 0 | transform_func->transform_data); |
545 | |
|
546 | 0 | transform_func_unref (transform_func); |
547 | |
|
548 | 0 | if (res) |
549 | 0 | { |
550 | 0 | binding->is_frozen = TRUE; |
551 | |
|
552 | 0 | (void) g_param_value_validate (binding->target_pspec, &to_value); |
553 | 0 | g_object_set_property (target, binding->target_pspec->name, &to_value); |
554 | |
|
555 | 0 | binding->is_frozen = FALSE; |
556 | 0 | } |
557 | |
|
558 | 0 | g_value_unset (&from_value); |
559 | 0 | g_value_unset (&to_value); |
560 | |
|
561 | 0 | g_object_unref (target); |
562 | 0 | g_object_unref (binding); |
563 | 0 | } |
564 | | |
565 | | static void |
566 | | on_target_notify (GObject *target, |
567 | | GParamSpec *pspec, |
568 | | BindingContext *context) |
569 | 0 | { |
570 | 0 | GBinding *binding; |
571 | 0 | GObject *source; |
572 | 0 | TransformFunc *transform_func; |
573 | 0 | GValue from_value = G_VALUE_INIT; |
574 | 0 | GValue to_value = G_VALUE_INIT; |
575 | 0 | gboolean res; |
576 | |
|
577 | 0 | binding = g_weak_ref_get (&context->binding); |
578 | 0 | if (!binding) |
579 | 0 | return; |
580 | | |
581 | 0 | if (binding->is_frozen) |
582 | 0 | { |
583 | 0 | g_object_unref (binding); |
584 | 0 | return; |
585 | 0 | } |
586 | | |
587 | 0 | source = g_weak_ref_get (&context->source); |
588 | 0 | if (!source) |
589 | 0 | { |
590 | 0 | g_object_unref (binding); |
591 | 0 | return; |
592 | 0 | } |
593 | | |
594 | | /* Get the transform function safely */ |
595 | 0 | g_mutex_lock (&binding->unbind_lock); |
596 | 0 | if (!binding->transform_func) |
597 | 0 | { |
598 | | /* it was released already during unbinding, nothing to do here */ |
599 | 0 | g_mutex_unlock (&binding->unbind_lock); |
600 | 0 | return; |
601 | 0 | } |
602 | 0 | transform_func = transform_func_ref (binding->transform_func); |
603 | 0 | g_mutex_unlock (&binding->unbind_lock); |
604 | |
|
605 | 0 | g_value_init (&from_value, G_PARAM_SPEC_VALUE_TYPE (binding->target_pspec)); |
606 | 0 | g_value_init (&to_value, G_PARAM_SPEC_VALUE_TYPE (binding->source_pspec)); |
607 | |
|
608 | 0 | g_object_get_property (target, binding->target_pspec->name, &from_value); |
609 | |
|
610 | 0 | res = transform_func->transform_t2s (binding, |
611 | 0 | &from_value, |
612 | 0 | &to_value, |
613 | 0 | transform_func->transform_data); |
614 | 0 | transform_func_unref (transform_func); |
615 | |
|
616 | 0 | if (res) |
617 | 0 | { |
618 | 0 | binding->is_frozen = TRUE; |
619 | |
|
620 | 0 | (void) g_param_value_validate (binding->source_pspec, &to_value); |
621 | 0 | g_object_set_property (source, binding->source_pspec->name, &to_value); |
622 | |
|
623 | 0 | binding->is_frozen = FALSE; |
624 | 0 | } |
625 | |
|
626 | 0 | g_value_unset (&from_value); |
627 | 0 | g_value_unset (&to_value); |
628 | |
|
629 | 0 | g_object_unref (source); |
630 | 0 | g_object_unref (binding); |
631 | 0 | } |
632 | | |
633 | | static inline void |
634 | | g_binding_unbind_internal (GBinding *binding, |
635 | | gboolean unref_binding) |
636 | 0 | { |
637 | 0 | BindingContext *context = binding->context; |
638 | 0 | GObject *source, *target; |
639 | 0 | gboolean binding_was_removed = FALSE; |
640 | 0 | TransformFunc *transform_func; |
641 | |
|
642 | 0 | g_mutex_lock (&binding->unbind_lock); |
643 | |
|
644 | 0 | transform_func = g_steal_pointer (&binding->transform_func); |
645 | |
|
646 | 0 | source = g_weak_ref_get (&context->source); |
647 | 0 | target = g_weak_ref_get (&context->target); |
648 | |
|
649 | 0 | binding_was_removed = unbind_internal_locked (context, binding, source, target); |
650 | |
|
651 | 0 | g_mutex_unlock (&binding->unbind_lock); |
652 | | |
653 | | /* Unref source, target and transform_func after the mutex is unlocked as it |
654 | | * might release the last reference, which then accesses the mutex again */ |
655 | 0 | g_clear_object (&target); |
656 | 0 | g_clear_object (&source); |
657 | |
|
658 | 0 | g_clear_pointer (&transform_func, transform_func_unref); |
659 | |
|
660 | 0 | if (binding_was_removed && unref_binding) |
661 | 0 | g_object_unref (binding); |
662 | 0 | } |
663 | | |
664 | | static void |
665 | | g_binding_finalize (GObject *gobject) |
666 | 0 | { |
667 | 0 | GBinding *binding = G_BINDING (gobject); |
668 | |
|
669 | 0 | g_binding_unbind_internal (binding, FALSE); |
670 | |
|
671 | 0 | binding_context_unref (binding->context); |
672 | |
|
673 | 0 | g_mutex_clear (&binding->unbind_lock); |
674 | |
|
675 | 0 | G_OBJECT_CLASS (g_binding_parent_class)->finalize (gobject); |
676 | 0 | } |
677 | | |
678 | | /* @key must have already been validated with is_valid() |
679 | | * Modifies @key in place. */ |
680 | | static void |
681 | | canonicalize_key (gchar *key) |
682 | 0 | { |
683 | 0 | gchar *p; |
684 | |
|
685 | 0 | for (p = key; *p != 0; p++) |
686 | 0 | { |
687 | 0 | gchar c = *p; |
688 | |
|
689 | 0 | if (c == '_') |
690 | 0 | *p = '-'; |
691 | 0 | } |
692 | 0 | } |
693 | | |
694 | | /* @key must have already been validated with is_valid() */ |
695 | | static gboolean |
696 | | is_canonical (const gchar *key) |
697 | 0 | { |
698 | 0 | return (strchr (key, '_') == NULL); |
699 | 0 | } |
700 | | |
701 | | static void |
702 | | g_binding_set_property (GObject *gobject, |
703 | | guint prop_id, |
704 | | const GValue *value, |
705 | | GParamSpec *pspec) |
706 | 0 | { |
707 | 0 | GBinding *binding = G_BINDING (gobject); |
708 | |
|
709 | 0 | switch (prop_id) |
710 | 0 | { |
711 | 0 | case PROP_SOURCE: |
712 | 0 | g_weak_ref_set (&binding->context->source, g_value_get_object (value)); |
713 | 0 | break; |
714 | | |
715 | 0 | case PROP_TARGET: |
716 | 0 | g_weak_ref_set (&binding->context->target, g_value_get_object (value)); |
717 | 0 | break; |
718 | | |
719 | 0 | case PROP_SOURCE_PROPERTY: |
720 | 0 | case PROP_TARGET_PROPERTY: |
721 | 0 | { |
722 | 0 | gchar *name_copy = NULL; |
723 | 0 | const gchar *name = g_value_get_string (value); |
724 | 0 | const gchar **dest; |
725 | | |
726 | | /* Ensure the name we intern is canonical. */ |
727 | 0 | if (!is_canonical (name)) |
728 | 0 | { |
729 | 0 | name_copy = g_value_dup_string (value); |
730 | 0 | canonicalize_key (name_copy); |
731 | 0 | name = name_copy; |
732 | 0 | } |
733 | |
|
734 | 0 | if (prop_id == PROP_SOURCE_PROPERTY) |
735 | 0 | dest = &binding->source_property; |
736 | 0 | else |
737 | 0 | dest = &binding->target_property; |
738 | |
|
739 | 0 | *dest = g_intern_string (name); |
740 | |
|
741 | 0 | g_free (name_copy); |
742 | 0 | break; |
743 | 0 | } |
744 | | |
745 | 0 | case PROP_FLAGS: |
746 | 0 | binding->flags = g_value_get_flags (value); |
747 | 0 | break; |
748 | | |
749 | 0 | default: |
750 | 0 | G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); |
751 | 0 | break; |
752 | 0 | } |
753 | 0 | } |
754 | | |
755 | | static void |
756 | | g_binding_get_property (GObject *gobject, |
757 | | guint prop_id, |
758 | | GValue *value, |
759 | | GParamSpec *pspec) |
760 | 0 | { |
761 | 0 | GBinding *binding = G_BINDING (gobject); |
762 | |
|
763 | 0 | switch (prop_id) |
764 | 0 | { |
765 | 0 | case PROP_SOURCE: |
766 | 0 | g_value_take_object (value, g_weak_ref_get (&binding->context->source)); |
767 | 0 | break; |
768 | | |
769 | 0 | case PROP_SOURCE_PROPERTY: |
770 | | /* @source_property is interned, so we don’t need to take a copy */ |
771 | 0 | g_value_set_interned_string (value, binding->source_property); |
772 | 0 | break; |
773 | | |
774 | 0 | case PROP_TARGET: |
775 | 0 | g_value_take_object (value, g_weak_ref_get (&binding->context->target)); |
776 | 0 | break; |
777 | | |
778 | 0 | case PROP_TARGET_PROPERTY: |
779 | | /* @target_property is interned, so we don’t need to take a copy */ |
780 | 0 | g_value_set_interned_string (value, binding->target_property); |
781 | 0 | break; |
782 | | |
783 | 0 | case PROP_FLAGS: |
784 | 0 | g_value_set_flags (value, binding->flags); |
785 | 0 | break; |
786 | | |
787 | 0 | default: |
788 | 0 | G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); |
789 | 0 | break; |
790 | 0 | } |
791 | 0 | } |
792 | | |
793 | | static void |
794 | | g_binding_constructed (GObject *gobject) |
795 | 0 | { |
796 | 0 | GBinding *binding = G_BINDING (gobject); |
797 | 0 | GBindingTransformFunc transform_func = default_transform; |
798 | 0 | GObject *source, *target; |
799 | 0 | GQuark source_property_detail; |
800 | 0 | GClosure *source_notify_closure; |
801 | | |
802 | | /* assert that we were constructed correctly */ |
803 | 0 | source = g_weak_ref_get (&binding->context->source); |
804 | 0 | target = g_weak_ref_get (&binding->context->target); |
805 | 0 | g_assert (source != NULL); |
806 | 0 | g_assert (target != NULL); |
807 | 0 | g_assert (binding->source_property != NULL); |
808 | 0 | g_assert (binding->target_property != NULL); |
809 | | |
810 | | /* we assume a check was performed prior to construction - since |
811 | | * g_object_bind_property_full() does it; we cannot fail construction |
812 | | * anyway, so it would be hard for use to properly warn here |
813 | | */ |
814 | 0 | binding->source_pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (source), binding->source_property); |
815 | 0 | binding->target_pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (target), binding->target_property); |
816 | 0 | g_assert (binding->source_pspec != NULL); |
817 | 0 | g_assert (binding->target_pspec != NULL); |
818 | | |
819 | | /* switch to the invert boolean transform if needed */ |
820 | 0 | if (binding->flags & G_BINDING_INVERT_BOOLEAN) |
821 | 0 | transform_func = default_invert_boolean_transform; |
822 | | |
823 | | /* set the default transformation functions here */ |
824 | 0 | binding->transform_func = transform_func_new (transform_func, transform_func, NULL, NULL); |
825 | |
|
826 | 0 | source_property_detail = g_quark_from_string (binding->source_property); |
827 | 0 | source_notify_closure = g_cclosure_new (G_CALLBACK (on_source_notify), |
828 | 0 | binding_context_ref (binding->context), |
829 | 0 | (GClosureNotify) binding_context_unref); |
830 | 0 | binding->source_notify = g_signal_connect_closure_by_id (source, |
831 | 0 | gobject_notify_signal_id, |
832 | 0 | source_property_detail, |
833 | 0 | source_notify_closure, |
834 | 0 | FALSE); |
835 | |
|
836 | 0 | g_object_weak_ref (source, weak_unbind, binding_context_ref (binding->context)); |
837 | |
|
838 | 0 | if (binding->flags & G_BINDING_BIDIRECTIONAL) |
839 | 0 | { |
840 | 0 | GQuark target_property_detail; |
841 | 0 | GClosure *target_notify_closure; |
842 | |
|
843 | 0 | target_property_detail = g_quark_from_string (binding->target_property); |
844 | 0 | target_notify_closure = g_cclosure_new (G_CALLBACK (on_target_notify), |
845 | 0 | binding_context_ref (binding->context), |
846 | 0 | (GClosureNotify) binding_context_unref); |
847 | 0 | binding->target_notify = g_signal_connect_closure_by_id (target, |
848 | 0 | gobject_notify_signal_id, |
849 | 0 | target_property_detail, |
850 | 0 | target_notify_closure, |
851 | 0 | FALSE); |
852 | 0 | } |
853 | |
|
854 | 0 | if (target != source) |
855 | 0 | { |
856 | 0 | g_object_weak_ref (target, weak_unbind, binding_context_ref (binding->context)); |
857 | | |
858 | | /* Need to remember separately if a target weak notify was installed as |
859 | | * unlike for the source it can exist independently of the property |
860 | | * notification callback */ |
861 | 0 | binding->target_weak_notify_installed = TRUE; |
862 | 0 | } |
863 | |
|
864 | 0 | g_object_unref (source); |
865 | 0 | g_object_unref (target); |
866 | 0 | } |
867 | | |
868 | | static void |
869 | | g_binding_class_init (GBindingClass *klass) |
870 | 0 | { |
871 | 0 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
872 | |
|
873 | 0 | gobject_notify_signal_id = g_signal_lookup ("notify", G_TYPE_OBJECT); |
874 | 0 | g_assert (gobject_notify_signal_id != 0); |
875 | | |
876 | 0 | gobject_class->constructed = g_binding_constructed; |
877 | 0 | gobject_class->set_property = g_binding_set_property; |
878 | 0 | gobject_class->get_property = g_binding_get_property; |
879 | 0 | gobject_class->finalize = g_binding_finalize; |
880 | | |
881 | | /** |
882 | | * GBinding:source: |
883 | | * |
884 | | * The #GObject that should be used as the source of the binding |
885 | | * |
886 | | * Since: 2.26 |
887 | | */ |
888 | 0 | g_object_class_install_property (gobject_class, PROP_SOURCE, |
889 | 0 | g_param_spec_object ("source", NULL, NULL, |
890 | 0 | G_TYPE_OBJECT, |
891 | 0 | G_PARAM_CONSTRUCT_ONLY | |
892 | 0 | G_PARAM_READWRITE | |
893 | 0 | G_PARAM_STATIC_STRINGS)); |
894 | | /** |
895 | | * GBinding:target: |
896 | | * |
897 | | * The #GObject that should be used as the target of the binding |
898 | | * |
899 | | * Since: 2.26 |
900 | | */ |
901 | 0 | g_object_class_install_property (gobject_class, PROP_TARGET, |
902 | 0 | g_param_spec_object ("target", NULL, NULL, |
903 | 0 | G_TYPE_OBJECT, |
904 | 0 | G_PARAM_CONSTRUCT_ONLY | |
905 | 0 | G_PARAM_READWRITE | |
906 | 0 | G_PARAM_STATIC_STRINGS)); |
907 | | /** |
908 | | * GBinding:source-property: |
909 | | * |
910 | | * The name of the property of #GBinding:source that should be used |
911 | | * as the source of the binding. |
912 | | * |
913 | | * This should be in [canonical form][canonical-parameter-names] to get the |
914 | | * best performance. |
915 | | * |
916 | | * Since: 2.26 |
917 | | */ |
918 | 0 | g_object_class_install_property (gobject_class, PROP_SOURCE_PROPERTY, |
919 | 0 | g_param_spec_string ("source-property", NULL, NULL, |
920 | 0 | NULL, |
921 | 0 | G_PARAM_CONSTRUCT_ONLY | |
922 | 0 | G_PARAM_READWRITE | |
923 | 0 | G_PARAM_STATIC_STRINGS)); |
924 | | /** |
925 | | * GBinding:target-property: |
926 | | * |
927 | | * The name of the property of #GBinding:target that should be used |
928 | | * as the target of the binding. |
929 | | * |
930 | | * This should be in [canonical form][canonical-parameter-names] to get the |
931 | | * best performance. |
932 | | * |
933 | | * Since: 2.26 |
934 | | */ |
935 | 0 | g_object_class_install_property (gobject_class, PROP_TARGET_PROPERTY, |
936 | 0 | g_param_spec_string ("target-property", NULL, NULL, |
937 | 0 | NULL, |
938 | 0 | G_PARAM_CONSTRUCT_ONLY | |
939 | 0 | G_PARAM_READWRITE | |
940 | 0 | G_PARAM_STATIC_STRINGS)); |
941 | | /** |
942 | | * GBinding:flags: |
943 | | * |
944 | | * Flags to be used to control the #GBinding |
945 | | * |
946 | | * Since: 2.26 |
947 | | */ |
948 | 0 | g_object_class_install_property (gobject_class, PROP_FLAGS, |
949 | 0 | g_param_spec_flags ("flags", NULL, NULL, |
950 | 0 | G_TYPE_BINDING_FLAGS, |
951 | 0 | G_BINDING_DEFAULT, |
952 | 0 | G_PARAM_CONSTRUCT_ONLY | |
953 | 0 | G_PARAM_READWRITE | |
954 | 0 | G_PARAM_STATIC_STRINGS)); |
955 | 0 | } |
956 | | |
957 | | static void |
958 | | g_binding_init (GBinding *binding) |
959 | 0 | { |
960 | 0 | g_mutex_init (&binding->unbind_lock); |
961 | |
|
962 | 0 | binding->context = g_atomic_rc_box_new0 (BindingContext); |
963 | 0 | g_weak_ref_init (&binding->context->binding, binding); |
964 | 0 | g_weak_ref_init (&binding->context->source, NULL); |
965 | 0 | g_weak_ref_init (&binding->context->target, NULL); |
966 | 0 | } |
967 | | |
968 | | /** |
969 | | * g_binding_get_flags: |
970 | | * @binding: a #GBinding |
971 | | * |
972 | | * Retrieves the flags passed when constructing the #GBinding. |
973 | | * |
974 | | * Returns: the #GBindingFlags used by the #GBinding |
975 | | * |
976 | | * Since: 2.26 |
977 | | */ |
978 | | GBindingFlags |
979 | | g_binding_get_flags (GBinding *binding) |
980 | 0 | { |
981 | 0 | g_return_val_if_fail (G_IS_BINDING (binding), G_BINDING_DEFAULT); |
982 | | |
983 | 0 | return binding->flags; |
984 | 0 | } |
985 | | |
986 | | /** |
987 | | * g_binding_get_source: |
988 | | * @binding: a #GBinding |
989 | | * |
990 | | * Retrieves the #GObject instance used as the source of the binding. |
991 | | * |
992 | | * A #GBinding can outlive the source #GObject as the binding does not hold a |
993 | | * strong reference to the source. If the source is destroyed before the |
994 | | * binding then this function will return %NULL. |
995 | | * |
996 | | * Use g_binding_dup_source() if the source or binding are used from different |
997 | | * threads as otherwise the pointer returned from this function might become |
998 | | * invalid if the source is finalized from another thread in the meantime. |
999 | | * |
1000 | | * Returns: (transfer none) (nullable): the source #GObject, or %NULL if the |
1001 | | * source does not exist any more. |
1002 | | * |
1003 | | * Deprecated: 2.68: Use g_binding_dup_source() for a safer version of this |
1004 | | * function. |
1005 | | * |
1006 | | * Since: 2.26 |
1007 | | */ |
1008 | | GObject * |
1009 | | g_binding_get_source (GBinding *binding) |
1010 | 0 | { |
1011 | 0 | GObject *source; |
1012 | |
|
1013 | 0 | g_return_val_if_fail (G_IS_BINDING (binding), NULL); |
1014 | | |
1015 | 0 | source = g_weak_ref_get (&binding->context->source); |
1016 | | /* Unref here, this API is not thread-safe |
1017 | | * FIXME: Remove this API when we next break API */ |
1018 | 0 | if (source) |
1019 | 0 | g_object_unref (source); |
1020 | |
|
1021 | 0 | return source; |
1022 | 0 | } |
1023 | | |
1024 | | /** |
1025 | | * g_binding_dup_source: |
1026 | | * @binding: a #GBinding |
1027 | | * |
1028 | | * Retrieves the #GObject instance used as the source of the binding. |
1029 | | * |
1030 | | * A #GBinding can outlive the source #GObject as the binding does not hold a |
1031 | | * strong reference to the source. If the source is destroyed before the |
1032 | | * binding then this function will return %NULL. |
1033 | | * |
1034 | | * Returns: (transfer full) (nullable): the source #GObject, or %NULL if the |
1035 | | * source does not exist any more. |
1036 | | * |
1037 | | * Since: 2.68 |
1038 | | */ |
1039 | | GObject * |
1040 | | g_binding_dup_source (GBinding *binding) |
1041 | 0 | { |
1042 | 0 | g_return_val_if_fail (G_IS_BINDING (binding), NULL); |
1043 | | |
1044 | 0 | return g_weak_ref_get (&binding->context->source); |
1045 | 0 | } |
1046 | | |
1047 | | /** |
1048 | | * g_binding_get_target: |
1049 | | * @binding: a #GBinding |
1050 | | * |
1051 | | * Retrieves the #GObject instance used as the target of the binding. |
1052 | | * |
1053 | | * A #GBinding can outlive the target #GObject as the binding does not hold a |
1054 | | * strong reference to the target. If the target is destroyed before the |
1055 | | * binding then this function will return %NULL. |
1056 | | * |
1057 | | * Use g_binding_dup_target() if the target or binding are used from different |
1058 | | * threads as otherwise the pointer returned from this function might become |
1059 | | * invalid if the target is finalized from another thread in the meantime. |
1060 | | * |
1061 | | * Returns: (transfer none) (nullable): the target #GObject, or %NULL if the |
1062 | | * target does not exist any more. |
1063 | | * |
1064 | | * Deprecated: 2.68: Use g_binding_dup_target() for a safer version of this |
1065 | | * function. |
1066 | | * |
1067 | | * Since: 2.26 |
1068 | | */ |
1069 | | GObject * |
1070 | | g_binding_get_target (GBinding *binding) |
1071 | 0 | { |
1072 | 0 | GObject *target; |
1073 | |
|
1074 | 0 | g_return_val_if_fail (G_IS_BINDING (binding), NULL); |
1075 | | |
1076 | 0 | target = g_weak_ref_get (&binding->context->target); |
1077 | | /* Unref here, this API is not thread-safe |
1078 | | * FIXME: Remove this API when we next break API */ |
1079 | 0 | if (target) |
1080 | 0 | g_object_unref (target); |
1081 | |
|
1082 | 0 | return target; |
1083 | 0 | } |
1084 | | |
1085 | | /** |
1086 | | * g_binding_dup_target: |
1087 | | * @binding: a #GBinding |
1088 | | * |
1089 | | * Retrieves the #GObject instance used as the target of the binding. |
1090 | | * |
1091 | | * A #GBinding can outlive the target #GObject as the binding does not hold a |
1092 | | * strong reference to the target. If the target is destroyed before the |
1093 | | * binding then this function will return %NULL. |
1094 | | * |
1095 | | * Returns: (transfer full) (nullable): the target #GObject, or %NULL if the |
1096 | | * target does not exist any more. |
1097 | | * |
1098 | | * Since: 2.68 |
1099 | | */ |
1100 | | GObject * |
1101 | | g_binding_dup_target (GBinding *binding) |
1102 | 0 | { |
1103 | 0 | g_return_val_if_fail (G_IS_BINDING (binding), NULL); |
1104 | | |
1105 | 0 | return g_weak_ref_get (&binding->context->target); |
1106 | 0 | } |
1107 | | |
1108 | | /** |
1109 | | * g_binding_get_source_property: |
1110 | | * @binding: a #GBinding |
1111 | | * |
1112 | | * Retrieves the name of the property of #GBinding:source used as the source |
1113 | | * of the binding. |
1114 | | * |
1115 | | * Returns: the name of the source property |
1116 | | * |
1117 | | * Since: 2.26 |
1118 | | */ |
1119 | | const gchar * |
1120 | | g_binding_get_source_property (GBinding *binding) |
1121 | 0 | { |
1122 | 0 | g_return_val_if_fail (G_IS_BINDING (binding), NULL); |
1123 | | |
1124 | 0 | return binding->source_property; |
1125 | 0 | } |
1126 | | |
1127 | | /** |
1128 | | * g_binding_get_target_property: |
1129 | | * @binding: a #GBinding |
1130 | | * |
1131 | | * Retrieves the name of the property of #GBinding:target used as the target |
1132 | | * of the binding. |
1133 | | * |
1134 | | * Returns: the name of the target property |
1135 | | * |
1136 | | * Since: 2.26 |
1137 | | */ |
1138 | | const gchar * |
1139 | | g_binding_get_target_property (GBinding *binding) |
1140 | 0 | { |
1141 | 0 | g_return_val_if_fail (G_IS_BINDING (binding), NULL); |
1142 | | |
1143 | 0 | return binding->target_property; |
1144 | 0 | } |
1145 | | |
1146 | | /** |
1147 | | * g_binding_unbind: |
1148 | | * @binding: a #GBinding |
1149 | | * |
1150 | | * Explicitly releases the binding between the source and the target |
1151 | | * property expressed by @binding. |
1152 | | * |
1153 | | * This function will release the reference that is being held on |
1154 | | * the @binding instance if the binding is still bound; if you want to hold on |
1155 | | * to the #GBinding instance after calling g_binding_unbind(), you will need |
1156 | | * to hold a reference to it. |
1157 | | * |
1158 | | * Note however that this function does not take ownership of @binding, it |
1159 | | * only unrefs the reference that was initially created by |
1160 | | * g_object_bind_property() and is owned by the binding. |
1161 | | * |
1162 | | * Since: 2.38 |
1163 | | */ |
1164 | | void |
1165 | | g_binding_unbind (GBinding *binding) |
1166 | 0 | { |
1167 | 0 | g_return_if_fail (G_IS_BINDING (binding)); |
1168 | | |
1169 | 0 | g_binding_unbind_internal (binding, TRUE); |
1170 | 0 | } |
1171 | | |
1172 | | /** |
1173 | | * g_object_bind_property_full: |
1174 | | * @source: (type GObject.Object): the source #GObject |
1175 | | * @source_property: the property on @source to bind |
1176 | | * @target: (type GObject.Object): the target #GObject |
1177 | | * @target_property: the property on @target to bind |
1178 | | * @flags: flags to pass to #GBinding |
1179 | | * @transform_to: (scope notified) (nullable): the transformation function |
1180 | | * from the @source to the @target, or %NULL to use the default |
1181 | | * @transform_from: (scope notified) (nullable): the transformation function |
1182 | | * from the @target to the @source, or %NULL to use the default |
1183 | | * @user_data: custom data to be passed to the transformation functions, |
1184 | | * or %NULL |
1185 | | * @notify: (nullable): a function to call when disposing the binding, to free |
1186 | | * resources used by the transformation functions, or %NULL if not required |
1187 | | * |
1188 | | * Complete version of g_object_bind_property(). |
1189 | | * |
1190 | | * Creates a binding between @source_property on @source and @target_property |
1191 | | * on @target, allowing you to set the transformation functions to be used by |
1192 | | * the binding. |
1193 | | * |
1194 | | * If @flags contains %G_BINDING_BIDIRECTIONAL then the binding will be mutual: |
1195 | | * if @target_property on @target changes then the @source_property on @source |
1196 | | * will be updated as well. The @transform_from function is only used in case |
1197 | | * of bidirectional bindings, otherwise it will be ignored |
1198 | | * |
1199 | | * The binding will automatically be removed when either the @source or the |
1200 | | * @target instances are finalized. This will release the reference that is |
1201 | | * being held on the #GBinding instance; if you want to hold on to the |
1202 | | * #GBinding instance, you will need to hold a reference to it. |
1203 | | * |
1204 | | * To remove the binding, call g_binding_unbind(). |
1205 | | * |
1206 | | * A #GObject can have multiple bindings. |
1207 | | * |
1208 | | * The same @user_data parameter will be used for both @transform_to |
1209 | | * and @transform_from transformation functions; the @notify function will |
1210 | | * be called once, when the binding is removed. If you need different data |
1211 | | * for each transformation function, please use |
1212 | | * g_object_bind_property_with_closures() instead. |
1213 | | * |
1214 | | * Returns: (transfer none): the #GBinding instance representing the |
1215 | | * binding between the two #GObject instances. The binding is released |
1216 | | * whenever the #GBinding reference count reaches zero. |
1217 | | * |
1218 | | * Since: 2.26 |
1219 | | */ |
1220 | | GBinding * |
1221 | | g_object_bind_property_full (gpointer source, |
1222 | | const gchar *source_property, |
1223 | | gpointer target, |
1224 | | const gchar *target_property, |
1225 | | GBindingFlags flags, |
1226 | | GBindingTransformFunc transform_to, |
1227 | | GBindingTransformFunc transform_from, |
1228 | | gpointer user_data, |
1229 | | GDestroyNotify notify) |
1230 | 0 | { |
1231 | 0 | GParamSpec *pspec; |
1232 | 0 | GBinding *binding; |
1233 | |
|
1234 | 0 | g_return_val_if_fail (G_IS_OBJECT (source), NULL); |
1235 | 0 | g_return_val_if_fail (source_property != NULL, NULL); |
1236 | 0 | g_return_val_if_fail (g_param_spec_is_valid_name (source_property), NULL); |
1237 | 0 | g_return_val_if_fail (G_IS_OBJECT (target), NULL); |
1238 | 0 | g_return_val_if_fail (target_property != NULL, NULL); |
1239 | 0 | g_return_val_if_fail (g_param_spec_is_valid_name (target_property), NULL); |
1240 | | |
1241 | 0 | if (source == target && g_strcmp0 (source_property, target_property) == 0) |
1242 | 0 | { |
1243 | 0 | g_critical ("Unable to bind the same property on the same instance"); |
1244 | 0 | return NULL; |
1245 | 0 | } |
1246 | | |
1247 | | /* remove the G_BINDING_INVERT_BOOLEAN flag in case we have |
1248 | | * custom transformation functions |
1249 | | */ |
1250 | 0 | if ((flags & G_BINDING_INVERT_BOOLEAN) && |
1251 | 0 | (transform_to != NULL || transform_from != NULL)) |
1252 | 0 | { |
1253 | 0 | flags &= ~G_BINDING_INVERT_BOOLEAN; |
1254 | 0 | } |
1255 | |
|
1256 | 0 | pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (source), source_property); |
1257 | 0 | if (pspec == NULL) |
1258 | 0 | { |
1259 | 0 | g_critical ("%s: The source object of type %s has no property called '%s'", |
1260 | 0 | G_STRLOC, |
1261 | 0 | G_OBJECT_TYPE_NAME (source), |
1262 | 0 | source_property); |
1263 | 0 | return NULL; |
1264 | 0 | } |
1265 | | |
1266 | 0 | if (!(pspec->flags & G_PARAM_READABLE)) |
1267 | 0 | { |
1268 | 0 | g_critical ("%s: The source object of type %s has no readable property called '%s'", |
1269 | 0 | G_STRLOC, |
1270 | 0 | G_OBJECT_TYPE_NAME (source), |
1271 | 0 | source_property); |
1272 | 0 | return NULL; |
1273 | 0 | } |
1274 | | |
1275 | 0 | if ((flags & G_BINDING_BIDIRECTIONAL) && |
1276 | 0 | ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) || !(pspec->flags & G_PARAM_WRITABLE))) |
1277 | 0 | { |
1278 | 0 | g_critical ("%s: The source object of type %s has no writable property called '%s'", |
1279 | 0 | G_STRLOC, |
1280 | 0 | G_OBJECT_TYPE_NAME (source), |
1281 | 0 | source_property); |
1282 | 0 | return NULL; |
1283 | 0 | } |
1284 | | |
1285 | 0 | if ((flags & G_BINDING_INVERT_BOOLEAN) && |
1286 | 0 | !(G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_BOOLEAN)) |
1287 | 0 | { |
1288 | 0 | g_critical ("%s: The G_BINDING_INVERT_BOOLEAN flag can only be used " |
1289 | 0 | "when binding boolean properties; the source property '%s' " |
1290 | 0 | "is of type '%s'", |
1291 | 0 | G_STRLOC, |
1292 | 0 | source_property, |
1293 | 0 | g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec))); |
1294 | 0 | return NULL; |
1295 | 0 | } |
1296 | | |
1297 | 0 | pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (target), target_property); |
1298 | 0 | if (pspec == NULL) |
1299 | 0 | { |
1300 | 0 | g_critical ("%s: The target object of type %s has no property called '%s'", |
1301 | 0 | G_STRLOC, |
1302 | 0 | G_OBJECT_TYPE_NAME (target), |
1303 | 0 | target_property); |
1304 | 0 | return NULL; |
1305 | 0 | } |
1306 | | |
1307 | 0 | if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) || !(pspec->flags & G_PARAM_WRITABLE)) |
1308 | 0 | { |
1309 | 0 | g_critical ("%s: The target object of type %s has no writable property called '%s'", |
1310 | 0 | G_STRLOC, |
1311 | 0 | G_OBJECT_TYPE_NAME (target), |
1312 | 0 | target_property); |
1313 | 0 | return NULL; |
1314 | 0 | } |
1315 | | |
1316 | 0 | if ((flags & G_BINDING_BIDIRECTIONAL) && |
1317 | 0 | !(pspec->flags & G_PARAM_READABLE)) |
1318 | 0 | { |
1319 | 0 | g_critical ("%s: The target object of type %s has no readable property called '%s'", |
1320 | 0 | G_STRLOC, |
1321 | 0 | G_OBJECT_TYPE_NAME (target), |
1322 | 0 | target_property); |
1323 | 0 | return NULL; |
1324 | 0 | } |
1325 | | |
1326 | 0 | if ((flags & G_BINDING_INVERT_BOOLEAN) && |
1327 | 0 | !(G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_BOOLEAN)) |
1328 | 0 | { |
1329 | 0 | g_critical ("%s: The G_BINDING_INVERT_BOOLEAN flag can only be used " |
1330 | 0 | "when binding boolean properties; the target property '%s' " |
1331 | 0 | "is of type '%s'", |
1332 | 0 | G_STRLOC, |
1333 | 0 | target_property, |
1334 | 0 | g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec))); |
1335 | 0 | return NULL; |
1336 | 0 | } |
1337 | | |
1338 | 0 | binding = g_object_new (G_TYPE_BINDING, |
1339 | 0 | "source", source, |
1340 | 0 | "source-property", source_property, |
1341 | 0 | "target", target, |
1342 | 0 | "target-property", target_property, |
1343 | 0 | "flags", flags, |
1344 | 0 | NULL); |
1345 | |
|
1346 | 0 | g_assert (binding->transform_func != NULL); |
1347 | | |
1348 | | /* Use default functions if not provided here */ |
1349 | 0 | if (transform_to == NULL) |
1350 | 0 | transform_to = binding->transform_func->transform_s2t; |
1351 | |
|
1352 | 0 | if (transform_from == NULL) |
1353 | 0 | transform_from = binding->transform_func->transform_t2s; |
1354 | |
|
1355 | 0 | g_clear_pointer (&binding->transform_func, transform_func_unref); |
1356 | 0 | binding->transform_func = transform_func_new (transform_to, transform_from, user_data, notify); |
1357 | | |
1358 | | /* synchronize the target with the source by faking an emission of |
1359 | | * the ::notify signal for the source property; this will also take |
1360 | | * care of the bidirectional binding case because the eventual change |
1361 | | * will emit a notification on the target |
1362 | | */ |
1363 | 0 | if (flags & G_BINDING_SYNC_CREATE) |
1364 | 0 | on_source_notify (source, binding->source_pspec, binding->context); |
1365 | |
|
1366 | 0 | return binding; |
1367 | 0 | } |
1368 | | |
1369 | | /** |
1370 | | * g_object_bind_property: |
1371 | | * @source: (type GObject.Object): the source #GObject |
1372 | | * @source_property: the property on @source to bind |
1373 | | * @target: (type GObject.Object): the target #GObject |
1374 | | * @target_property: the property on @target to bind |
1375 | | * @flags: flags to pass to #GBinding |
1376 | | * |
1377 | | * Creates a binding between @source_property on @source and @target_property |
1378 | | * on @target. |
1379 | | * |
1380 | | * Whenever the @source_property is changed the @target_property is |
1381 | | * updated using the same value. For instance: |
1382 | | * |
1383 | | * |[<!-- language="C" --> |
1384 | | * g_object_bind_property (action, "active", widget, "sensitive", 0); |
1385 | | * ]| |
1386 | | * |
1387 | | * Will result in the "sensitive" property of the widget #GObject instance to be |
1388 | | * updated with the same value of the "active" property of the action #GObject |
1389 | | * instance. |
1390 | | * |
1391 | | * If @flags contains %G_BINDING_BIDIRECTIONAL then the binding will be mutual: |
1392 | | * if @target_property on @target changes then the @source_property on @source |
1393 | | * will be updated as well. |
1394 | | * |
1395 | | * The binding will automatically be removed when either the @source or the |
1396 | | * @target instances are finalized. To remove the binding without affecting the |
1397 | | * @source and the @target you can just call g_object_unref() on the returned |
1398 | | * #GBinding instance. |
1399 | | * |
1400 | | * Removing the binding by calling g_object_unref() on it must only be done if |
1401 | | * the binding, @source and @target are only used from a single thread and it |
1402 | | * is clear that both @source and @target outlive the binding. Especially it |
1403 | | * is not safe to rely on this if the binding, @source or @target can be |
1404 | | * finalized from different threads. Keep another reference to the binding and |
1405 | | * use g_binding_unbind() instead to be on the safe side. |
1406 | | * |
1407 | | * A #GObject can have multiple bindings. |
1408 | | * |
1409 | | * Returns: (transfer none): the #GBinding instance representing the |
1410 | | * binding between the two #GObject instances. The binding is released |
1411 | | * whenever the #GBinding reference count reaches zero. |
1412 | | * |
1413 | | * Since: 2.26 |
1414 | | */ |
1415 | | GBinding * |
1416 | | g_object_bind_property (gpointer source, |
1417 | | const gchar *source_property, |
1418 | | gpointer target, |
1419 | | const gchar *target_property, |
1420 | | GBindingFlags flags) |
1421 | 0 | { |
1422 | | /* type checking is done in g_object_bind_property_full() */ |
1423 | |
|
1424 | 0 | return g_object_bind_property_full (source, source_property, |
1425 | 0 | target, target_property, |
1426 | 0 | flags, |
1427 | 0 | NULL, |
1428 | 0 | NULL, |
1429 | 0 | NULL, NULL); |
1430 | 0 | } |
1431 | | |
1432 | | typedef struct _TransformData |
1433 | | { |
1434 | | GClosure *transform_to_closure; |
1435 | | GClosure *transform_from_closure; |
1436 | | } TransformData; |
1437 | | |
1438 | | static gboolean |
1439 | | bind_with_closures_transform_to (GBinding *binding, |
1440 | | const GValue *source, |
1441 | | GValue *target, |
1442 | | gpointer data) |
1443 | 0 | { |
1444 | 0 | TransformData *t_data = data; |
1445 | 0 | GValue params[3] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT }; |
1446 | 0 | GValue retval = G_VALUE_INIT; |
1447 | 0 | gboolean res; |
1448 | |
|
1449 | 0 | g_value_init (¶ms[0], G_TYPE_BINDING); |
1450 | 0 | g_value_set_object (¶ms[0], binding); |
1451 | |
|
1452 | 0 | g_value_init (¶ms[1], G_TYPE_VALUE); |
1453 | 0 | g_value_set_boxed (¶ms[1], source); |
1454 | |
|
1455 | 0 | g_value_init (¶ms[2], G_TYPE_VALUE); |
1456 | 0 | g_value_set_boxed (¶ms[2], target); |
1457 | |
|
1458 | 0 | g_value_init (&retval, G_TYPE_BOOLEAN); |
1459 | 0 | g_value_set_boolean (&retval, FALSE); |
1460 | |
|
1461 | 0 | g_closure_invoke (t_data->transform_to_closure, &retval, 3, params, NULL); |
1462 | |
|
1463 | 0 | res = g_value_get_boolean (&retval); |
1464 | 0 | if (res) |
1465 | 0 | { |
1466 | 0 | const GValue *out_value = g_value_get_boxed (¶ms[2]); |
1467 | |
|
1468 | 0 | g_assert (out_value != NULL); |
1469 | | |
1470 | 0 | g_value_copy (out_value, target); |
1471 | 0 | } |
1472 | | |
1473 | 0 | g_value_unset (¶ms[0]); |
1474 | 0 | g_value_unset (¶ms[1]); |
1475 | 0 | g_value_unset (¶ms[2]); |
1476 | 0 | g_value_unset (&retval); |
1477 | |
|
1478 | 0 | return res; |
1479 | 0 | } |
1480 | | |
1481 | | static gboolean |
1482 | | bind_with_closures_transform_from (GBinding *binding, |
1483 | | const GValue *source, |
1484 | | GValue *target, |
1485 | | gpointer data) |
1486 | 0 | { |
1487 | 0 | TransformData *t_data = data; |
1488 | 0 | GValue params[3] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT }; |
1489 | 0 | GValue retval = G_VALUE_INIT; |
1490 | 0 | gboolean res; |
1491 | |
|
1492 | 0 | g_value_init (¶ms[0], G_TYPE_BINDING); |
1493 | 0 | g_value_set_object (¶ms[0], binding); |
1494 | |
|
1495 | 0 | g_value_init (¶ms[1], G_TYPE_VALUE); |
1496 | 0 | g_value_set_boxed (¶ms[1], source); |
1497 | |
|
1498 | 0 | g_value_init (¶ms[2], G_TYPE_VALUE); |
1499 | 0 | g_value_set_boxed (¶ms[2], target); |
1500 | |
|
1501 | 0 | g_value_init (&retval, G_TYPE_BOOLEAN); |
1502 | 0 | g_value_set_boolean (&retval, FALSE); |
1503 | |
|
1504 | 0 | g_closure_invoke (t_data->transform_from_closure, &retval, 3, params, NULL); |
1505 | |
|
1506 | 0 | res = g_value_get_boolean (&retval); |
1507 | 0 | if (res) |
1508 | 0 | { |
1509 | 0 | const GValue *out_value = g_value_get_boxed (¶ms[2]); |
1510 | |
|
1511 | 0 | g_assert (out_value != NULL); |
1512 | | |
1513 | 0 | g_value_copy (out_value, target); |
1514 | 0 | } |
1515 | | |
1516 | 0 | g_value_unset (¶ms[0]); |
1517 | 0 | g_value_unset (¶ms[1]); |
1518 | 0 | g_value_unset (¶ms[2]); |
1519 | 0 | g_value_unset (&retval); |
1520 | |
|
1521 | 0 | return res; |
1522 | 0 | } |
1523 | | |
1524 | | static void |
1525 | | bind_with_closures_free_func (gpointer data) |
1526 | 0 | { |
1527 | 0 | TransformData *t_data = data; |
1528 | |
|
1529 | 0 | if (t_data->transform_to_closure != NULL) |
1530 | 0 | g_closure_unref (t_data->transform_to_closure); |
1531 | |
|
1532 | 0 | if (t_data->transform_from_closure != NULL) |
1533 | 0 | g_closure_unref (t_data->transform_from_closure); |
1534 | |
|
1535 | 0 | g_slice_free (TransformData, t_data); |
1536 | 0 | } |
1537 | | |
1538 | | /** |
1539 | | * g_object_bind_property_with_closures: (rename-to g_object_bind_property_full) |
1540 | | * @source: (type GObject.Object): the source #GObject |
1541 | | * @source_property: the property on @source to bind |
1542 | | * @target: (type GObject.Object): the target #GObject |
1543 | | * @target_property: the property on @target to bind |
1544 | | * @flags: flags to pass to #GBinding |
1545 | | * @transform_to: a #GClosure wrapping the transformation function |
1546 | | * from the @source to the @target, or %NULL to use the default |
1547 | | * @transform_from: a #GClosure wrapping the transformation function |
1548 | | * from the @target to the @source, or %NULL to use the default |
1549 | | * |
1550 | | * Creates a binding between @source_property on @source and @target_property |
1551 | | * on @target, allowing you to set the transformation functions to be used by |
1552 | | * the binding. |
1553 | | * |
1554 | | * This function is the language bindings friendly version of |
1555 | | * g_object_bind_property_full(), using #GClosures instead of |
1556 | | * function pointers. |
1557 | | * |
1558 | | * Returns: (transfer none): the #GBinding instance representing the |
1559 | | * binding between the two #GObject instances. The binding is released |
1560 | | * whenever the #GBinding reference count reaches zero. |
1561 | | * |
1562 | | * Since: 2.26 |
1563 | | */ |
1564 | | GBinding * |
1565 | | g_object_bind_property_with_closures (gpointer source, |
1566 | | const gchar *source_property, |
1567 | | gpointer target, |
1568 | | const gchar *target_property, |
1569 | | GBindingFlags flags, |
1570 | | GClosure *transform_to, |
1571 | | GClosure *transform_from) |
1572 | 0 | { |
1573 | 0 | TransformData *data; |
1574 | |
|
1575 | 0 | data = g_slice_new0 (TransformData); |
1576 | |
|
1577 | 0 | if (transform_to != NULL) |
1578 | 0 | { |
1579 | 0 | if (G_CLOSURE_NEEDS_MARSHAL (transform_to)) |
1580 | 0 | g_closure_set_marshal (transform_to, g_cclosure_marshal_BOOLEAN__BOXED_BOXED); |
1581 | |
|
1582 | 0 | data->transform_to_closure = g_closure_ref (transform_to); |
1583 | 0 | g_closure_sink (data->transform_to_closure); |
1584 | 0 | } |
1585 | |
|
1586 | 0 | if (transform_from != NULL) |
1587 | 0 | { |
1588 | 0 | if (G_CLOSURE_NEEDS_MARSHAL (transform_from)) |
1589 | 0 | g_closure_set_marshal (transform_from, g_cclosure_marshal_BOOLEAN__BOXED_BOXED); |
1590 | |
|
1591 | 0 | data->transform_from_closure = g_closure_ref (transform_from); |
1592 | 0 | g_closure_sink (data->transform_from_closure); |
1593 | 0 | } |
1594 | |
|
1595 | 0 | return g_object_bind_property_full (source, source_property, |
1596 | 0 | target, target_property, |
1597 | 0 | flags, |
1598 | 0 | transform_to != NULL ? bind_with_closures_transform_to : NULL, |
1599 | 0 | transform_from != NULL ? bind_with_closures_transform_from : NULL, |
1600 | 0 | data, |
1601 | 0 | bind_with_closures_free_func); |
1602 | 0 | } |