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

source code of gtk/subprojects/glib/gobject/gbinding.c