Branch data Line data Source code
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 : 5 : g_binding_flags_get_type (void)
122 : : {
123 : : static GType static_g_define_type_id = 0;
124 : :
125 : 5 : if (g_once_init_enter_pointer (&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 : 4 : g_flags_register_static (g_intern_static_string ("GBindingFlags"), values);
136 : 4 : g_once_init_leave_pointer (&static_g_define_type_id, g_define_type_id);
137 : : }
138 : :
139 : 5 : 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 : : */
154 : : typedef struct {
155 : : GWeakRef binding;
156 : : GWeakRef source;
157 : : GWeakRef target;
158 : : gboolean binding_removed;
159 : : } BindingContext;
160 : :
161 : : static BindingContext *
162 : 613 : binding_context_ref (BindingContext *context)
163 : : {
164 : 613 : return g_atomic_rc_box_acquire (context);
165 : : }
166 : :
167 : : static void
168 : 162 : binding_context_clear (BindingContext *context)
169 : : {
170 : 162 : g_weak_ref_clear (&context->binding);
171 : 162 : g_weak_ref_clear (&context->source);
172 : 162 : g_weak_ref_clear (&context->target);
173 : 162 : }
174 : :
175 : : static void
176 : 775 : binding_context_unref (BindingContext *context)
177 : : {
178 : 775 : g_atomic_rc_box_release_full (context, (GDestroyNotify) binding_context_clear);
179 : 775 : }
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 : 324 : transform_func_new (GBindingTransformFunc transform_s2t,
197 : : GBindingTransformFunc transform_t2s,
198 : : gpointer transform_data,
199 : : GDestroyNotify destroy_notify)
200 : : {
201 : 324 : TransformFunc *func = g_atomic_rc_box_new0 (TransformFunc);
202 : :
203 : 324 : func->transform_s2t = transform_s2t;
204 : 324 : func->transform_t2s = transform_t2s;
205 : 324 : func->transform_data = transform_data;
206 : 324 : func->destroy_notify = destroy_notify;
207 : :
208 : 324 : return func;
209 : : }
210 : :
211 : : static TransformFunc *
212 : 101 : transform_func_ref (TransformFunc *func)
213 : : {
214 : 101 : return g_atomic_rc_box_acquire (func);
215 : : }
216 : :
217 : : static void
218 : 324 : transform_func_clear (TransformFunc *func)
219 : : {
220 : 324 : if (func->destroy_notify)
221 : 4 : func->destroy_notify (func->transform_data);
222 : 324 : }
223 : :
224 : : static void
225 : 425 : transform_func_unref (TransformFunc *func)
226 : : {
227 : 425 : g_atomic_rc_box_release_full (func, (GDestroyNotify) transform_func_clear);
228 : 425 : }
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 : 2084 : G_DEFINE_TYPE (GBinding, g_binding, G_TYPE_OBJECT)
286 : :
287 : : static 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. */
293 : : static gboolean
294 : 853 : unbind_internal_locked (BindingContext *context, GBinding *binding, GObject *source, GObject *target)
295 : : {
296 : 853 : gboolean binding_was_removed = FALSE;
297 : :
298 : 853 : g_assert (context != NULL);
299 : 853 : 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 : 853 : 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 : 105 : if (binding->source_notify != 0)
314 : : {
315 : 105 : g_signal_handler_disconnect (source, binding->source_notify);
316 : :
317 : 105 : g_object_weak_unref (source, weak_unbind, context);
318 : 105 : binding_context_unref (context);
319 : :
320 : 105 : binding->source_notify = 0;
321 : : }
322 : 105 : g_weak_ref_set (&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 : 853 : 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 : 114 : if (binding->target_notify != 0)
334 : : {
335 : 89 : g_signal_handler_disconnect (target, binding->target_notify);
336 : :
337 : 89 : binding->target_notify = 0;
338 : : }
339 : 114 : g_weak_ref_set (&context->target, NULL);
340 : :
341 : : /* Remove the weak notify from the target, at most once */
342 : 114 : if (binding->target_weak_notify_installed)
343 : : {
344 : 111 : g_object_weak_unref (target, weak_unbind, context);
345 : 111 : binding_context_unref (context);
346 : 111 : 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 : 853 : if (!context->binding_removed)
353 : : {
354 : 162 : context->binding_removed = TRUE;
355 : 162 : binding_was_removed = TRUE;
356 : : }
357 : :
358 : 853 : 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. */
365 : : static void
366 : 102 : weak_unbind (gpointer user_data,
367 : : GObject *where_the_object_was)
368 : : {
369 : 102 : BindingContext *context = user_data;
370 : : GBinding *binding;
371 : : GObject *source, *target;
372 : 102 : gboolean binding_was_removed = FALSE;
373 : : TransformFunc *transform_func;
374 : :
375 : 102 : binding = g_weak_ref_get (&context->binding);
376 : 102 : if (!binding)
377 : : {
378 : : /* The binding was already destroyed before so there's nothing to do */
379 : 0 : binding_context_unref (context);
380 : 0 : return;
381 : : }
382 : :
383 : 102 : g_mutex_lock (&binding->unbind_lock);
384 : :
385 : 102 : transform_func = g_steal_pointer (&binding->transform_func);
386 : :
387 : 102 : source = g_weak_ref_get (&context->source);
388 : 102 : 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 : 102 : if (source == where_the_object_was)
405 : : {
406 : 1 : g_weak_ref_set (&context->source, NULL);
407 : 1 : g_clear_object (&source);
408 : : }
409 : :
410 : 102 : if (target == where_the_object_was)
411 : : {
412 : 1 : g_weak_ref_set (&context->target, NULL);
413 : 1 : g_clear_object (&target);
414 : : }
415 : :
416 : 102 : binding_was_removed = unbind_internal_locked (context, binding, source, target);
417 : :
418 : 102 : 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 : 102 : g_clear_object (&target);
423 : 102 : g_clear_object (&source);
424 : :
425 : 102 : g_clear_pointer (&transform_func, transform_func_unref);
426 : :
427 : : /* This releases the strong reference we got from the weak ref above */
428 : 102 : g_object_unref (binding);
429 : :
430 : : /* This will take care of the binding itself. */
431 : 102 : if (binding_was_removed)
432 : 66 : g_object_unref (binding);
433 : :
434 : : /* Each weak notify owns a reference to the binding context. */
435 : 102 : binding_context_unref (context);
436 : : }
437 : :
438 : : static gboolean
439 : 88 : default_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 : 88 : 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 : 4 : if (g_value_type_compatible (G_VALUE_TYPE (value_a),
451 : : G_VALUE_TYPE (value_b)))
452 : : {
453 : 0 : g_value_copy (value_a, value_b);
454 : 0 : return TRUE;
455 : : }
456 : :
457 : 4 : if (g_value_type_transformable (G_VALUE_TYPE (value_a),
458 : : G_VALUE_TYPE (value_b)))
459 : : {
460 : 3 : if (g_value_transform (value_a, value_b))
461 : 3 : return TRUE;
462 : : }
463 : :
464 : 1 : g_critical ("%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 : 1 : return FALSE;
471 : : }
472 : :
473 : 84 : g_value_copy (value_a, value_b);
474 : 84 : return TRUE;
475 : : }
476 : :
477 : : static gboolean
478 : 2 : default_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 : 2 : g_assert (G_VALUE_HOLDS_BOOLEAN (value_a));
486 : 2 : g_assert (G_VALUE_HOLDS_BOOLEAN (value_b));
487 : :
488 : 2 : value = g_value_get_boolean (value_a);
489 : 2 : value = !value;
490 : :
491 : 2 : g_value_set_boolean (value_b, value);
492 : :
493 : 2 : return TRUE;
494 : : }
495 : :
496 : : static void
497 : 101 : on_source_notify (GObject *source,
498 : : GParamSpec *pspec,
499 : : BindingContext *context)
500 : : {
501 : : GBinding *binding;
502 : : GObject *target;
503 : : TransformFunc *transform_func;
504 : 101 : GValue from_value = G_VALUE_INIT;
505 : 101 : GValue to_value = G_VALUE_INIT;
506 : : gboolean res;
507 : :
508 : 101 : binding = g_weak_ref_get (&context->binding);
509 : 101 : if (!binding)
510 : 12 : return;
511 : :
512 : 101 : if (binding->is_frozen)
513 : : {
514 : 12 : g_object_unref (binding);
515 : 12 : return;
516 : : }
517 : :
518 : 89 : target = g_weak_ref_get (&context->target);
519 : 89 : if (!target)
520 : : {
521 : 0 : g_object_unref (binding);
522 : 0 : return;
523 : : }
524 : :
525 : : /* Get the transform function safely */
526 : 89 : g_mutex_lock (&binding->unbind_lock);
527 : 89 : if (!binding->transform_func)
528 : : {
529 : : /* it was released already during unbinding, nothing to do here */
530 : 0 : g_mutex_unlock (&binding->unbind_lock);
531 : 0 : return;
532 : : }
533 : 89 : transform_func = transform_func_ref (binding->transform_func);
534 : 89 : g_mutex_unlock (&binding->unbind_lock);
535 : :
536 : 89 : g_value_init (&from_value, G_PARAM_SPEC_VALUE_TYPE (binding->source_pspec));
537 : 89 : g_value_init (&to_value, G_PARAM_SPEC_VALUE_TYPE (binding->target_pspec));
538 : :
539 : 89 : g_object_get_property (source, binding->source_pspec->name, &from_value);
540 : :
541 : 89 : res = transform_func->transform_s2t (binding,
542 : : &from_value,
543 : : &to_value,
544 : : transform_func->transform_data);
545 : :
546 : 89 : transform_func_unref (transform_func);
547 : :
548 : 89 : if (res)
549 : : {
550 : 88 : binding->is_frozen = TRUE;
551 : :
552 : 88 : (void) g_param_value_validate (binding->target_pspec, &to_value);
553 : 88 : g_object_set_property (target, binding->target_pspec->name, &to_value);
554 : :
555 : 88 : binding->is_frozen = FALSE;
556 : : }
557 : :
558 : 89 : g_value_unset (&from_value);
559 : 89 : g_value_unset (&to_value);
560 : :
561 : 89 : g_object_unref (target);
562 : 89 : g_object_unref (binding);
563 : : }
564 : :
565 : : static void
566 : 68 : on_target_notify (GObject *target,
567 : : GParamSpec *pspec,
568 : : BindingContext *context)
569 : : {
570 : : GBinding *binding;
571 : : GObject *source;
572 : : TransformFunc *transform_func;
573 : 68 : GValue from_value = G_VALUE_INIT;
574 : 68 : GValue to_value = G_VALUE_INIT;
575 : : gboolean res;
576 : :
577 : 68 : binding = g_weak_ref_get (&context->binding);
578 : 68 : if (!binding)
579 : 56 : return;
580 : :
581 : 68 : if (binding->is_frozen)
582 : : {
583 : 56 : g_object_unref (binding);
584 : 56 : return;
585 : : }
586 : :
587 : 12 : source = g_weak_ref_get (&context->source);
588 : 12 : if (!source)
589 : : {
590 : 0 : g_object_unref (binding);
591 : 0 : return;
592 : : }
593 : :
594 : : /* Get the transform function safely */
595 : 12 : g_mutex_lock (&binding->unbind_lock);
596 : 12 : if (!binding->transform_func)
597 : : {
598 : : /* it was released already during unbinding, nothing to do here */
599 : 0 : g_mutex_unlock (&binding->unbind_lock);
600 : 0 : return;
601 : : }
602 : 12 : transform_func = transform_func_ref (binding->transform_func);
603 : 12 : g_mutex_unlock (&binding->unbind_lock);
604 : :
605 : 12 : g_value_init (&from_value, G_PARAM_SPEC_VALUE_TYPE (binding->target_pspec));
606 : 12 : g_value_init (&to_value, G_PARAM_SPEC_VALUE_TYPE (binding->source_pspec));
607 : :
608 : 12 : g_object_get_property (target, binding->target_pspec->name, &from_value);
609 : :
610 : 12 : res = transform_func->transform_t2s (binding,
611 : : &from_value,
612 : : &to_value,
613 : : transform_func->transform_data);
614 : 12 : transform_func_unref (transform_func);
615 : :
616 : 12 : if (res)
617 : : {
618 : 12 : binding->is_frozen = TRUE;
619 : :
620 : 12 : (void) g_param_value_validate (binding->source_pspec, &to_value);
621 : 12 : g_object_set_property (source, binding->source_pspec->name, &to_value);
622 : :
623 : 12 : binding->is_frozen = FALSE;
624 : : }
625 : :
626 : 12 : g_value_unset (&from_value);
627 : 12 : g_value_unset (&to_value);
628 : :
629 : 12 : g_object_unref (source);
630 : 12 : g_object_unref (binding);
631 : : }
632 : :
633 : : static inline void
634 : 751 : g_binding_unbind_internal (GBinding *binding,
635 : : gboolean unref_binding)
636 : : {
637 : 751 : BindingContext *context = binding->context;
638 : : GObject *source, *target;
639 : 751 : gboolean binding_was_removed = FALSE;
640 : : TransformFunc *transform_func;
641 : :
642 : 751 : g_mutex_lock (&binding->unbind_lock);
643 : :
644 : 751 : transform_func = g_steal_pointer (&binding->transform_func);
645 : :
646 : 751 : source = g_weak_ref_get (&context->source);
647 : 751 : target = g_weak_ref_get (&context->target);
648 : :
649 : 751 : binding_was_removed = unbind_internal_locked (context, binding, source, target);
650 : :
651 : 751 : 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 : 751 : g_clear_object (&target);
656 : 751 : g_clear_object (&source);
657 : :
658 : 751 : g_clear_pointer (&transform_func, transform_func_unref);
659 : :
660 : 751 : if (binding_was_removed && unref_binding)
661 : 90 : g_object_unref (binding);
662 : 751 : }
663 : :
664 : : static void
665 : 162 : g_binding_finalize (GObject *gobject)
666 : : {
667 : 162 : GBinding *binding = G_BINDING (gobject);
668 : :
669 : 162 : g_binding_unbind_internal (binding, FALSE);
670 : :
671 : 162 : binding_context_unref (binding->context);
672 : :
673 : 162 : g_mutex_clear (&binding->unbind_lock);
674 : :
675 : 162 : G_OBJECT_CLASS (g_binding_parent_class)->finalize (gobject);
676 : 162 : }
677 : :
678 : : /* @key must have already been validated with is_valid()
679 : : * Modifies @key in place. */
680 : : static void
681 : 2 : canonicalize_key (gchar *key)
682 : : {
683 : : gchar *p;
684 : :
685 : 26 : for (p = key; *p != 0; p++)
686 : : {
687 : 24 : gchar c = *p;
688 : :
689 : 24 : if (c == '_')
690 : 2 : *p = '-';
691 : : }
692 : 2 : }
693 : :
694 : : /* @key must have already been validated with is_valid() */
695 : : static gboolean
696 : 324 : is_canonical (const gchar *key)
697 : : {
698 : 324 : return (strchr (key, '_') == NULL);
699 : : }
700 : :
701 : : static void
702 : 810 : g_binding_set_property (GObject *gobject,
703 : : guint prop_id,
704 : : const GValue *value,
705 : : GParamSpec *pspec)
706 : : {
707 : 810 : GBinding *binding = G_BINDING (gobject);
708 : :
709 : 810 : switch (prop_id)
710 : : {
711 : 162 : case PROP_SOURCE:
712 : 162 : g_weak_ref_set (&binding->context->source, g_value_get_object (value));
713 : 162 : break;
714 : :
715 : 162 : case PROP_TARGET:
716 : 162 : g_weak_ref_set (&binding->context->target, g_value_get_object (value));
717 : 162 : break;
718 : :
719 : 324 : case PROP_SOURCE_PROPERTY:
720 : : case PROP_TARGET_PROPERTY:
721 : : {
722 : 324 : gchar *name_copy = NULL;
723 : 324 : const gchar *name = g_value_get_string (value);
724 : : const gchar **dest;
725 : :
726 : : /* Ensure the name we intern is canonical. */
727 : 324 : if (!is_canonical (name))
728 : : {
729 : 2 : name_copy = g_value_dup_string (value);
730 : 2 : canonicalize_key (name_copy);
731 : 2 : name = name_copy;
732 : : }
733 : :
734 : 324 : if (prop_id == PROP_SOURCE_PROPERTY)
735 : 162 : dest = &binding->source_property;
736 : : else
737 : 162 : dest = &binding->target_property;
738 : :
739 : 324 : *dest = g_intern_string (name);
740 : :
741 : 324 : g_free (name_copy);
742 : 324 : break;
743 : : }
744 : :
745 : 162 : case PROP_FLAGS:
746 : 162 : binding->flags = g_value_get_flags (value);
747 : 162 : break;
748 : :
749 : 0 : default:
750 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
751 : 0 : break;
752 : : }
753 : 810 : }
754 : :
755 : : static void
756 : 5 : g_binding_get_property (GObject *gobject,
757 : : guint prop_id,
758 : : GValue *value,
759 : : GParamSpec *pspec)
760 : : {
761 : 5 : GBinding *binding = G_BINDING (gobject);
762 : :
763 : 5 : switch (prop_id)
764 : : {
765 : 1 : case PROP_SOURCE:
766 : 1 : g_value_take_object (value, g_weak_ref_get (&binding->context->source));
767 : 1 : break;
768 : :
769 : 1 : case PROP_SOURCE_PROPERTY:
770 : : /* @source_property is interned, so we don’t need to take a copy */
771 : 1 : g_value_set_interned_string (value, binding->source_property);
772 : 1 : break;
773 : :
774 : 1 : case PROP_TARGET:
775 : 1 : g_value_take_object (value, g_weak_ref_get (&binding->context->target));
776 : 1 : break;
777 : :
778 : 1 : case PROP_TARGET_PROPERTY:
779 : : /* @target_property is interned, so we don’t need to take a copy */
780 : 1 : g_value_set_interned_string (value, binding->target_property);
781 : 1 : break;
782 : :
783 : 1 : case PROP_FLAGS:
784 : 1 : g_value_set_flags (value, binding->flags);
785 : 1 : break;
786 : :
787 : 0 : default:
788 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
789 : 0 : break;
790 : : }
791 : 5 : }
792 : :
793 : : static void
794 : 162 : g_binding_constructed (GObject *gobject)
795 : : {
796 : 162 : GBinding *binding = G_BINDING (gobject);
797 : 162 : GBindingTransformFunc transform_func = default_transform;
798 : : GObject *source, *target;
799 : : GQuark source_property_detail;
800 : : GClosure *source_notify_closure;
801 : :
802 : : /* assert that we were constructed correctly */
803 : 162 : source = g_weak_ref_get (&binding->context->source);
804 : 162 : target = g_weak_ref_get (&binding->context->target);
805 : 162 : g_assert (source != NULL);
806 : 162 : g_assert (target != NULL);
807 : 162 : g_assert (binding->source_property != NULL);
808 : 162 : 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 : 162 : binding->source_pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (source), binding->source_property);
815 : 162 : binding->target_pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (target), binding->target_property);
816 : 162 : g_assert (binding->source_pspec != NULL);
817 : 162 : g_assert (binding->target_pspec != NULL);
818 : :
819 : : /* switch to the invert boolean transform if needed */
820 : 162 : if (binding->flags & G_BINDING_INVERT_BOOLEAN)
821 : 1 : transform_func = default_invert_boolean_transform;
822 : :
823 : : /* set the default transformation functions here */
824 : 162 : binding->transform_func = transform_func_new (transform_func, transform_func, NULL, NULL);
825 : :
826 : 162 : source_property_detail = g_quark_from_string (binding->source_property);
827 : 162 : source_notify_closure = g_cclosure_new (G_CALLBACK (on_source_notify),
828 : 162 : binding_context_ref (binding->context),
829 : : (GClosureNotify) binding_context_unref);
830 : 162 : binding->source_notify = g_signal_connect_closure_by_id (source,
831 : : gobject_notify_signal_id,
832 : : source_property_detail,
833 : : source_notify_closure,
834 : : FALSE);
835 : :
836 : 162 : g_object_weak_ref (source, weak_unbind, binding_context_ref (binding->context));
837 : :
838 : 162 : if (binding->flags & G_BINDING_BIDIRECTIONAL)
839 : : {
840 : : GQuark target_property_detail;
841 : : GClosure *target_notify_closure;
842 : :
843 : 133 : target_property_detail = g_quark_from_string (binding->target_property);
844 : 133 : target_notify_closure = g_cclosure_new (G_CALLBACK (on_target_notify),
845 : 133 : binding_context_ref (binding->context),
846 : : (GClosureNotify) binding_context_unref);
847 : 133 : binding->target_notify = g_signal_connect_closure_by_id (target,
848 : : gobject_notify_signal_id,
849 : : target_property_detail,
850 : : target_notify_closure,
851 : : FALSE);
852 : : }
853 : :
854 : 162 : if (target != source)
855 : : {
856 : 156 : 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 : 156 : binding->target_weak_notify_installed = TRUE;
862 : : }
863 : :
864 : 162 : g_object_unref (source);
865 : 162 : g_object_unref (target);
866 : 162 : }
867 : :
868 : : static void
869 : 3 : g_binding_class_init (GBindingClass *klass)
870 : : {
871 : 3 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
872 : :
873 : 3 : gobject_notify_signal_id = g_signal_lookup ("notify", G_TYPE_OBJECT);
874 : 3 : g_assert (gobject_notify_signal_id != 0);
875 : :
876 : 3 : gobject_class->constructed = g_binding_constructed;
877 : 3 : gobject_class->set_property = g_binding_set_property;
878 : 3 : gobject_class->get_property = g_binding_get_property;
879 : 3 : 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 : 3 : g_object_class_install_property (gobject_class, PROP_SOURCE,
889 : : g_param_spec_object ("source", NULL, NULL,
890 : : G_TYPE_OBJECT,
891 : : G_PARAM_CONSTRUCT_ONLY |
892 : : G_PARAM_READWRITE |
893 : : 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 : 3 : g_object_class_install_property (gobject_class, PROP_TARGET,
902 : : g_param_spec_object ("target", NULL, NULL,
903 : : G_TYPE_OBJECT,
904 : : G_PARAM_CONSTRUCT_ONLY |
905 : : G_PARAM_READWRITE |
906 : : 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 : 3 : g_object_class_install_property (gobject_class, PROP_SOURCE_PROPERTY,
919 : : g_param_spec_string ("source-property", NULL, NULL,
920 : : NULL,
921 : : G_PARAM_CONSTRUCT_ONLY |
922 : : G_PARAM_READWRITE |
923 : : 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 : 3 : g_object_class_install_property (gobject_class, PROP_TARGET_PROPERTY,
936 : : g_param_spec_string ("target-property", NULL, NULL,
937 : : NULL,
938 : : G_PARAM_CONSTRUCT_ONLY |
939 : : G_PARAM_READWRITE |
940 : : 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 : 3 : g_object_class_install_property (gobject_class, PROP_FLAGS,
949 : : g_param_spec_flags ("flags", NULL, NULL,
950 : : G_TYPE_BINDING_FLAGS,
951 : : G_BINDING_DEFAULT,
952 : : G_PARAM_CONSTRUCT_ONLY |
953 : : G_PARAM_READWRITE |
954 : : G_PARAM_STATIC_STRINGS));
955 : 3 : }
956 : :
957 : : static void
958 : 162 : g_binding_init (GBinding *binding)
959 : : {
960 : 162 : g_mutex_init (&binding->unbind_lock);
961 : :
962 : 162 : binding->context = g_atomic_rc_box_new0 (BindingContext);
963 : 162 : g_weak_ref_init (&binding->context->binding, binding);
964 : 162 : g_weak_ref_init (&binding->context->source, NULL);
965 : 162 : g_weak_ref_init (&binding->context->target, NULL);
966 : 162 : }
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 : 2 : g_binding_get_flags (GBinding *binding)
980 : : {
981 : 2 : g_return_val_if_fail (G_IS_BINDING (binding), G_BINDING_DEFAULT);
982 : :
983 : 2 : return binding->flags;
984 : : }
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 : 2 : g_binding_get_source (GBinding *binding)
1010 : : {
1011 : : GObject *source;
1012 : :
1013 : 2 : g_return_val_if_fail (G_IS_BINDING (binding), NULL);
1014 : :
1015 : 2 : 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 : 2 : if (source)
1019 : 2 : g_object_unref (source);
1020 : :
1021 : 2 : return source;
1022 : : }
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 : 2 : g_binding_dup_source (GBinding *binding)
1041 : : {
1042 : 2 : g_return_val_if_fail (G_IS_BINDING (binding), NULL);
1043 : :
1044 : 2 : return g_weak_ref_get (&binding->context->source);
1045 : : }
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 : 2 : g_binding_get_target (GBinding *binding)
1071 : : {
1072 : : GObject *target;
1073 : :
1074 : 2 : g_return_val_if_fail (G_IS_BINDING (binding), NULL);
1075 : :
1076 : 2 : 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 : 2 : if (target)
1080 : 2 : g_object_unref (target);
1081 : :
1082 : 2 : return target;
1083 : : }
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 : 2 : g_binding_dup_target (GBinding *binding)
1102 : : {
1103 : 2 : g_return_val_if_fail (G_IS_BINDING (binding), NULL);
1104 : :
1105 : 2 : return g_weak_ref_get (&binding->context->target);
1106 : : }
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 : 2 : g_binding_get_source_property (GBinding *binding)
1121 : : {
1122 : 2 : g_return_val_if_fail (G_IS_BINDING (binding), NULL);
1123 : :
1124 : 2 : return binding->source_property;
1125 : : }
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 : 2 : g_binding_get_target_property (GBinding *binding)
1140 : : {
1141 : 2 : g_return_val_if_fail (G_IS_BINDING (binding), NULL);
1142 : :
1143 : 2 : return binding->target_property;
1144 : : }
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 : 589 : g_binding_unbind (GBinding *binding)
1166 : : {
1167 : 589 : g_return_if_fail (G_IS_BINDING (binding));
1168 : :
1169 : 589 : g_binding_unbind_internal (binding, TRUE);
1170 : : }
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 : 162 : 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 : : {
1231 : : GParamSpec *pspec;
1232 : : GBinding *binding;
1233 : :
1234 : 162 : g_return_val_if_fail (G_IS_OBJECT (source), NULL);
1235 : 162 : g_return_val_if_fail (source_property != NULL, NULL);
1236 : 162 : g_return_val_if_fail (g_param_spec_is_valid_name (source_property), NULL);
1237 : 162 : g_return_val_if_fail (G_IS_OBJECT (target), NULL);
1238 : 162 : g_return_val_if_fail (target_property != NULL, NULL);
1239 : 162 : g_return_val_if_fail (g_param_spec_is_valid_name (target_property), NULL);
1240 : :
1241 : 162 : if (source == target && g_strcmp0 (source_property, target_property) == 0)
1242 : : {
1243 : 0 : g_critical ("Unable to bind the same property on the same instance");
1244 : 0 : return NULL;
1245 : : }
1246 : :
1247 : : /* remove the G_BINDING_INVERT_BOOLEAN flag in case we have
1248 : : * custom transformation functions
1249 : : */
1250 : 162 : if ((flags & G_BINDING_INVERT_BOOLEAN) &&
1251 : 1 : (transform_to != NULL || transform_from != NULL))
1252 : : {
1253 : 0 : flags &= ~G_BINDING_INVERT_BOOLEAN;
1254 : : }
1255 : :
1256 : 162 : pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (source), source_property);
1257 : 162 : if (pspec == NULL)
1258 : : {
1259 : 0 : g_critical ("%s: The source object of type %s has no property called '%s'",
1260 : : G_STRLOC,
1261 : : G_OBJECT_TYPE_NAME (source),
1262 : : source_property);
1263 : 0 : return NULL;
1264 : : }
1265 : :
1266 : 162 : if (!(pspec->flags & G_PARAM_READABLE))
1267 : : {
1268 : 0 : g_critical ("%s: The source object of type %s has no readable property called '%s'",
1269 : : G_STRLOC,
1270 : : G_OBJECT_TYPE_NAME (source),
1271 : : source_property);
1272 : 0 : return NULL;
1273 : : }
1274 : :
1275 : 162 : if ((flags & G_BINDING_BIDIRECTIONAL) &&
1276 : 133 : ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) || !(pspec->flags & G_PARAM_WRITABLE)))
1277 : : {
1278 : 0 : g_critical ("%s: The source object of type %s has no writable property called '%s'",
1279 : : G_STRLOC,
1280 : : G_OBJECT_TYPE_NAME (source),
1281 : : source_property);
1282 : 0 : return NULL;
1283 : : }
1284 : :
1285 : 162 : if ((flags & G_BINDING_INVERT_BOOLEAN) &&
1286 : 1 : !(G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_BOOLEAN))
1287 : : {
1288 : 0 : g_critical ("%s: The G_BINDING_INVERT_BOOLEAN flag can only be used "
1289 : : "when binding boolean properties; the source property '%s' "
1290 : : "is of type '%s'",
1291 : : G_STRLOC,
1292 : : source_property,
1293 : : g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1294 : 0 : return NULL;
1295 : : }
1296 : :
1297 : 162 : pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (target), target_property);
1298 : 162 : if (pspec == NULL)
1299 : : {
1300 : 0 : g_critical ("%s: The target object of type %s has no property called '%s'",
1301 : : G_STRLOC,
1302 : : G_OBJECT_TYPE_NAME (target),
1303 : : target_property);
1304 : 0 : return NULL;
1305 : : }
1306 : :
1307 : 162 : if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) || !(pspec->flags & G_PARAM_WRITABLE))
1308 : : {
1309 : 0 : g_critical ("%s: The target object of type %s has no writable property called '%s'",
1310 : : G_STRLOC,
1311 : : G_OBJECT_TYPE_NAME (target),
1312 : : target_property);
1313 : 0 : return NULL;
1314 : : }
1315 : :
1316 : 162 : if ((flags & G_BINDING_BIDIRECTIONAL) &&
1317 : 133 : !(pspec->flags & G_PARAM_READABLE))
1318 : : {
1319 : 0 : g_critical ("%s: The target object of type %s has no readable property called '%s'",
1320 : : G_STRLOC,
1321 : : G_OBJECT_TYPE_NAME (target),
1322 : : target_property);
1323 : 0 : return NULL;
1324 : : }
1325 : :
1326 : 162 : if ((flags & G_BINDING_INVERT_BOOLEAN) &&
1327 : 1 : !(G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_BOOLEAN))
1328 : : {
1329 : 0 : g_critical ("%s: The G_BINDING_INVERT_BOOLEAN flag can only be used "
1330 : : "when binding boolean properties; the target property '%s' "
1331 : : "is of type '%s'",
1332 : : G_STRLOC,
1333 : : target_property,
1334 : : g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1335 : 0 : return NULL;
1336 : : }
1337 : :
1338 : 162 : binding = g_object_new (G_TYPE_BINDING,
1339 : : "source", source,
1340 : : "source-property", source_property,
1341 : : "target", target,
1342 : : "target-property", target_property,
1343 : : "flags", flags,
1344 : : NULL);
1345 : :
1346 : 162 : g_assert (binding->transform_func != NULL);
1347 : :
1348 : : /* Use default functions if not provided here */
1349 : 162 : if (transform_to == NULL)
1350 : 157 : transform_to = binding->transform_func->transform_s2t;
1351 : :
1352 : 162 : if (transform_from == NULL)
1353 : 158 : transform_from = binding->transform_func->transform_t2s;
1354 : :
1355 : 162 : g_clear_pointer (&binding->transform_func, transform_func_unref);
1356 : 162 : 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 : 162 : if (flags & G_BINDING_SYNC_CREATE)
1364 : 40 : on_source_notify (source, binding->source_pspec, binding->context);
1365 : :
1366 : 162 : return binding;
1367 : : }
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 : 121 : g_object_bind_property (gpointer source,
1417 : : const gchar *source_property,
1418 : : gpointer target,
1419 : : const gchar *target_property,
1420 : : GBindingFlags flags)
1421 : : {
1422 : : /* type checking is done in g_object_bind_property_full() */
1423 : :
1424 : 121 : return g_object_bind_property_full (source, source_property,
1425 : : target, target_property,
1426 : : flags,
1427 : : NULL,
1428 : : NULL,
1429 : : NULL, NULL);
1430 : : }
1431 : :
1432 : : typedef struct _TransformData
1433 : : {
1434 : : GClosure *transform_to_closure;
1435 : : GClosure *transform_from_closure;
1436 : : } TransformData;
1437 : :
1438 : : static gboolean
1439 : 4 : bind_with_closures_transform_to (GBinding *binding,
1440 : : const GValue *source,
1441 : : GValue *target,
1442 : : gpointer data)
1443 : : {
1444 : 4 : TransformData *t_data = data;
1445 : 4 : GValue params[3] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
1446 : 4 : GValue retval = G_VALUE_INIT;
1447 : : gboolean res;
1448 : :
1449 : 4 : g_value_init (¶ms[0], G_TYPE_BINDING);
1450 : 4 : g_value_set_object (¶ms[0], binding);
1451 : :
1452 : 4 : g_value_init (¶ms[1], G_TYPE_VALUE);
1453 : 4 : g_value_set_boxed (¶ms[1], source);
1454 : :
1455 : 4 : g_value_init (¶ms[2], G_TYPE_VALUE);
1456 : 4 : g_value_set_boxed (¶ms[2], target);
1457 : :
1458 : 4 : g_value_init (&retval, G_TYPE_BOOLEAN);
1459 : 4 : g_value_set_boolean (&retval, FALSE);
1460 : :
1461 : 4 : g_closure_invoke (t_data->transform_to_closure, &retval, 3, params, NULL);
1462 : :
1463 : 4 : res = g_value_get_boolean (&retval);
1464 : 4 : if (res)
1465 : : {
1466 : 4 : const GValue *out_value = g_value_get_boxed (¶ms[2]);
1467 : :
1468 : 4 : g_assert (out_value != NULL);
1469 : :
1470 : 4 : g_value_copy (out_value, target);
1471 : : }
1472 : :
1473 : 4 : g_value_unset (¶ms[0]);
1474 : 4 : g_value_unset (¶ms[1]);
1475 : 4 : g_value_unset (¶ms[2]);
1476 : 4 : g_value_unset (&retval);
1477 : :
1478 : 4 : return res;
1479 : : }
1480 : :
1481 : : static gboolean
1482 : 2 : bind_with_closures_transform_from (GBinding *binding,
1483 : : const GValue *source,
1484 : : GValue *target,
1485 : : gpointer data)
1486 : : {
1487 : 2 : TransformData *t_data = data;
1488 : 2 : GValue params[3] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
1489 : 2 : GValue retval = G_VALUE_INIT;
1490 : : gboolean res;
1491 : :
1492 : 2 : g_value_init (¶ms[0], G_TYPE_BINDING);
1493 : 2 : g_value_set_object (¶ms[0], binding);
1494 : :
1495 : 2 : g_value_init (¶ms[1], G_TYPE_VALUE);
1496 : 2 : g_value_set_boxed (¶ms[1], source);
1497 : :
1498 : 2 : g_value_init (¶ms[2], G_TYPE_VALUE);
1499 : 2 : g_value_set_boxed (¶ms[2], target);
1500 : :
1501 : 2 : g_value_init (&retval, G_TYPE_BOOLEAN);
1502 : 2 : g_value_set_boolean (&retval, FALSE);
1503 : :
1504 : 2 : g_closure_invoke (t_data->transform_from_closure, &retval, 3, params, NULL);
1505 : :
1506 : 2 : res = g_value_get_boolean (&retval);
1507 : 2 : if (res)
1508 : : {
1509 : 2 : const GValue *out_value = g_value_get_boxed (¶ms[2]);
1510 : :
1511 : 2 : g_assert (out_value != NULL);
1512 : :
1513 : 2 : g_value_copy (out_value, target);
1514 : : }
1515 : :
1516 : 2 : g_value_unset (¶ms[0]);
1517 : 2 : g_value_unset (¶ms[1]);
1518 : 2 : g_value_unset (¶ms[2]);
1519 : 2 : g_value_unset (&retval);
1520 : :
1521 : 2 : return res;
1522 : : }
1523 : :
1524 : : static void
1525 : 3 : bind_with_closures_free_func (gpointer data)
1526 : : {
1527 : 3 : TransformData *t_data = data;
1528 : :
1529 : 3 : if (t_data->transform_to_closure != NULL)
1530 : 3 : g_closure_unref (t_data->transform_to_closure);
1531 : :
1532 : 3 : if (t_data->transform_from_closure != NULL)
1533 : 2 : g_closure_unref (t_data->transform_from_closure);
1534 : :
1535 : 3 : g_slice_free (TransformData, t_data);
1536 : 3 : }
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 : 3 : 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 : : {
1573 : : TransformData *data;
1574 : :
1575 : 3 : data = g_slice_new0 (TransformData);
1576 : :
1577 : 3 : if (transform_to != NULL)
1578 : : {
1579 : 3 : if (G_CLOSURE_NEEDS_MARSHAL (transform_to))
1580 : 2 : g_closure_set_marshal (transform_to, g_cclosure_marshal_BOOLEAN__BOXED_BOXED);
1581 : :
1582 : 3 : data->transform_to_closure = g_closure_ref (transform_to);
1583 : 3 : g_closure_sink (data->transform_to_closure);
1584 : : }
1585 : :
1586 : 3 : if (transform_from != NULL)
1587 : : {
1588 : 2 : if (G_CLOSURE_NEEDS_MARSHAL (transform_from))
1589 : 2 : g_closure_set_marshal (transform_from, g_cclosure_marshal_BOOLEAN__BOXED_BOXED);
1590 : :
1591 : 2 : data->transform_from_closure = g_closure_ref (transform_from);
1592 : 2 : g_closure_sink (data->transform_from_closure);
1593 : : }
1594 : :
1595 : 3 : return g_object_bind_property_full (source, source_property,
1596 : : target, target_property,
1597 : : flags,
1598 : : transform_to != NULL ? bind_with_closures_transform_to : NULL,
1599 : : transform_from != NULL ? bind_with_closures_transform_from : NULL,
1600 : : data,
1601 : : bind_with_closures_free_func);
1602 : : }
|