binding: Cast to avoid compiler warning
[platform/upstream/glib.git] / gobject / tests / binding.c
1 #include <stdlib.h>
2 #include <gstdio.h>
3 #include <glib-object.h>
4
5 typedef struct _BindingSource
6 {
7   GObject parent_instance;
8
9   gint foo;
10   gdouble value;
11 } BindingSource;
12
13 typedef struct _BindingSourceClass
14 {
15   GObjectClass parent_class;
16 } BindingSourceClass;
17
18 enum
19 {
20   PROP_SOURCE_0,
21
22   PROP_SOURCE_FOO,
23
24   PROP_SOURCE_VALUE
25 };
26
27 G_DEFINE_TYPE (BindingSource, binding_source, G_TYPE_OBJECT);
28
29 static void
30 binding_source_set_property (GObject      *gobject,
31                              guint         prop_id,
32                              const GValue *value,
33                              GParamSpec   *pspec)
34 {
35   BindingSource *source = (BindingSource *) gobject;
36
37   switch (prop_id)
38     {
39     case PROP_SOURCE_FOO:
40       source->foo = g_value_get_int (value);
41       break;
42
43     case PROP_SOURCE_VALUE:
44       source->value = g_value_get_double (value);
45       break;
46
47     default:
48       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
49     }
50 }
51
52 static void
53 binding_source_get_property (GObject    *gobject,
54                              guint       prop_id,
55                              GValue     *value,
56                              GParamSpec *pspec)
57 {
58   BindingSource *source = (BindingSource *) gobject;
59
60   switch (prop_id)
61     {
62     case PROP_SOURCE_FOO:
63       g_value_set_int (value, source->foo);
64       break;
65
66     case PROP_SOURCE_VALUE:
67       g_value_set_double (value, source->value);
68       break;
69
70     default:
71       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
72     }
73 }
74
75 static void
76 binding_source_class_init (BindingSourceClass *klass)
77 {
78   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
79
80   gobject_class->set_property = binding_source_set_property;
81   gobject_class->get_property = binding_source_get_property;
82
83   g_object_class_install_property (gobject_class, PROP_SOURCE_FOO,
84                                    g_param_spec_int ("foo", "Foo", "Foo",
85                                                      -1, 100,
86                                                      0,
87                                                      G_PARAM_READWRITE));
88   g_object_class_install_property (gobject_class, PROP_SOURCE_VALUE,
89                                    g_param_spec_double ("value", "Value", "Value",
90                                                         -100.0, 200.0,
91                                                         0.0,
92                                                         G_PARAM_READWRITE));
93 }
94
95 static void
96 binding_source_init (BindingSource *self)
97 {
98 }
99
100 typedef struct _BindingTarget
101 {
102   GObject parent_instance;
103
104   gint bar;
105   gdouble value;
106 } BindingTarget;
107
108 typedef struct _BindingTargetClass
109 {
110   GObjectClass parent_class;
111 } BindingTargetClass;
112
113 enum
114 {
115   PROP_TARGET_0,
116
117   PROP_TARGET_BAR,
118
119   PROP_TARGET_VALUE
120 };
121
122 G_DEFINE_TYPE (BindingTarget, binding_target, G_TYPE_OBJECT);
123
124 static void
125 binding_target_set_property (GObject      *gobject,
126                              guint         prop_id,
127                              const GValue *value,
128                              GParamSpec   *pspec)
129 {
130   BindingTarget *target = (BindingTarget *) gobject;
131
132   switch (prop_id)
133     {
134     case PROP_TARGET_BAR:
135       target->bar = g_value_get_int (value);
136       break;
137
138     case PROP_TARGET_VALUE:
139       target->value = g_value_get_double (value);
140       break;
141
142     default:
143       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
144     }
145 }
146
147 static void
148 binding_target_get_property (GObject    *gobject,
149                              guint       prop_id,
150                              GValue     *value,
151                              GParamSpec *pspec)
152 {
153   BindingTarget *target = (BindingTarget *) gobject;
154
155   switch (prop_id)
156     {
157     case PROP_TARGET_BAR:
158       g_value_set_int (value, target->bar);
159       break;
160
161     case PROP_TARGET_VALUE:
162       g_value_set_double (value, target->value);
163       break;
164
165     default:
166       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
167     }
168 }
169
170 static void
171 binding_target_class_init (BindingTargetClass *klass)
172 {
173   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
174
175   gobject_class->set_property = binding_target_set_property;
176   gobject_class->get_property = binding_target_get_property;
177
178   g_object_class_install_property (gobject_class, PROP_TARGET_BAR,
179                                    g_param_spec_int ("bar", "Bar", "Bar",
180                                                      -1, 100,
181                                                      0,
182                                                      G_PARAM_READWRITE));
183   g_object_class_install_property (gobject_class, PROP_SOURCE_VALUE,
184                                    g_param_spec_double ("value", "Value", "Value",
185                                                         -100.0, 200.0,
186                                                         0.0,
187                                                         G_PARAM_READWRITE));
188 }
189
190 static void
191 binding_target_init (BindingTarget *self)
192 {
193 }
194
195 static gboolean
196 celsius_to_fahrenheit (GBinding     *binding,
197                        const GValue *source_value,
198                        GValue       *target_value,
199                        gpointer      user_data G_GNUC_UNUSED)
200 {
201   gdouble celsius, fahrenheit;
202
203   g_assert (G_VALUE_HOLDS (source_value, G_TYPE_DOUBLE));
204   g_assert (G_VALUE_HOLDS (target_value, G_TYPE_DOUBLE));
205
206   celsius = g_value_get_double (source_value);
207   fahrenheit = (9 * celsius / 5) + 32.0;
208
209   if (g_test_verbose ())
210     g_print ("Converting %.2fC to %.2fF\n", celsius, fahrenheit);
211
212   g_value_set_double (target_value, fahrenheit);
213
214   return TRUE;
215 }
216
217 static gboolean
218 fahrenheit_to_celsius (GBinding     *binding,
219                        const GValue *source_value,
220                        GValue       *target_value,
221                        gpointer      user_data G_GNUC_UNUSED)
222 {
223   gdouble celsius, fahrenheit;
224
225   g_assert (G_VALUE_HOLDS (source_value, G_TYPE_DOUBLE));
226   g_assert (G_VALUE_HOLDS (target_value, G_TYPE_DOUBLE));
227
228   fahrenheit = g_value_get_double (source_value);
229   celsius = 5 * (fahrenheit - 32.0) / 9;
230
231   if (g_test_verbose ())
232     g_print ("Converting %.2fF to %.2fC\n", fahrenheit, celsius);
233
234   g_value_set_double (target_value, celsius);
235
236   return TRUE;
237 }
238
239 static void
240 binding_default (void)
241 {
242   BindingSource *source = g_object_new (binding_source_get_type (), NULL);
243   BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
244   GBinding *binding;
245
246   binding = g_object_bind_property (source, "foo",
247                                     target, "bar",
248                                     G_BINDING_DEFAULT);
249
250   g_assert (g_binding_get_source (binding) == G_OBJECT (source));
251   g_assert (g_binding_get_target (binding) == G_OBJECT (target));
252   g_assert_cmpstr (g_binding_get_source_property (binding), ==, "foo");
253   g_assert_cmpstr (g_binding_get_target_property (binding), ==, "bar");
254   g_assert_cmpint (g_binding_get_flags (binding), ==, G_BINDING_DEFAULT);
255
256   g_object_set (source, "foo", 42, NULL);
257   g_assert_cmpint (source->foo, ==, target->bar);
258
259   g_object_set (target, "bar", 47, NULL);
260   g_assert_cmpint (source->foo, !=, target->bar);
261
262   g_object_unref (binding);
263
264   g_object_set (source, "foo", 0, NULL);
265   g_assert_cmpint (source->foo, !=, target->bar);
266
267   g_object_unref (source);
268   g_object_unref (target);
269 }
270
271 static void
272 binding_bidirectional (void)
273 {
274   BindingSource *source = g_object_new (binding_source_get_type (), NULL);
275   BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
276   GBinding *binding;
277
278   binding = g_object_bind_property (source, "foo",
279                                     target, "bar",
280                                     G_BINDING_BIDIRECTIONAL);
281
282   g_object_set (source, "foo", 42, NULL);
283   g_assert_cmpint (source->foo, ==, target->bar);
284
285   g_object_set (target, "bar", 47, NULL);
286   g_assert_cmpint (source->foo, ==, target->bar);
287
288   g_object_unref (binding);
289
290   g_object_set (source, "foo", 0, NULL);
291   g_assert_cmpint (source->foo, !=, target->bar);
292
293   g_object_unref (source);
294   g_object_unref (target);
295 }
296
297 static void
298 data_free (gpointer data)
299 {
300   gboolean *b = data;
301
302   *b = TRUE;
303 }
304
305 static void
306 binding_transform (void)
307 {
308   BindingSource *source = g_object_new (binding_source_get_type (), NULL);
309   BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
310   GBinding *binding;
311   gboolean unused_data = FALSE;
312
313   binding = g_object_bind_property_full (source, "value",
314                                          target, "value",
315                                          G_BINDING_BIDIRECTIONAL,
316                                          celsius_to_fahrenheit,
317                                          fahrenheit_to_celsius,
318                                          &unused_data, data_free);
319
320   g_object_set (source, "value", 24.0, NULL);
321   g_assert_cmpfloat (target->value, ==, ((9 * 24.0 / 5) + 32.0));
322
323   g_object_set (target, "value", 69.0, NULL);
324   g_assert_cmpfloat (source->value, ==, (5 * (69.0 - 32.0) / 9));
325
326   g_object_unref (source);
327   g_object_unref (target);
328
329   g_assert (unused_data);
330 }
331
332 static void
333 binding_chain (void)
334 {
335   BindingSource *a = g_object_new (binding_source_get_type (), NULL);
336   BindingSource *b = g_object_new (binding_source_get_type (), NULL);
337   BindingSource *c = g_object_new (binding_source_get_type (), NULL);
338   GBinding *binding_1, *binding_2;
339
340   /* A -> B, B -> C */
341   binding_1 = g_object_bind_property (a, "foo", b, "foo", G_BINDING_BIDIRECTIONAL);
342   binding_2 = g_object_bind_property (b, "foo", c, "foo", G_BINDING_BIDIRECTIONAL);
343
344   /* verify the chain */
345   g_object_set (a, "foo", 42, NULL);
346   g_assert_cmpint (a->foo, ==, b->foo);
347   g_assert_cmpint (b->foo, ==, c->foo);
348
349   /* unbind A -> B and B -> C */
350   g_object_unref (binding_1);
351   g_object_unref (binding_2);
352
353   /* bind A -> C directly */
354   binding_2 = g_object_bind_property (a, "foo", c, "foo", G_BINDING_BIDIRECTIONAL);
355
356   /* verify the chain is broken */
357   g_object_set (a, "foo", 47, NULL);
358   g_assert_cmpint (a->foo, !=, b->foo);
359   g_assert_cmpint (a->foo, ==, c->foo);
360
361   g_object_unref (a);
362   g_object_unref (b);
363   g_object_unref (c);
364 }
365
366 static void
367 binding_sync_create (void)
368 {
369   BindingSource *source = g_object_new (binding_source_get_type (),
370                                         "foo", 42,
371                                         NULL);
372   BindingTarget *target = g_object_new (binding_target_get_type (),
373                                         "bar", 47,
374                                         NULL);
375   GBinding *binding;
376
377   binding = g_object_bind_property (source, "foo",
378                                     target, "bar",
379                                     G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
380
381   g_assert_cmpint (source->foo, ==, 42);
382   g_assert_cmpint (target->bar, ==, 42);
383
384   g_object_set (source, "foo", 47, NULL);
385   g_assert_cmpint (source->foo, ==, target->bar);
386
387   g_object_unref (binding);
388
389   g_object_set (target, "bar", 49, NULL);
390
391   binding = g_object_bind_property (source, "foo",
392                                     target, "bar",
393                                     G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
394   g_assert_cmpint (source->foo, ==, 47);
395   g_assert_cmpint (target->bar, ==, 47);
396
397   g_object_unref (source);
398   g_object_unref (target);
399 }
400
401 int
402 main (int argc, char *argv[])
403 {
404   g_type_init ();
405   g_test_init (&argc, &argv, NULL);
406
407   g_test_add_func ("/binding/default", binding_default);
408   g_test_add_func ("/binding/bidirectional", binding_bidirectional);
409   g_test_add_func ("/binding/transform", binding_transform);
410   g_test_add_func ("/binding/chain", binding_chain);
411   g_test_add_func ("/binding/sync-create", binding_sync_create);
412
413   return g_test_run ();
414 }