Branch data Line data Source code
1 : : #include <stdlib.h>
2 : : #include <gstdio.h>
3 : : #include <glib-object.h>
4 : :
5 : : #define assert_cmpsource(binding, op, expected_source) G_STMT_START { \
6 : : GObject *tmp, *tmp2; \
7 : : tmp = g_binding_dup_source ((binding)); \
8 : : G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
9 : : tmp2 = g_binding_get_source ((binding)); \
10 : : G_GNUC_END_IGNORE_DEPRECATIONS \
11 : : g_assert_nonnull (tmp); \
12 : : g_assert_true ((gpointer) tmp op (gpointer) (expected_source)); \
13 : : g_assert_true (tmp == tmp2); \
14 : : g_object_unref (tmp); \
15 : : } G_STMT_END
16 : :
17 : : #define assert_cmptarget(binding, op, expected_target) G_STMT_START { \
18 : : GObject *tmp, *tmp2; \
19 : : tmp = g_binding_dup_target ((binding)); \
20 : : G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
21 : : tmp2 = g_binding_get_target ((binding)); \
22 : : G_GNUC_END_IGNORE_DEPRECATIONS \
23 : : g_assert_nonnull (tmp); \
24 : : g_assert_true ((gpointer) tmp op (gpointer) (expected_target)); \
25 : : g_assert_true (tmp == tmp2); \
26 : : g_object_unref (tmp); \
27 : : } G_STMT_END
28 : :
29 : : typedef struct {
30 : : GTypeInterface g_iface;
31 : : } FooInterface;
32 : :
33 : : GType foo_get_type (void);
34 : :
35 : 2 : G_DEFINE_INTERFACE (Foo, foo, G_TYPE_OBJECT)
36 : :
37 : : static void
38 : 1 : foo_default_init (FooInterface *iface)
39 : : {
40 : 1 : }
41 : :
42 : : typedef struct {
43 : : GObject parent;
44 : : } Baa;
45 : :
46 : : typedef struct {
47 : : GObjectClass parent_class;
48 : : } BaaClass;
49 : :
50 : : static void
51 : 1 : baa_init_foo (FooInterface *iface)
52 : : {
53 : 1 : }
54 : :
55 : : GType baa_get_type (void);
56 : :
57 : 4 : G_DEFINE_TYPE_WITH_CODE (Baa, baa, G_TYPE_OBJECT,
58 : : G_IMPLEMENT_INTERFACE (foo_get_type (), baa_init_foo))
59 : :
60 : : static void
61 : 2 : baa_init (Baa *baa)
62 : : {
63 : 2 : }
64 : :
65 : : static void
66 : 1 : baa_class_init (BaaClass *class)
67 : : {
68 : 1 : }
69 : :
70 : : typedef struct _BindingSource
71 : : {
72 : : GObject parent_instance;
73 : :
74 : : gint foo;
75 : : gint bar;
76 : : gdouble double_value;
77 : : gboolean toggle;
78 : : gpointer item;
79 : : } BindingSource;
80 : :
81 : : typedef struct _BindingSourceClass
82 : : {
83 : : GObjectClass parent_class;
84 : : } BindingSourceClass;
85 : :
86 : : enum
87 : : {
88 : : PROP_SOURCE_0,
89 : :
90 : : PROP_SOURCE_FOO,
91 : : PROP_SOURCE_BAR,
92 : : PROP_SOURCE_DOUBLE_VALUE,
93 : : PROP_SOURCE_TOGGLE,
94 : : PROP_SOURCE_OBJECT
95 : : };
96 : :
97 : : static GType binding_source_get_type (void);
98 : 124 : G_DEFINE_TYPE (BindingSource, binding_source, G_TYPE_OBJECT)
99 : :
100 : : static void
101 : 33 : binding_source_set_property (GObject *gobject,
102 : : guint prop_id,
103 : : const GValue *value,
104 : : GParamSpec *pspec)
105 : : {
106 : 33 : BindingSource *source = (BindingSource *) gobject;
107 : :
108 : 33 : switch (prop_id)
109 : : {
110 : 19 : case PROP_SOURCE_FOO:
111 : 19 : source->foo = g_value_get_int (value);
112 : 19 : break;
113 : :
114 : 3 : case PROP_SOURCE_BAR:
115 : 3 : source->bar = g_value_get_int (value);
116 : 3 : break;
117 : :
118 : 6 : case PROP_SOURCE_DOUBLE_VALUE:
119 : 6 : source->double_value = g_value_get_double (value);
120 : 6 : break;
121 : :
122 : 3 : case PROP_SOURCE_TOGGLE:
123 : 3 : source->toggle = g_value_get_boolean (value);
124 : 3 : break;
125 : :
126 : 2 : case PROP_SOURCE_OBJECT:
127 : 2 : source->item = g_value_get_object (value);
128 : 2 : break;
129 : :
130 : 0 : default:
131 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
132 : : }
133 : 33 : }
134 : :
135 : : static void
136 : 19 : binding_source_get_property (GObject *gobject,
137 : : guint prop_id,
138 : : GValue *value,
139 : : GParamSpec *pspec)
140 : : {
141 : 19 : BindingSource *source = (BindingSource *) gobject;
142 : :
143 : 19 : switch (prop_id)
144 : : {
145 : 11 : case PROP_SOURCE_FOO:
146 : 11 : g_value_set_int (value, source->foo);
147 : 11 : break;
148 : :
149 : 1 : case PROP_SOURCE_BAR:
150 : 1 : g_value_set_int (value, source->bar);
151 : 1 : break;
152 : :
153 : 4 : case PROP_SOURCE_DOUBLE_VALUE:
154 : 4 : g_value_set_double (value, source->double_value);
155 : 4 : break;
156 : :
157 : 1 : case PROP_SOURCE_TOGGLE:
158 : 1 : g_value_set_boolean (value, source->toggle);
159 : 1 : break;
160 : :
161 : 2 : case PROP_SOURCE_OBJECT:
162 : 2 : g_value_set_object (value, source->item);
163 : 2 : break;
164 : :
165 : 0 : default:
166 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
167 : : }
168 : 19 : }
169 : :
170 : : static void
171 : 1 : binding_source_class_init (BindingSourceClass *klass)
172 : : {
173 : 1 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
174 : :
175 : 1 : gobject_class->set_property = binding_source_set_property;
176 : 1 : gobject_class->get_property = binding_source_get_property;
177 : :
178 : 1 : g_object_class_install_property (gobject_class, PROP_SOURCE_FOO,
179 : : g_param_spec_int ("foo", "Foo", "Foo",
180 : : -1, 100,
181 : : 0,
182 : : G_PARAM_READWRITE));
183 : 1 : g_object_class_install_property (gobject_class, PROP_SOURCE_BAR,
184 : : g_param_spec_int ("bar", "Bar", "Bar",
185 : : -1, 100,
186 : : 0,
187 : : G_PARAM_READWRITE));
188 : 1 : g_object_class_install_property (gobject_class, PROP_SOURCE_DOUBLE_VALUE,
189 : : g_param_spec_double ("double-value", "Value", "Value",
190 : : -100.0, 200.0,
191 : : 0.0,
192 : : G_PARAM_READWRITE));
193 : 1 : g_object_class_install_property (gobject_class, PROP_SOURCE_TOGGLE,
194 : : g_param_spec_boolean ("toggle", "Toggle", "Toggle",
195 : : FALSE,
196 : : G_PARAM_READWRITE));
197 : 1 : g_object_class_install_property (gobject_class, PROP_SOURCE_OBJECT,
198 : : g_param_spec_object ("object", "Object", "Object",
199 : : G_TYPE_OBJECT,
200 : : G_PARAM_READWRITE));
201 : 1 : }
202 : :
203 : : static void
204 : 122 : binding_source_init (BindingSource *self)
205 : : {
206 : 122 : }
207 : :
208 : : typedef struct _BindingTarget
209 : : {
210 : : GObject parent_instance;
211 : :
212 : : gint bar;
213 : : gdouble double_value;
214 : : gboolean toggle;
215 : : gpointer foo;
216 : : } BindingTarget;
217 : :
218 : : typedef struct _BindingTargetClass
219 : : {
220 : : GObjectClass parent_class;
221 : : } BindingTargetClass;
222 : :
223 : : enum
224 : : {
225 : : PROP_TARGET_0,
226 : :
227 : : PROP_TARGET_BAR,
228 : : PROP_TARGET_DOUBLE_VALUE,
229 : : PROP_TARGET_TOGGLE,
230 : : PROP_TARGET_FOO
231 : : };
232 : :
233 : : static GType binding_target_get_type (void);
234 : 118 : G_DEFINE_TYPE (BindingTarget, binding_target, G_TYPE_OBJECT)
235 : :
236 : : static void
237 : 24 : binding_target_set_property (GObject *gobject,
238 : : guint prop_id,
239 : : const GValue *value,
240 : : GParamSpec *pspec)
241 : : {
242 : 24 : BindingTarget *target = (BindingTarget *) gobject;
243 : :
244 : 24 : switch (prop_id)
245 : : {
246 : 11 : case PROP_TARGET_BAR:
247 : 11 : target->bar = g_value_get_int (value);
248 : 11 : break;
249 : :
250 : 8 : case PROP_TARGET_DOUBLE_VALUE:
251 : 8 : target->double_value = g_value_get_double (value);
252 : 8 : break;
253 : :
254 : 3 : case PROP_TARGET_TOGGLE:
255 : 3 : target->toggle = g_value_get_boolean (value);
256 : 3 : break;
257 : :
258 : 2 : case PROP_TARGET_FOO:
259 : 2 : target->foo = g_value_get_object (value);
260 : 2 : break;
261 : :
262 : 0 : default:
263 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
264 : : }
265 : 24 : }
266 : :
267 : : static void
268 : 5 : binding_target_get_property (GObject *gobject,
269 : : guint prop_id,
270 : : GValue *value,
271 : : GParamSpec *pspec)
272 : : {
273 : 5 : BindingTarget *target = (BindingTarget *) gobject;
274 : :
275 : 5 : switch (prop_id)
276 : : {
277 : 1 : case PROP_TARGET_BAR:
278 : 1 : g_value_set_int (value, target->bar);
279 : 1 : break;
280 : :
281 : 3 : case PROP_TARGET_DOUBLE_VALUE:
282 : 3 : g_value_set_double (value, target->double_value);
283 : 3 : break;
284 : :
285 : 1 : case PROP_TARGET_TOGGLE:
286 : 1 : g_value_set_boolean (value, target->toggle);
287 : 1 : break;
288 : :
289 : 0 : case PROP_TARGET_FOO:
290 : 0 : g_value_set_object (value, target->foo);
291 : 0 : break;
292 : :
293 : 0 : default:
294 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
295 : : }
296 : 5 : }
297 : :
298 : : static void
299 : 1 : binding_target_class_init (BindingTargetClass *klass)
300 : : {
301 : 1 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
302 : :
303 : 1 : gobject_class->set_property = binding_target_set_property;
304 : 1 : gobject_class->get_property = binding_target_get_property;
305 : :
306 : 1 : g_object_class_install_property (gobject_class, PROP_TARGET_BAR,
307 : : g_param_spec_int ("bar", "Bar", "Bar",
308 : : -1, 100,
309 : : 0,
310 : : G_PARAM_READWRITE));
311 : 1 : g_object_class_install_property (gobject_class, PROP_TARGET_DOUBLE_VALUE,
312 : : g_param_spec_double ("double-value", "Value", "Value",
313 : : -100.0, 200.0,
314 : : 0.0,
315 : : G_PARAM_READWRITE));
316 : 1 : g_object_class_install_property (gobject_class, PROP_TARGET_TOGGLE,
317 : : g_param_spec_boolean ("toggle", "Toggle", "Toggle",
318 : : FALSE,
319 : : G_PARAM_READWRITE));
320 : 1 : g_object_class_install_property (gobject_class, PROP_TARGET_FOO,
321 : : g_param_spec_object ("foo", "Foo", "Foo",
322 : : foo_get_type (),
323 : : G_PARAM_READWRITE));
324 : 1 : }
325 : :
326 : : static void
327 : 116 : binding_target_init (BindingTarget *self)
328 : : {
329 : 116 : }
330 : :
331 : : static gboolean
332 : 2 : celsius_to_fahrenheit (GBinding *binding,
333 : : const GValue *from_value,
334 : : GValue *to_value,
335 : : gpointer user_data G_GNUC_UNUSED)
336 : : {
337 : : gdouble celsius, fahrenheit;
338 : :
339 : 2 : g_assert_true (G_VALUE_HOLDS (from_value, G_TYPE_DOUBLE));
340 : 2 : g_assert_true (G_VALUE_HOLDS (to_value, G_TYPE_DOUBLE));
341 : :
342 : 2 : celsius = g_value_get_double (from_value);
343 : 2 : fahrenheit = (9 * celsius / 5) + 32.0;
344 : :
345 : 2 : if (g_test_verbose ())
346 : 0 : g_printerr ("Converting %.2fC to %.2fF\n", celsius, fahrenheit);
347 : :
348 : 2 : g_value_set_double (to_value, fahrenheit);
349 : :
350 : 2 : return TRUE;
351 : : }
352 : :
353 : : static gboolean
354 : 2 : fahrenheit_to_celsius (GBinding *binding,
355 : : const GValue *from_value,
356 : : GValue *to_value,
357 : : gpointer user_data G_GNUC_UNUSED)
358 : : {
359 : : gdouble celsius, fahrenheit;
360 : :
361 : 2 : g_assert_true (G_VALUE_HOLDS (from_value, G_TYPE_DOUBLE));
362 : 2 : g_assert_true (G_VALUE_HOLDS (to_value, G_TYPE_DOUBLE));
363 : :
364 : 2 : fahrenheit = g_value_get_double (from_value);
365 : 2 : celsius = 5 * (fahrenheit - 32.0) / 9;
366 : :
367 : 2 : if (g_test_verbose ())
368 : 0 : g_printerr ("Converting %.2fF to %.2fC\n", fahrenheit, celsius);
369 : :
370 : 2 : g_value_set_double (to_value, celsius);
371 : :
372 : 2 : return TRUE;
373 : : }
374 : :
375 : : static void
376 : 1 : binding_default (void)
377 : : {
378 : 1 : BindingSource *source = g_object_new (binding_source_get_type (), NULL);
379 : 1 : BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
380 : : GBinding *binding;
381 : :
382 : 1 : binding = g_object_bind_property (source, "foo",
383 : : target, "bar",
384 : : G_BINDING_DEFAULT);
385 : :
386 : 1 : g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
387 : :
388 : 1 : assert_cmpsource (binding, ==, source);
389 : 1 : assert_cmptarget (binding, ==, target);
390 : :
391 : 1 : g_assert_cmpstr (g_binding_get_source_property (binding), ==, "foo");
392 : 1 : g_assert_cmpstr (g_binding_get_target_property (binding), ==, "bar");
393 : 1 : g_assert_cmpint (g_binding_get_flags (binding), ==, G_BINDING_DEFAULT);
394 : :
395 : 1 : g_object_set (source, "foo", 42, NULL);
396 : 1 : g_assert_cmpint (source->foo, ==, target->bar);
397 : :
398 : 1 : g_object_set (target, "bar", 47, NULL);
399 : 1 : g_assert_cmpint (source->foo, !=, target->bar);
400 : :
401 : 1 : g_object_unref (binding);
402 : :
403 : 1 : g_object_set (source, "foo", 0, NULL);
404 : 1 : g_assert_cmpint (source->foo, !=, target->bar);
405 : :
406 : 1 : g_object_unref (source);
407 : 1 : g_object_unref (target);
408 : 1 : g_assert_null (binding);
409 : 1 : }
410 : :
411 : : static void
412 : 1 : binding_canonicalisation (void)
413 : : {
414 : 1 : BindingSource *source = g_object_new (binding_source_get_type (), NULL);
415 : 1 : BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
416 : : GBinding *binding;
417 : :
418 : 1 : g_test_summary ("Test that bindings set up with non-canonical property names work");
419 : :
420 : 1 : binding = g_object_bind_property (source, "double_value",
421 : : target, "double_value",
422 : : G_BINDING_DEFAULT);
423 : :
424 : 1 : g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
425 : :
426 : 1 : assert_cmpsource (binding, ==, source);
427 : 1 : assert_cmptarget (binding, ==, target);
428 : :
429 : 1 : g_assert_cmpstr (g_binding_get_source_property (binding), ==, "double-value");
430 : 1 : g_assert_cmpstr (g_binding_get_target_property (binding), ==, "double-value");
431 : 1 : g_assert_cmpint (g_binding_get_flags (binding), ==, G_BINDING_DEFAULT);
432 : :
433 : 1 : g_object_set (source, "double-value", 24.0, NULL);
434 : 1 : g_assert_cmpfloat (target->double_value, ==, source->double_value);
435 : :
436 : 1 : g_object_set (target, "double-value", 69.0, NULL);
437 : 1 : g_assert_cmpfloat (source->double_value, !=, target->double_value);
438 : :
439 : 1 : g_object_unref (target);
440 : 1 : g_object_unref (source);
441 : 1 : g_assert_null (binding);
442 : 1 : }
443 : :
444 : : static void
445 : 1 : binding_bidirectional (void)
446 : : {
447 : 1 : BindingSource *source = g_object_new (binding_source_get_type (), NULL);
448 : 1 : BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
449 : : GBinding *binding;
450 : :
451 : 1 : binding = g_object_bind_property (source, "foo",
452 : : target, "bar",
453 : : G_BINDING_BIDIRECTIONAL);
454 : 1 : g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
455 : :
456 : 1 : g_object_set (source, "foo", 42, NULL);
457 : 1 : g_assert_cmpint (source->foo, ==, target->bar);
458 : :
459 : 1 : g_object_set (target, "bar", 47, NULL);
460 : 1 : g_assert_cmpint (source->foo, ==, target->bar);
461 : :
462 : 1 : g_object_unref (binding);
463 : :
464 : 1 : g_object_set (source, "foo", 0, NULL);
465 : 1 : g_assert_cmpint (source->foo, !=, target->bar);
466 : :
467 : 1 : g_object_unref (source);
468 : 1 : g_object_unref (target);
469 : 1 : g_assert_null (binding);
470 : 1 : }
471 : :
472 : : static void
473 : 3 : data_free (gpointer data)
474 : : {
475 : 3 : gboolean *b = data;
476 : :
477 : 3 : *b = TRUE;
478 : 3 : }
479 : :
480 : : static void
481 : 1 : binding_transform_default (void)
482 : : {
483 : 1 : BindingSource *source = g_object_new (binding_source_get_type (), NULL);
484 : 1 : BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
485 : : GBinding *binding;
486 : : gpointer src, trg;
487 : : gchar *src_prop, *trg_prop;
488 : : GBindingFlags flags;
489 : :
490 : 1 : binding = g_object_bind_property (source, "foo",
491 : : target, "double-value",
492 : : G_BINDING_BIDIRECTIONAL);
493 : :
494 : 1 : g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
495 : :
496 : 1 : g_object_get (binding,
497 : : "source", &src,
498 : : "source-property", &src_prop,
499 : : "target", &trg,
500 : : "target-property", &trg_prop,
501 : : "flags", &flags,
502 : : NULL);
503 : 1 : g_assert_true (src == source);
504 : 1 : g_assert_true (trg == target);
505 : 1 : g_assert_cmpstr (src_prop, ==, "foo");
506 : 1 : g_assert_cmpstr (trg_prop, ==, "double-value");
507 : 1 : g_assert_cmpint (flags, ==, G_BINDING_BIDIRECTIONAL);
508 : 1 : g_object_unref (src);
509 : 1 : g_object_unref (trg);
510 : 1 : g_free (src_prop);
511 : 1 : g_free (trg_prop);
512 : :
513 : 1 : g_object_set (source, "foo", 24, NULL);
514 : 1 : g_assert_cmpfloat (target->double_value, ==, 24.0);
515 : :
516 : 1 : g_object_set (target, "double-value", 69.0, NULL);
517 : 1 : g_assert_cmpint (source->foo, ==, 69);
518 : :
519 : 1 : g_object_unref (target);
520 : 1 : g_object_unref (source);
521 : 1 : g_assert_null (binding);
522 : 1 : }
523 : :
524 : : static void
525 : 1 : binding_transform (void)
526 : : {
527 : 1 : BindingSource *source = g_object_new (binding_source_get_type (), NULL);
528 : 1 : BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
529 : : GBinding *binding G_GNUC_UNUSED;
530 : 1 : gboolean unused_data = FALSE;
531 : :
532 : 1 : binding = g_object_bind_property_full (source, "double-value",
533 : : target, "double-value",
534 : : G_BINDING_BIDIRECTIONAL,
535 : : celsius_to_fahrenheit,
536 : : fahrenheit_to_celsius,
537 : : &unused_data, data_free);
538 : :
539 : 1 : g_object_set (source, "double-value", 24.0, NULL);
540 : 1 : g_assert_cmpfloat (target->double_value, ==, ((9 * 24.0 / 5) + 32.0));
541 : :
542 : 1 : g_object_set (target, "double-value", 69.0, NULL);
543 : 1 : g_assert_cmpfloat (source->double_value, ==, (5 * (69.0 - 32.0) / 9));
544 : :
545 : 1 : g_object_unref (source);
546 : 1 : g_object_unref (target);
547 : :
548 : 1 : g_assert_true (unused_data);
549 : 1 : }
550 : :
551 : : static void
552 : 1 : binding_transform_closure (void)
553 : : {
554 : 1 : BindingSource *source = g_object_new (binding_source_get_type (), NULL);
555 : 1 : BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
556 : : GBinding *binding G_GNUC_UNUSED;
557 : 1 : gboolean unused_data_1 = FALSE, unused_data_2 = FALSE;
558 : : GClosure *c2f_clos, *f2c_clos;
559 : :
560 : 1 : c2f_clos = g_cclosure_new (G_CALLBACK (celsius_to_fahrenheit), &unused_data_1, (GClosureNotify) data_free);
561 : :
562 : 1 : f2c_clos = g_cclosure_new (G_CALLBACK (fahrenheit_to_celsius), &unused_data_2, (GClosureNotify) data_free);
563 : :
564 : 1 : binding = g_object_bind_property_with_closures (source, "double-value",
565 : : target, "double-value",
566 : : G_BINDING_BIDIRECTIONAL,
567 : : c2f_clos,
568 : : f2c_clos);
569 : :
570 : 1 : g_object_set (source, "double-value", 24.0, NULL);
571 : 1 : g_assert_cmpfloat (target->double_value, ==, ((9 * 24.0 / 5) + 32.0));
572 : :
573 : 1 : g_object_set (target, "double-value", 69.0, NULL);
574 : 1 : g_assert_cmpfloat (source->double_value, ==, (5 * (69.0 - 32.0) / 9));
575 : :
576 : 1 : g_object_unref (source);
577 : 1 : g_object_unref (target);
578 : :
579 : 1 : g_assert_true (unused_data_1);
580 : 1 : g_assert_true (unused_data_2);
581 : 1 : }
582 : :
583 : : static void
584 : 1 : binding_chain (void)
585 : : {
586 : 1 : BindingSource *a = g_object_new (binding_source_get_type (), NULL);
587 : 1 : BindingSource *b = g_object_new (binding_source_get_type (), NULL);
588 : 1 : BindingSource *c = g_object_new (binding_source_get_type (), NULL);
589 : : GBinding *binding_1, *binding_2;
590 : :
591 : 1 : g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=621782");
592 : :
593 : : /* A -> B, B -> C */
594 : 1 : binding_1 = g_object_bind_property (a, "foo", b, "foo", G_BINDING_BIDIRECTIONAL);
595 : 1 : g_object_add_weak_pointer (G_OBJECT (binding_1), (gpointer *) &binding_1);
596 : :
597 : 1 : binding_2 = g_object_bind_property (b, "foo", c, "foo", G_BINDING_BIDIRECTIONAL);
598 : 1 : g_object_add_weak_pointer (G_OBJECT (binding_2), (gpointer *) &binding_2);
599 : :
600 : : /* verify the chain */
601 : 1 : g_object_set (a, "foo", 42, NULL);
602 : 1 : g_assert_cmpint (a->foo, ==, b->foo);
603 : 1 : g_assert_cmpint (b->foo, ==, c->foo);
604 : :
605 : : /* unbind A -> B and B -> C */
606 : 1 : g_object_unref (binding_1);
607 : 1 : g_assert_null (binding_1);
608 : 1 : g_object_unref (binding_2);
609 : 1 : g_assert_null (binding_2);
610 : :
611 : : /* bind A -> C directly */
612 : 1 : binding_2 = g_object_bind_property (a, "foo", c, "foo", G_BINDING_BIDIRECTIONAL);
613 : :
614 : : /* verify the chain is broken */
615 : 1 : g_object_set (a, "foo", 47, NULL);
616 : 1 : g_assert_cmpint (a->foo, !=, b->foo);
617 : 1 : g_assert_cmpint (a->foo, ==, c->foo);
618 : :
619 : 1 : g_object_unref (a);
620 : 1 : g_object_unref (b);
621 : 1 : g_object_unref (c);
622 : 1 : }
623 : :
624 : : static void
625 : 1 : binding_sync_create (void)
626 : : {
627 : 1 : BindingSource *source = g_object_new (binding_source_get_type (),
628 : : "foo", 42,
629 : : NULL);
630 : 1 : BindingTarget *target = g_object_new (binding_target_get_type (),
631 : : "bar", 47,
632 : : NULL);
633 : : GBinding *binding;
634 : :
635 : 1 : binding = g_object_bind_property (source, "foo",
636 : : target, "bar",
637 : : G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
638 : :
639 : 1 : g_assert_cmpint (source->foo, ==, 42);
640 : 1 : g_assert_cmpint (target->bar, ==, 42);
641 : :
642 : 1 : g_object_set (source, "foo", 47, NULL);
643 : 1 : g_assert_cmpint (source->foo, ==, target->bar);
644 : :
645 : 1 : g_object_unref (binding);
646 : :
647 : 1 : g_object_set (target, "bar", 49, NULL);
648 : :
649 : 1 : binding = g_object_bind_property (source, "foo",
650 : : target, "bar",
651 : : G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
652 : 1 : g_assert_cmpint (source->foo, ==, 47);
653 : 1 : g_assert_cmpint (target->bar, ==, 47);
654 : :
655 : 1 : g_object_unref (source);
656 : 1 : g_object_unref (target);
657 : 1 : }
658 : :
659 : : static void
660 : 1 : binding_invert_boolean (void)
661 : : {
662 : 1 : BindingSource *source = g_object_new (binding_source_get_type (),
663 : : "toggle", TRUE,
664 : : NULL);
665 : 1 : BindingTarget *target = g_object_new (binding_target_get_type (),
666 : : "toggle", FALSE,
667 : : NULL);
668 : : GBinding *binding;
669 : :
670 : 1 : binding = g_object_bind_property (source, "toggle",
671 : : target, "toggle",
672 : : G_BINDING_BIDIRECTIONAL | G_BINDING_INVERT_BOOLEAN);
673 : :
674 : 1 : g_assert_true (source->toggle);
675 : 1 : g_assert_false (target->toggle);
676 : :
677 : 1 : g_object_set (source, "toggle", FALSE, NULL);
678 : 1 : g_assert_false (source->toggle);
679 : 1 : g_assert_true (target->toggle);
680 : :
681 : 1 : g_object_set (target, "toggle", FALSE, NULL);
682 : 1 : g_assert_true (source->toggle);
683 : 1 : g_assert_false (target->toggle);
684 : :
685 : 1 : g_object_unref (binding);
686 : 1 : g_object_unref (source);
687 : 1 : g_object_unref (target);
688 : 1 : }
689 : :
690 : : static void
691 : 1 : binding_same_object (void)
692 : : {
693 : 1 : BindingSource *source = g_object_new (binding_source_get_type (),
694 : : "foo", 100,
695 : : "bar", 50,
696 : : NULL);
697 : : GBinding *binding;
698 : :
699 : 1 : binding = g_object_bind_property (source, "foo",
700 : : source, "bar",
701 : : G_BINDING_BIDIRECTIONAL);
702 : 1 : g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
703 : :
704 : 1 : g_object_set (source, "foo", 10, NULL);
705 : 1 : g_assert_cmpint (source->foo, ==, 10);
706 : 1 : g_assert_cmpint (source->bar, ==, 10);
707 : 1 : g_object_set (source, "bar", 30, NULL);
708 : 1 : g_assert_cmpint (source->foo, ==, 30);
709 : 1 : g_assert_cmpint (source->bar, ==, 30);
710 : :
711 : 1 : g_object_unref (source);
712 : 1 : g_assert_null (binding);
713 : 1 : }
714 : :
715 : : static void
716 : 1 : binding_unbind (void)
717 : : {
718 : 1 : BindingSource *source = g_object_new (binding_source_get_type (), NULL);
719 : 1 : BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
720 : : GBinding *binding;
721 : :
722 : 1 : binding = g_object_bind_property (source, "foo",
723 : : target, "bar",
724 : : G_BINDING_DEFAULT);
725 : 1 : g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
726 : :
727 : 1 : g_object_set (source, "foo", 42, NULL);
728 : 1 : g_assert_cmpint (source->foo, ==, target->bar);
729 : :
730 : 1 : g_object_set (target, "bar", 47, NULL);
731 : 1 : g_assert_cmpint (source->foo, !=, target->bar);
732 : :
733 : 1 : g_binding_unbind (binding);
734 : 1 : g_assert_null (binding);
735 : :
736 : 1 : g_object_set (source, "foo", 0, NULL);
737 : 1 : g_assert_cmpint (source->foo, !=, target->bar);
738 : :
739 : 1 : g_object_unref (source);
740 : 1 : g_object_unref (target);
741 : :
742 : :
743 : : /* g_binding_unbind() has a special case for this */
744 : 1 : source = g_object_new (binding_source_get_type (), NULL);
745 : 1 : binding = g_object_bind_property (source, "foo",
746 : : source, "bar",
747 : : G_BINDING_DEFAULT);
748 : 1 : g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
749 : :
750 : 1 : g_binding_unbind (binding);
751 : 1 : g_assert_null (binding);
752 : :
753 : 1 : g_object_unref (source);
754 : 1 : }
755 : :
756 : : /* When source or target die, so does the binding if there is no other ref */
757 : : static void
758 : 1 : binding_unbind_weak (void)
759 : : {
760 : : GBinding *binding;
761 : : BindingSource *source;
762 : : BindingTarget *target;
763 : :
764 : : /* first source, then target */
765 : 1 : source = g_object_new (binding_source_get_type (), NULL);
766 : 1 : target = g_object_new (binding_target_get_type (), NULL);
767 : 1 : binding = g_object_bind_property (source, "foo",
768 : : target, "bar",
769 : : G_BINDING_DEFAULT);
770 : 1 : g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
771 : 1 : g_assert_nonnull (binding);
772 : 1 : g_object_unref (source);
773 : 1 : g_assert_null (binding);
774 : 1 : g_object_unref (target);
775 : 1 : g_assert_null (binding);
776 : :
777 : : /* first target, then source */
778 : 1 : source = g_object_new (binding_source_get_type (), NULL);
779 : 1 : target = g_object_new (binding_target_get_type (), NULL);
780 : 1 : binding = g_object_bind_property (source, "foo",
781 : : target, "bar",
782 : : G_BINDING_DEFAULT);
783 : 1 : g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
784 : 1 : g_assert_nonnull (binding);
785 : 1 : g_object_unref (target);
786 : 1 : g_assert_null (binding);
787 : 1 : g_object_unref (source);
788 : 1 : g_assert_null (binding);
789 : :
790 : : /* target and source are the same */
791 : 1 : source = g_object_new (binding_source_get_type (), NULL);
792 : 1 : binding = g_object_bind_property (source, "foo",
793 : : source, "bar",
794 : : G_BINDING_DEFAULT);
795 : 1 : g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
796 : 1 : g_assert_nonnull (binding);
797 : 1 : g_object_unref (source);
798 : 1 : g_assert_null (binding);
799 : 1 : }
800 : :
801 : : /* Test that every call to unbind() after the first is a noop */
802 : : static void
803 : 1 : binding_unbind_multiple (void)
804 : : {
805 : 1 : BindingSource *source = g_object_new (binding_source_get_type (), NULL);
806 : 1 : BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
807 : : GBinding *binding;
808 : : guint i;
809 : :
810 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1373");
811 : :
812 : 1 : binding = g_object_bind_property (source, "foo",
813 : : target, "bar",
814 : : G_BINDING_DEFAULT);
815 : 1 : g_object_ref (binding);
816 : 1 : g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
817 : 1 : g_assert_nonnull (binding);
818 : :
819 : : /* this shouldn't crash */
820 : 51 : for (i = 0; i < 50; i++)
821 : : {
822 : 50 : g_binding_unbind (binding);
823 : 50 : g_assert_nonnull (binding);
824 : : }
825 : :
826 : 1 : g_object_unref (binding);
827 : 1 : g_assert_null (binding);
828 : :
829 : 1 : g_object_unref (source);
830 : 1 : g_object_unref (target);
831 : 1 : }
832 : :
833 : : static void
834 : 1 : binding_fail (void)
835 : : {
836 : 1 : BindingSource *source = g_object_new (binding_source_get_type (), NULL);
837 : 1 : BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
838 : : GBinding *binding;
839 : :
840 : : /* double -> boolean is not supported */
841 : 1 : binding = g_object_bind_property (source, "double-value",
842 : : target, "toggle",
843 : : G_BINDING_DEFAULT);
844 : 1 : g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
845 : :
846 : 1 : g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_CRITICAL,
847 : : "*Unable to convert*double*boolean*");
848 : 1 : g_object_set (source, "double-value", 1.0, NULL);
849 : 1 : g_test_assert_expected_messages ();
850 : :
851 : 1 : g_object_unref (source);
852 : 1 : g_object_unref (target);
853 : 1 : g_assert_null (binding);
854 : 1 : }
855 : :
856 : : static gboolean
857 : 1 : transform_to_func (GBinding *binding,
858 : : const GValue *value_a,
859 : : GValue *value_b,
860 : : gpointer user_data)
861 : : {
862 : 1 : if (g_value_type_compatible (G_VALUE_TYPE (value_a), G_VALUE_TYPE (value_b)))
863 : : {
864 : 0 : g_value_copy (value_a, value_b);
865 : 0 : return TRUE;
866 : : }
867 : :
868 : 1 : if (g_value_type_transformable (G_VALUE_TYPE (value_a), G_VALUE_TYPE (value_b)))
869 : : {
870 : 1 : if (g_value_transform (value_a, value_b))
871 : 1 : return TRUE;
872 : : }
873 : :
874 : 0 : return FALSE;
875 : : }
876 : :
877 : : static void
878 : 1 : binding_interface (void)
879 : : {
880 : 1 : BindingSource *source = g_object_new (binding_source_get_type (), NULL);
881 : 1 : BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
882 : : GObject *baa;
883 : : GBinding *binding;
884 : : GClosure *transform_to;
885 : :
886 : : /* binding a generic object property to an interface-valued one */
887 : 1 : binding = g_object_bind_property (source, "object",
888 : : target, "foo",
889 : : G_BINDING_DEFAULT);
890 : :
891 : 1 : baa = g_object_new (baa_get_type (), NULL);
892 : 1 : g_object_set (source, "object", baa, NULL);
893 : 1 : g_object_unref (baa);
894 : :
895 : 1 : g_binding_unbind (binding);
896 : :
897 : : /* the same, with a generic marshaller */
898 : 1 : transform_to = g_cclosure_new (G_CALLBACK (transform_to_func), NULL, NULL);
899 : 1 : g_closure_set_marshal (transform_to, g_cclosure_marshal_generic);
900 : 1 : binding = g_object_bind_property_with_closures (source, "object",
901 : : target, "foo",
902 : : G_BINDING_DEFAULT,
903 : : transform_to,
904 : : NULL);
905 : :
906 : 1 : baa = g_object_new (baa_get_type (), NULL);
907 : 1 : g_object_set (source, "object", baa, NULL);
908 : 1 : g_object_unref (baa);
909 : :
910 : 1 : g_binding_unbind (binding);
911 : :
912 : 1 : g_object_unref (source);
913 : 1 : g_object_unref (target);
914 : 1 : }
915 : :
916 : : typedef struct {
917 : : GThread *thread;
918 : : GBinding *binding;
919 : : GMutex *lock;
920 : : GCond *cond;
921 : : gboolean *wait;
922 : : gint *count; /* (atomic) */
923 : : } ConcurrentUnbindData;
924 : :
925 : : static gpointer
926 : 500 : concurrent_unbind_func (gpointer data)
927 : : {
928 : 500 : ConcurrentUnbindData *unbind_data = data;
929 : :
930 : 500 : g_mutex_lock (unbind_data->lock);
931 : 500 : g_atomic_int_inc (unbind_data->count);
932 : 1000 : while (*unbind_data->wait)
933 : 500 : g_cond_wait (unbind_data->cond, unbind_data->lock);
934 : 500 : g_mutex_unlock (unbind_data->lock);
935 : 500 : g_binding_unbind (unbind_data->binding);
936 : 500 : g_object_unref (unbind_data->binding);
937 : :
938 : 500 : return NULL;
939 : : }
940 : :
941 : : static void
942 : 1 : binding_concurrent_unbind (void)
943 : : {
944 : : guint i, j;
945 : :
946 : 1 : g_test_summary ("Test that unbinding from multiple threads concurrently works correctly");
947 : :
948 : 51 : for (i = 0; i < 50; i++)
949 : : {
950 : 50 : BindingSource *source = g_object_new (binding_source_get_type (), NULL);
951 : 50 : BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
952 : : GBinding *binding;
953 : 50 : GQueue threads = G_QUEUE_INIT;
954 : : GMutex lock;
955 : : GCond cond;
956 : 50 : gboolean wait = TRUE;
957 : 50 : gint count = 0; /* (atomic) */
958 : : ConcurrentUnbindData *data;
959 : :
960 : 50 : g_mutex_init (&lock);
961 : 50 : g_cond_init (&cond);
962 : :
963 : 50 : binding = g_object_bind_property (source, "foo",
964 : : target, "bar",
965 : : G_BINDING_BIDIRECTIONAL);
966 : 50 : g_object_ref (binding);
967 : :
968 : 550 : for (j = 0; j < 10; j++)
969 : : {
970 : 500 : data = g_new0 (ConcurrentUnbindData, 1);
971 : :
972 : 500 : data->binding = g_object_ref (binding);
973 : 500 : data->lock = &lock;
974 : 500 : data->cond = &cond;
975 : 500 : data->wait = &wait;
976 : 500 : data->count = &count;
977 : :
978 : 500 : data->thread = g_thread_new ("binding-concurrent", concurrent_unbind_func, data);
979 : 500 : g_queue_push_tail (&threads, data);
980 : : }
981 : :
982 : : /* wait until all threads are started */
983 : 218147 : while (g_atomic_int_get (&count) < 10)
984 : 218097 : g_thread_yield ();
985 : :
986 : 50 : g_mutex_lock (&lock);
987 : 50 : wait = FALSE;
988 : 50 : g_cond_broadcast (&cond);
989 : 50 : g_mutex_unlock (&lock);
990 : :
991 : 550 : while ((data = g_queue_pop_head (&threads)))
992 : : {
993 : 500 : g_thread_join (data->thread);
994 : 500 : g_free (data);
995 : : }
996 : :
997 : 50 : g_mutex_clear (&lock);
998 : 50 : g_cond_clear (&cond);
999 : :
1000 : 50 : g_object_unref (binding);
1001 : 50 : g_object_unref (source);
1002 : 50 : g_object_unref (target);
1003 : : }
1004 : 1 : }
1005 : :
1006 : : typedef struct {
1007 : : GObject *object;
1008 : : GMutex *lock;
1009 : : GCond *cond;
1010 : : gint *count; /* (atomic) */
1011 : : gboolean *wait;
1012 : : } ConcurrentFinalizeData;
1013 : :
1014 : : static gpointer
1015 : 100 : concurrent_finalize_func (gpointer data)
1016 : : {
1017 : 100 : ConcurrentFinalizeData *finalize_data = data;
1018 : :
1019 : 100 : g_mutex_lock (finalize_data->lock);
1020 : 100 : g_atomic_int_inc (finalize_data->count);
1021 : 200 : while (*finalize_data->wait)
1022 : 100 : g_cond_wait (finalize_data->cond, finalize_data->lock);
1023 : 100 : g_mutex_unlock (finalize_data->lock);
1024 : 100 : g_object_unref (finalize_data->object);
1025 : 100 : g_free (finalize_data);
1026 : :
1027 : 100 : return NULL;
1028 : : }
1029 : :
1030 : : static void
1031 : 1 : binding_concurrent_finalizing (void)
1032 : : {
1033 : : guint i;
1034 : :
1035 : 1 : g_test_summary ("Test that finalizing source/target from multiple threads concurrently works correctly");
1036 : :
1037 : 51 : for (i = 0; i < 50; i++)
1038 : : {
1039 : 50 : BindingSource *source = g_object_new (binding_source_get_type (), NULL);
1040 : 50 : BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
1041 : : GBinding *binding;
1042 : : GMutex lock;
1043 : : GCond cond;
1044 : 50 : gboolean wait = TRUE;
1045 : : ConcurrentFinalizeData *data;
1046 : : GThread *source_thread, *target_thread;
1047 : 50 : gint count = 0; /* (atomic) */
1048 : :
1049 : 50 : g_mutex_init (&lock);
1050 : 50 : g_cond_init (&cond);
1051 : :
1052 : 50 : binding = g_object_bind_property (source, "foo",
1053 : : target, "bar",
1054 : : G_BINDING_BIDIRECTIONAL);
1055 : 50 : g_object_ref (binding);
1056 : :
1057 : 50 : data = g_new0 (ConcurrentFinalizeData, 1);
1058 : 50 : data->object = (GObject *) source;
1059 : 50 : data->wait = &wait;
1060 : 50 : data->lock = &lock;
1061 : 50 : data->cond = &cond;
1062 : 50 : data->count = &count;
1063 : 50 : source_thread = g_thread_new ("binding-concurrent", concurrent_finalize_func, data);
1064 : :
1065 : 50 : data = g_new0 (ConcurrentFinalizeData, 1);
1066 : 50 : data->object = (GObject *) target;
1067 : 50 : data->wait = &wait;
1068 : 50 : data->lock = &lock;
1069 : 50 : data->cond = &cond;
1070 : 50 : data->count = &count;
1071 : 50 : target_thread = g_thread_new ("binding-concurrent", concurrent_finalize_func, data);
1072 : :
1073 : : /* wait until all threads are started */
1074 : 161391 : while (g_atomic_int_get (&count) < 2)
1075 : 161341 : g_thread_yield ();
1076 : :
1077 : 50 : g_mutex_lock (&lock);
1078 : 50 : wait = FALSE;
1079 : 50 : g_cond_broadcast (&cond);
1080 : 50 : g_mutex_unlock (&lock);
1081 : :
1082 : 50 : g_thread_join (source_thread);
1083 : 50 : g_thread_join (target_thread);
1084 : :
1085 : 50 : g_mutex_clear (&lock);
1086 : 50 : g_cond_clear (&cond);
1087 : :
1088 : 50 : g_object_unref (binding);
1089 : : }
1090 : 1 : }
1091 : :
1092 : : static void
1093 : 1 : binding_dispose_source (void)
1094 : : {
1095 : : /* Test that the source can be disposed */
1096 : 1 : BindingSource *source = g_object_new (binding_source_get_type (), NULL);
1097 : 1 : BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
1098 : : GBinding *binding;
1099 : :
1100 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2676");
1101 : :
1102 : 1 : binding = g_object_bind_property (source, "foo",
1103 : : target, "bar",
1104 : : G_BINDING_DEFAULT);
1105 : :
1106 : 1 : g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
1107 : :
1108 : 1 : g_object_run_dispose (G_OBJECT (source));
1109 : 1 : g_assert_null (binding);
1110 : :
1111 : 1 : g_object_unref (target);
1112 : 1 : g_object_unref (source);
1113 : 1 : }
1114 : :
1115 : : static void
1116 : 1 : binding_dispose_target (void)
1117 : : {
1118 : : /* Test that the target can be disposed */
1119 : 1 : BindingSource *source = g_object_new (binding_source_get_type (), NULL);
1120 : 1 : BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
1121 : : GBinding *binding;
1122 : :
1123 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2676");
1124 : :
1125 : 1 : binding = g_object_bind_property (source, "foo",
1126 : : target, "bar",
1127 : : G_BINDING_DEFAULT);
1128 : :
1129 : 1 : g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
1130 : :
1131 : 1 : g_object_run_dispose (G_OBJECT (target));
1132 : 1 : g_assert_null (binding);
1133 : :
1134 : 1 : g_object_unref (target);
1135 : 1 : g_object_unref (source);
1136 : 1 : }
1137 : :
1138 : : int
1139 : 1 : main (int argc, char *argv[])
1140 : : {
1141 : 1 : g_test_init (&argc, &argv, NULL);
1142 : :
1143 : 1 : g_test_add_func ("/binding/default", binding_default);
1144 : 1 : g_test_add_func ("/binding/canonicalisation", binding_canonicalisation);
1145 : 1 : g_test_add_func ("/binding/bidirectional", binding_bidirectional);
1146 : 1 : g_test_add_func ("/binding/transform", binding_transform);
1147 : 1 : g_test_add_func ("/binding/transform-default", binding_transform_default);
1148 : 1 : g_test_add_func ("/binding/transform-closure", binding_transform_closure);
1149 : 1 : g_test_add_func ("/binding/chain", binding_chain);
1150 : 1 : g_test_add_func ("/binding/sync-create", binding_sync_create);
1151 : 1 : g_test_add_func ("/binding/invert-boolean", binding_invert_boolean);
1152 : 1 : g_test_add_func ("/binding/same-object", binding_same_object);
1153 : 1 : g_test_add_func ("/binding/unbind", binding_unbind);
1154 : 1 : g_test_add_func ("/binding/unbind-weak", binding_unbind_weak);
1155 : 1 : g_test_add_func ("/binding/unbind-multiple", binding_unbind_multiple);
1156 : 1 : g_test_add_func ("/binding/fail", binding_fail);
1157 : 1 : g_test_add_func ("/binding/interface", binding_interface);
1158 : 1 : g_test_add_func ("/binding/concurrent-unbind", binding_concurrent_unbind);
1159 : 1 : g_test_add_func ("/binding/concurrent-finalizing", binding_concurrent_finalizing);
1160 : 1 : g_test_add_func ("/binding/dispose-source", binding_dispose_source);
1161 : 1 : g_test_add_func ("/binding/dispose-target", binding_dispose_target);
1162 : :
1163 : 1 : return g_test_run ();
1164 : : }
|