3 #include <glib-object.h>
5 typedef struct _BindingSource
7 GObject parent_instance
;
15 typedef struct _BindingSourceClass
17 GObjectClass parent_class
;
30 static GType
binding_source_get_type (void);
31 G_DEFINE_TYPE (BindingSource
, binding_source
, G_TYPE_OBJECT
)
34 binding_source_set_property (GObject
*gobject
,
39 BindingSource
*source
= (BindingSource
*) gobject
;
44 source
->foo
= g_value_get_int (value
);
48 source
->bar
= g_value_get_int (value
);
51 case PROP_SOURCE_VALUE
:
52 source
->value
= g_value_get_double (value
);
55 case PROP_SOURCE_TOGGLE
:
56 source
->toggle
= g_value_get_boolean (value
);
60 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject
, prop_id
, pspec
);
65 binding_source_get_property (GObject
*gobject
,
70 BindingSource
*source
= (BindingSource
*) gobject
;
75 g_value_set_int (value
, source
->foo
);
79 g_value_set_int (value
, source
->bar
);
82 case PROP_SOURCE_VALUE
:
83 g_value_set_double (value
, source
->value
);
86 case PROP_SOURCE_TOGGLE
:
87 g_value_set_boolean (value
, source
->toggle
);
91 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject
, prop_id
, pspec
);
96 binding_source_class_init (BindingSourceClass
*klass
)
98 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
100 gobject_class
->set_property
= binding_source_set_property
;
101 gobject_class
->get_property
= binding_source_get_property
;
103 g_object_class_install_property (gobject_class
, PROP_SOURCE_FOO
,
104 g_param_spec_int ("foo", "Foo", "Foo",
108 g_object_class_install_property (gobject_class
, PROP_SOURCE_BAR
,
109 g_param_spec_int ("bar", "Bar", "Bar",
113 g_object_class_install_property (gobject_class
, PROP_SOURCE_VALUE
,
114 g_param_spec_double ("value", "Value", "Value",
118 g_object_class_install_property (gobject_class
, PROP_SOURCE_TOGGLE
,
119 g_param_spec_boolean ("toggle", "Toggle", "Toggle",
125 binding_source_init (BindingSource
*self
)
129 typedef struct _BindingTarget
131 GObject parent_instance
;
138 typedef struct _BindingTargetClass
140 GObjectClass parent_class
;
141 } BindingTargetClass
;
152 static GType
binding_target_get_type (void);
153 G_DEFINE_TYPE (BindingTarget
, binding_target
, G_TYPE_OBJECT
)
156 binding_target_set_property (GObject
*gobject
,
161 BindingTarget
*target
= (BindingTarget
*) gobject
;
165 case PROP_TARGET_BAR
:
166 target
->bar
= g_value_get_int (value
);
169 case PROP_TARGET_VALUE
:
170 target
->value
= g_value_get_double (value
);
173 case PROP_TARGET_TOGGLE
:
174 target
->toggle
= g_value_get_boolean (value
);
178 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject
, prop_id
, pspec
);
183 binding_target_get_property (GObject
*gobject
,
188 BindingTarget
*target
= (BindingTarget
*) gobject
;
192 case PROP_TARGET_BAR
:
193 g_value_set_int (value
, target
->bar
);
196 case PROP_TARGET_VALUE
:
197 g_value_set_double (value
, target
->value
);
200 case PROP_TARGET_TOGGLE
:
201 g_value_set_boolean (value
, target
->toggle
);
205 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject
, prop_id
, pspec
);
210 binding_target_class_init (BindingTargetClass
*klass
)
212 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
214 gobject_class
->set_property
= binding_target_set_property
;
215 gobject_class
->get_property
= binding_target_get_property
;
217 g_object_class_install_property (gobject_class
, PROP_TARGET_BAR
,
218 g_param_spec_int ("bar", "Bar", "Bar",
222 g_object_class_install_property (gobject_class
, PROP_TARGET_VALUE
,
223 g_param_spec_double ("value", "Value", "Value",
227 g_object_class_install_property (gobject_class
, PROP_TARGET_TOGGLE
,
228 g_param_spec_boolean ("toggle", "Toggle", "Toggle",
234 binding_target_init (BindingTarget
*self
)
239 celsius_to_fahrenheit (GBinding
*binding
,
240 const GValue
*from_value
,
242 gpointer user_data G_GNUC_UNUSED
)
244 gdouble celsius
, fahrenheit
;
246 g_assert (G_VALUE_HOLDS (from_value
, G_TYPE_DOUBLE
));
247 g_assert (G_VALUE_HOLDS (to_value
, G_TYPE_DOUBLE
));
249 celsius
= g_value_get_double (from_value
);
250 fahrenheit
= (9 * celsius
/ 5) + 32.0;
252 if (g_test_verbose ())
253 g_printerr ("Converting %.2fC to %.2fF\n", celsius
, fahrenheit
);
255 g_value_set_double (to_value
, fahrenheit
);
261 fahrenheit_to_celsius (GBinding
*binding
,
262 const GValue
*from_value
,
264 gpointer user_data G_GNUC_UNUSED
)
266 gdouble celsius
, fahrenheit
;
268 g_assert (G_VALUE_HOLDS (from_value
, G_TYPE_DOUBLE
));
269 g_assert (G_VALUE_HOLDS (to_value
, G_TYPE_DOUBLE
));
271 fahrenheit
= g_value_get_double (from_value
);
272 celsius
= 5 * (fahrenheit
- 32.0) / 9;
274 if (g_test_verbose ())
275 g_printerr ("Converting %.2fF to %.2fC\n", fahrenheit
, celsius
);
277 g_value_set_double (to_value
, celsius
);
283 binding_default (void)
285 BindingSource
*source
= g_object_new (binding_source_get_type (), NULL
);
286 BindingTarget
*target
= g_object_new (binding_target_get_type (), NULL
);
289 binding
= g_object_bind_property (source
, "foo",
293 g_object_add_weak_pointer (G_OBJECT (binding
), (gpointer
*) &binding
);
294 g_assert ((BindingSource
*) g_binding_get_source (binding
) == source
);
295 g_assert ((BindingTarget
*) g_binding_get_target (binding
) == target
);
296 g_assert_cmpstr (g_binding_get_source_property (binding
), ==, "foo");
297 g_assert_cmpstr (g_binding_get_target_property (binding
), ==, "bar");
298 g_assert_cmpint (g_binding_get_flags (binding
), ==, G_BINDING_DEFAULT
);
300 g_object_set (source
, "foo", 42, NULL
);
301 g_assert_cmpint (source
->foo
, ==, target
->bar
);
303 g_object_set (target
, "bar", 47, NULL
);
304 g_assert_cmpint (source
->foo
, !=, target
->bar
);
306 g_object_unref (binding
);
308 g_object_set (source
, "foo", 0, NULL
);
309 g_assert_cmpint (source
->foo
, !=, target
->bar
);
311 g_object_unref (source
);
312 g_object_unref (target
);
313 g_assert (binding
== NULL
);
317 binding_bidirectional (void)
319 BindingSource
*source
= g_object_new (binding_source_get_type (), NULL
);
320 BindingTarget
*target
= g_object_new (binding_target_get_type (), NULL
);
323 binding
= g_object_bind_property (source
, "foo",
325 G_BINDING_BIDIRECTIONAL
);
326 g_object_add_weak_pointer (G_OBJECT (binding
), (gpointer
*) &binding
);
328 g_object_set (source
, "foo", 42, NULL
);
329 g_assert_cmpint (source
->foo
, ==, target
->bar
);
331 g_object_set (target
, "bar", 47, NULL
);
332 g_assert_cmpint (source
->foo
, ==, target
->bar
);
334 g_object_unref (binding
);
336 g_object_set (source
, "foo", 0, NULL
);
337 g_assert_cmpint (source
->foo
, !=, target
->bar
);
339 g_object_unref (source
);
340 g_object_unref (target
);
341 g_assert (binding
== NULL
);
345 data_free (gpointer data
)
353 binding_transform_default (void)
355 BindingSource
*source
= g_object_new (binding_source_get_type (), NULL
);
356 BindingTarget
*target
= g_object_new (binding_target_get_type (), NULL
);
359 gchar
*src_prop
, *trg_prop
;
362 binding
= g_object_bind_property (source
, "foo",
364 G_BINDING_BIDIRECTIONAL
);
366 g_object_add_weak_pointer (G_OBJECT (binding
), (gpointer
*) &binding
);
368 g_object_get (binding
,
370 "source-property", &src_prop
,
372 "target-property", &trg_prop
,
375 g_assert (src
== source
);
376 g_assert (trg
== target
);
377 g_assert_cmpstr (src_prop
, ==, "foo");
378 g_assert_cmpstr (trg_prop
, ==, "value");
379 g_assert_cmpint (flags
, ==, G_BINDING_BIDIRECTIONAL
);
380 g_object_unref (src
);
381 g_object_unref (trg
);
385 g_object_set (source
, "foo", 24, NULL
);
386 g_assert_cmpfloat (target
->value
, ==, 24.0);
388 g_object_set (target
, "value", 69.0, NULL
);
389 g_assert_cmpint (source
->foo
, ==, 69);
391 g_object_unref (target
);
392 g_object_unref (source
);
393 g_assert (binding
== NULL
);
397 binding_transform (void)
399 BindingSource
*source
= g_object_new (binding_source_get_type (), NULL
);
400 BindingTarget
*target
= g_object_new (binding_target_get_type (), NULL
);
401 GBinding
*binding G_GNUC_UNUSED
;
402 gboolean unused_data
= FALSE
;
404 binding
= g_object_bind_property_full (source
, "value",
406 G_BINDING_BIDIRECTIONAL
,
407 celsius_to_fahrenheit
,
408 fahrenheit_to_celsius
,
409 &unused_data
, data_free
);
411 g_object_set (source
, "value", 24.0, NULL
);
412 g_assert_cmpfloat (target
->value
, ==, ((9 * 24.0 / 5) + 32.0));
414 g_object_set (target
, "value", 69.0, NULL
);
415 g_assert_cmpfloat (source
->value
, ==, (5 * (69.0 - 32.0) / 9));
417 g_object_unref (source
);
418 g_object_unref (target
);
420 g_assert (unused_data
);
424 binding_transform_closure (void)
426 BindingSource
*source
= g_object_new (binding_source_get_type (), NULL
);
427 BindingTarget
*target
= g_object_new (binding_target_get_type (), NULL
);
428 GBinding
*binding G_GNUC_UNUSED
;
429 gboolean unused_data_1
= FALSE
, unused_data_2
= FALSE
;
430 GClosure
*c2f_clos
, *f2c_clos
;
432 c2f_clos
= g_cclosure_new (G_CALLBACK (celsius_to_fahrenheit
), &unused_data_1
, (GClosureNotify
) data_free
);
434 f2c_clos
= g_cclosure_new (G_CALLBACK (fahrenheit_to_celsius
), &unused_data_2
, (GClosureNotify
) data_free
);
436 binding
= g_object_bind_property_with_closures (source
, "value",
438 G_BINDING_BIDIRECTIONAL
,
442 g_object_set (source
, "value", 24.0, NULL
);
443 g_assert_cmpfloat (target
->value
, ==, ((9 * 24.0 / 5) + 32.0));
445 g_object_set (target
, "value", 69.0, NULL
);
446 g_assert_cmpfloat (source
->value
, ==, (5 * (69.0 - 32.0) / 9));
448 g_object_unref (source
);
449 g_object_unref (target
);
451 g_assert (unused_data_1
);
452 g_assert (unused_data_2
);
458 BindingSource
*a
= g_object_new (binding_source_get_type (), NULL
);
459 BindingSource
*b
= g_object_new (binding_source_get_type (), NULL
);
460 BindingSource
*c
= g_object_new (binding_source_get_type (), NULL
);
461 GBinding
*binding_1
, *binding_2
;
463 g_test_bug ("621782");
466 binding_1
= g_object_bind_property (a
, "foo", b
, "foo", G_BINDING_BIDIRECTIONAL
);
467 g_object_add_weak_pointer (G_OBJECT (binding_1
), (gpointer
*) &binding_1
);
469 binding_2
= g_object_bind_property (b
, "foo", c
, "foo", G_BINDING_BIDIRECTIONAL
);
470 g_object_add_weak_pointer (G_OBJECT (binding_2
), (gpointer
*) &binding_2
);
472 /* verify the chain */
473 g_object_set (a
, "foo", 42, NULL
);
474 g_assert_cmpint (a
->foo
, ==, b
->foo
);
475 g_assert_cmpint (b
->foo
, ==, c
->foo
);
477 /* unbind A -> B and B -> C */
478 g_object_unref (binding_1
);
479 g_assert (binding_1
== NULL
);
480 g_object_unref (binding_2
);
481 g_assert (binding_2
== NULL
);
483 /* bind A -> C directly */
484 binding_2
= g_object_bind_property (a
, "foo", c
, "foo", G_BINDING_BIDIRECTIONAL
);
486 /* verify the chain is broken */
487 g_object_set (a
, "foo", 47, NULL
);
488 g_assert_cmpint (a
->foo
, !=, b
->foo
);
489 g_assert_cmpint (a
->foo
, ==, c
->foo
);
497 binding_sync_create (void)
499 BindingSource
*source
= g_object_new (binding_source_get_type (),
502 BindingTarget
*target
= g_object_new (binding_target_get_type (),
507 binding
= g_object_bind_property (source
, "foo",
509 G_BINDING_DEFAULT
| G_BINDING_SYNC_CREATE
);
511 g_assert_cmpint (source
->foo
, ==, 42);
512 g_assert_cmpint (target
->bar
, ==, 42);
514 g_object_set (source
, "foo", 47, NULL
);
515 g_assert_cmpint (source
->foo
, ==, target
->bar
);
517 g_object_unref (binding
);
519 g_object_set (target
, "bar", 49, NULL
);
521 binding
= g_object_bind_property (source
, "foo",
523 G_BINDING_BIDIRECTIONAL
| G_BINDING_SYNC_CREATE
);
524 g_assert_cmpint (source
->foo
, ==, 47);
525 g_assert_cmpint (target
->bar
, ==, 47);
527 g_object_unref (source
);
528 g_object_unref (target
);
532 binding_invert_boolean (void)
534 BindingSource
*source
= g_object_new (binding_source_get_type (),
537 BindingTarget
*target
= g_object_new (binding_target_get_type (),
542 binding
= g_object_bind_property (source
, "toggle",
544 G_BINDING_BIDIRECTIONAL
| G_BINDING_INVERT_BOOLEAN
);
546 g_assert (source
->toggle
);
547 g_assert (!target
->toggle
);
549 g_object_set (source
, "toggle", FALSE
, NULL
);
550 g_assert (!source
->toggle
);
551 g_assert (target
->toggle
);
553 g_object_set (target
, "toggle", FALSE
, NULL
);
554 g_assert (source
->toggle
);
555 g_assert (!target
->toggle
);
557 g_object_unref (binding
);
558 g_object_unref (source
);
559 g_object_unref (target
);
563 binding_same_object (void)
565 BindingSource
*source
= g_object_new (binding_source_get_type (),
571 binding
= g_object_bind_property (source
, "foo",
573 G_BINDING_BIDIRECTIONAL
);
574 g_object_add_weak_pointer (G_OBJECT (binding
), (gpointer
*) &binding
);
576 g_object_set (source
, "foo", 10, NULL
);
577 g_assert_cmpint (source
->foo
, ==, 10);
578 g_assert_cmpint (source
->bar
, ==, 10);
579 g_object_set (source
, "bar", 30, NULL
);
580 g_assert_cmpint (source
->foo
, ==, 30);
581 g_assert_cmpint (source
->bar
, ==, 30);
583 g_object_unref (source
);
584 g_assert (binding
== NULL
);
588 binding_unbind (void)
590 BindingSource
*source
= g_object_new (binding_source_get_type (), NULL
);
591 BindingTarget
*target
= g_object_new (binding_target_get_type (), NULL
);
594 binding
= g_object_bind_property (source
, "foo",
597 g_object_add_weak_pointer (G_OBJECT (binding
), (gpointer
*) &binding
);
599 g_object_set (source
, "foo", 42, NULL
);
600 g_assert_cmpint (source
->foo
, ==, target
->bar
);
602 g_object_set (target
, "bar", 47, NULL
);
603 g_assert_cmpint (source
->foo
, !=, target
->bar
);
605 g_binding_unbind (binding
);
606 g_assert (binding
== NULL
);
608 g_object_set (source
, "foo", 0, NULL
);
609 g_assert_cmpint (source
->foo
, !=, target
->bar
);
611 g_object_unref (source
);
612 g_object_unref (target
);
615 /* g_binding_unbind() has a special case for this */
616 source
= g_object_new (binding_source_get_type (), NULL
);
617 binding
= g_object_bind_property (source
, "foo",
620 g_object_add_weak_pointer (G_OBJECT (binding
), (gpointer
*) &binding
);
622 g_binding_unbind (binding
);
623 g_assert (binding
== NULL
);
625 g_object_unref (source
);
631 BindingSource
*source
= g_object_new (binding_source_get_type (), NULL
);
632 BindingTarget
*target
= g_object_new (binding_target_get_type (), NULL
);
635 /* double -> boolean is not supported */
636 binding
= g_object_bind_property (source
, "value",
639 g_object_add_weak_pointer (G_OBJECT (binding
), (gpointer
*) &binding
);
641 g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING
,
642 "*Unable to convert*double*boolean*");
643 g_object_set (source
, "value", 1.0, NULL
);
644 g_test_assert_expected_messages ();
646 g_object_unref (source
);
647 g_object_unref (target
);
648 g_assert (binding
== NULL
);
652 main (int argc
, char *argv
[])
654 g_test_init (&argc
, &argv
, NULL
);
656 g_test_bug_base ("http://bugzilla.gnome.org/");
658 g_test_add_func ("/binding/default", binding_default
);
659 g_test_add_func ("/binding/bidirectional", binding_bidirectional
);
660 g_test_add_func ("/binding/transform", binding_transform
);
661 g_test_add_func ("/binding/transform-default", binding_transform_default
);
662 g_test_add_func ("/binding/transform-closure", binding_transform_closure
);
663 g_test_add_func ("/binding/chain", binding_chain
);
664 g_test_add_func ("/binding/sync-create", binding_sync_create
);
665 g_test_add_func ("/binding/invert-boolean", binding_invert_boolean
);
666 g_test_add_func ("/binding/same-object", binding_same_object
);
667 g_test_add_func ("/binding/unbind", binding_unbind
);
668 g_test_add_func ("/binding/fail", binding_fail
);
670 return g_test_run ();