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 | |
120 | GType |
121 | g_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 | */ |
154 | typedef struct { |
155 | GWeakRef binding; |
156 | GWeakRef source; |
157 | GWeakRef target; |
158 | gboolean binding_removed; |
159 | } BindingContext; |
160 | |
161 | static BindingContext * |
162 | binding_context_ref (BindingContext *context) |
163 | { |
164 | return g_atomic_rc_box_acquire (context); |
165 | } |
166 | |
167 | static void |
168 | binding_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 | |
175 | static void |
176 | binding_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 | */ |
187 | typedef struct { |
188 | GBindingTransformFunc transform_s2t; |
189 | GBindingTransformFunc transform_t2s; |
190 | |
191 | gpointer transform_data; |
192 | GDestroyNotify destroy_notify; |
193 | } TransformFunc; |
194 | |
195 | static TransformFunc * |
196 | transform_func_new (GBindingTransformFunc transform_s2t, |
197 | GBindingTransformFunc transform_t2s, |
198 | gpointer transform_data, |
199 | GDestroyNotify destroy_notify) |
200 | { |
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 | |
211 | static TransformFunc * |
212 | transform_func_ref (TransformFunc *func) |
213 | { |
214 | return g_atomic_rc_box_acquire (func); |
215 | } |
216 | |
217 | static void |
218 | transform_func_clear (TransformFunc *func) |
219 | { |
220 | if (func->destroy_notify) |
221 | func->destroy_notify (func->transform_data); |
222 | } |
223 | |
224 | static void |
225 | transform_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 | |
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 | 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 | unbind_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. */ |
365 | static void |
366 | weak_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 | |
438 | static gboolean |
439 | default_transform (GBinding *binding, |
440 | const GValue *value_a, |
441 | GValue *value_b, |
442 | gpointer user_data G_GNUC_UNUSED) |
443 | { |
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 | |
477 | static gboolean |
478 | default_invert_boolean_transform (GBinding *binding, |
479 | const GValue *value_a, |
480 | GValue *value_b, |
481 | gpointer user_data G_GNUC_UNUSED) |
482 | { |
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 | |
496 | static void |
497 | on_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 | |
565 | static void |
566 | on_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 | |
633 | static inline void |
634 | g_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 | |
664 | static void |
665 | g_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. */ |
680 | static void |
681 | canonicalize_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() */ |
695 | static gboolean |
696 | is_canonical (const gchar *key) |
697 | { |
698 | return (strchr (s: key, c: '_') == NULL); |
699 | } |
700 | |
701 | static gboolean |
702 | is_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 | |
725 | static void |
726 | g_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 | |
779 | static void |
780 | g_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 | |
817 | static void |
818 | g_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 | |
892 | static void |
893 | g_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 | |
991 | static void |
992 | g_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 | */ |
1012 | GBindingFlags |
1013 | g_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 | */ |
1042 | GObject * |
1043 | g_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 | */ |
1073 | GObject * |
1074 | g_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 | */ |
1103 | GObject * |
1104 | g_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 | */ |
1134 | GObject * |
1135 | g_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 | */ |
1153 | const gchar * |
1154 | g_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 | */ |
1172 | const gchar * |
1173 | g_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 | */ |
1198 | void |
1199 | g_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 | */ |
1254 | GBinding * |
1255 | g_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 | */ |
1447 | GBinding * |
1448 | g_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 | |
1464 | typedef struct _TransformData |
1465 | { |
1466 | GClosure *transform_to_closure; |
1467 | GClosure *transform_from_closure; |
1468 | } TransformData; |
1469 | |
1470 | static gboolean |
1471 | bind_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: ¶ms[0], G_TYPE_BINDING); |
1482 | g_value_set_object (value: ¶ms[0], v_object: binding); |
1483 | |
1484 | g_value_init (value: ¶ms[1], G_TYPE_VALUE); |
1485 | g_value_set_boxed (value: ¶ms[1], v_boxed: source); |
1486 | |
1487 | g_value_init (value: ¶ms[2], G_TYPE_VALUE); |
1488 | g_value_set_boxed (value: ¶ms[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: ¶ms[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: ¶ms[0]); |
1506 | g_value_unset (value: ¶ms[1]); |
1507 | g_value_unset (value: ¶ms[2]); |
1508 | g_value_unset (value: &retval); |
1509 | |
1510 | return res; |
1511 | } |
1512 | |
1513 | static gboolean |
1514 | bind_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: ¶ms[0], G_TYPE_BINDING); |
1525 | g_value_set_object (value: ¶ms[0], v_object: binding); |
1526 | |
1527 | g_value_init (value: ¶ms[1], G_TYPE_VALUE); |
1528 | g_value_set_boxed (value: ¶ms[1], v_boxed: source); |
1529 | |
1530 | g_value_init (value: ¶ms[2], G_TYPE_VALUE); |
1531 | g_value_set_boxed (value: ¶ms[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: ¶ms[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: ¶ms[0]); |
1549 | g_value_unset (value: ¶ms[1]); |
1550 | g_value_unset (value: ¶ms[2]); |
1551 | g_value_unset (value: &retval); |
1552 | |
1553 | return res; |
1554 | } |
1555 | |
1556 | static void |
1557 | bind_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 | */ |
1596 | GBinding * |
1597 | g_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 | |