11 activate (GAction *action,
15 Activation *activation = user_data;
18 activation->params = g_variant_ref (parameter);
20 activation->params = NULL;
21 activation->did_run = TRUE;
27 Activation a = { 0, };
28 GSimpleAction *action;
30 GVariantType *parameter_type;
32 GVariantType *state_type;
35 action = g_simple_action_new ("foo", NULL);
36 g_assert (g_action_get_enabled (G_ACTION (action)));
37 g_assert (g_action_get_parameter_type (G_ACTION (action)) == NULL);
38 g_assert (g_action_get_state_type (G_ACTION (action)) == NULL);
39 g_assert (g_action_get_state_hint (G_ACTION (action)) == NULL);
40 g_assert (g_action_get_state (G_ACTION (action)) == NULL);
43 "parameter-type", ¶meter_type,
45 "state-type", &state_type,
48 g_assert_cmpstr (name, ==, "foo");
49 g_assert (parameter_type == NULL);
51 g_assert (state_type == NULL);
52 g_assert (state == NULL);
55 g_signal_connect (action, "activate", G_CALLBACK (activate), &a);
56 g_assert (!a.did_run);
57 g_action_activate (G_ACTION (action), NULL);
61 g_simple_action_set_enabled (action, FALSE);
62 g_action_activate (G_ACTION (action), NULL);
63 g_assert (!a.did_run);
65 if (g_test_undefined ())
67 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
69 g_action_activate (G_ACTION (action), g_variant_new_string ("xxx"));
72 g_test_trap_assert_failed ();
75 g_object_unref (action);
76 g_assert (!a.did_run);
78 action = g_simple_action_new ("foo", G_VARIANT_TYPE_STRING);
79 g_assert (g_action_get_enabled (G_ACTION (action)));
80 g_assert (g_variant_type_equal (g_action_get_parameter_type (G_ACTION (action)), G_VARIANT_TYPE_STRING));
81 g_assert (g_action_get_state_type (G_ACTION (action)) == NULL);
82 g_assert (g_action_get_state_hint (G_ACTION (action)) == NULL);
83 g_assert (g_action_get_state (G_ACTION (action)) == NULL);
85 g_signal_connect (action, "activate", G_CALLBACK (activate), &a);
86 g_assert (!a.did_run);
87 g_action_activate (G_ACTION (action), g_variant_new_string ("Hello world"));
89 g_assert_cmpstr (g_variant_get_string (a.params, NULL), ==, "Hello world");
90 g_variant_unref (a.params);
93 if (g_test_undefined ())
95 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
97 g_action_activate (G_ACTION (action), NULL);
101 g_test_trap_assert_failed ();
104 g_object_unref (action);
105 g_assert (!a.did_run);
109 strv_has_string (gchar **haystack,
114 for (n = 0; haystack != NULL && haystack[n] != NULL; n++)
116 if (g_strcmp0 (haystack[n], needle) == 0)
123 strv_strv_cmp (gchar **a, gchar **b)
127 for (n = 0; a[n] != NULL; n++)
129 if (!strv_has_string (b, a[n]))
133 for (n = 0; b[n] != NULL; n++)
135 if (!strv_has_string (a, b[n]))
143 strv_set_equal (gchar **strv, ...)
152 va_start (list, strv);
155 str = va_arg (list, const gchar *);
158 if (!strv_has_string (strv, str))
168 res = g_strv_length ((gchar**)strv) == count;
174 test_simple_group (void)
176 GSimpleActionGroup *group;
177 Activation a = { 0, };
178 GSimpleAction *simple;
183 simple = g_simple_action_new ("foo", NULL);
184 g_signal_connect (simple, "activate", G_CALLBACK (activate), &a);
185 g_assert (!a.did_run);
186 g_action_activate (G_ACTION (simple), NULL);
187 g_assert (a.did_run);
190 group = g_simple_action_group_new ();
191 g_simple_action_group_insert (group, G_ACTION (simple));
192 g_object_unref (simple);
194 g_assert (!a.did_run);
195 g_action_group_activate_action (G_ACTION_GROUP (group), "foo", NULL);
196 g_assert (a.did_run);
198 simple = g_simple_action_new_stateful ("bar", G_VARIANT_TYPE_STRING, g_variant_new_string ("hihi"));
199 g_simple_action_group_insert (group, G_ACTION (simple));
200 g_object_unref (simple);
202 g_assert (g_action_group_has_action (G_ACTION_GROUP (group), "foo"));
203 g_assert (g_action_group_has_action (G_ACTION_GROUP (group), "bar"));
204 g_assert (!g_action_group_has_action (G_ACTION_GROUP (group), "baz"));
205 actions = g_action_group_list_actions (G_ACTION_GROUP (group));
206 g_assert_cmpint (g_strv_length (actions), ==, 2);
207 g_assert (strv_set_equal (actions, "foo", "bar", NULL));
208 g_strfreev (actions);
209 g_assert (g_action_group_get_action_enabled (G_ACTION_GROUP (group), "foo"));
210 g_assert (g_action_group_get_action_enabled (G_ACTION_GROUP (group), "bar"));
211 g_assert (g_action_group_get_action_parameter_type (G_ACTION_GROUP (group), "foo") == NULL);
212 g_assert (g_variant_type_equal (g_action_group_get_action_parameter_type (G_ACTION_GROUP (group), "bar"), G_VARIANT_TYPE_STRING));
213 g_assert (g_action_group_get_action_state_type (G_ACTION_GROUP (group), "foo") == NULL);
214 g_assert (g_variant_type_equal (g_action_group_get_action_state_type (G_ACTION_GROUP (group), "bar"), G_VARIANT_TYPE_STRING));
215 g_assert (g_action_group_get_action_state_hint (G_ACTION_GROUP (group), "foo") == NULL);
216 g_assert (g_action_group_get_action_state_hint (G_ACTION_GROUP (group), "bar") == NULL);
217 g_assert (g_action_group_get_action_state (G_ACTION_GROUP (group), "foo") == NULL);
218 state = g_action_group_get_action_state (G_ACTION_GROUP (group), "bar");
219 g_assert (g_variant_type_equal (g_variant_get_type (state), G_VARIANT_TYPE_STRING));
220 g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hihi");
221 g_variant_unref (state);
223 g_action_group_change_action_state (G_ACTION_GROUP (group), "bar", g_variant_new_string ("boo"));
224 state = g_action_group_get_action_state (G_ACTION_GROUP (group), "bar");
225 g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "boo");
226 g_variant_unref (state);
228 action = g_simple_action_group_lookup (group, "bar");
229 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
230 g_assert (!g_action_group_get_action_enabled (G_ACTION_GROUP (group), "bar"));
232 g_simple_action_group_remove (group, "bar");
233 action = g_simple_action_group_lookup (group, "foo");
234 g_assert_cmpstr (g_action_get_name (action), ==, "foo");
235 action = g_simple_action_group_lookup (group, "bar");
236 g_assert (action == NULL);
239 g_object_unref (group);
240 g_assert (!a.did_run);
246 GSimpleAction *action;
249 action = g_simple_action_new_stateful ("foo", NULL, g_variant_new_string ("hihi"));
250 g_assert (g_action_get_enabled (G_ACTION (action)));
251 g_assert (g_action_get_parameter_type (G_ACTION (action)) == NULL);
252 g_assert (g_action_get_state_hint (G_ACTION (action)) == NULL);
253 g_assert (g_variant_type_equal (g_action_get_state_type (G_ACTION (action)),
254 G_VARIANT_TYPE_STRING));
255 state = g_action_get_state (G_ACTION (action));
256 g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hihi");
257 g_variant_unref (state);
259 if (g_test_undefined ())
261 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
263 g_simple_action_set_state (action, g_variant_new_int32 (123));
266 g_test_trap_assert_failed ();
269 g_simple_action_set_state (action, g_variant_new_string ("hello"));
270 state = g_action_get_state (G_ACTION (action));
271 g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hello");
272 g_variant_unref (state);
274 g_object_unref (action);
276 action = g_simple_action_new ("foo", NULL);
278 if (g_test_undefined ())
280 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
282 g_simple_action_set_state (action, g_variant_new_int32 (123));
285 g_test_trap_assert_failed ();
288 g_object_unref (action);
291 static gboolean foo_activated = FALSE;
292 static gboolean bar_activated = FALSE;
295 activate_foo (GSimpleAction *simple,
299 g_assert (user_data == GINT_TO_POINTER (123));
300 g_assert (parameter == NULL);
301 foo_activated = TRUE;
305 activate_bar (GSimpleAction *simple,
309 g_assert (user_data == GINT_TO_POINTER (123));
310 g_assert_cmpstr (g_variant_get_string (parameter, NULL), ==, "param");
311 bar_activated = TRUE;
315 change_volume_state (GSimpleAction *action,
321 requested = g_variant_get_int32 (value);
323 /* Volume only goes from 0 to 10 */
324 if (0 <= requested && requested <= 10)
325 g_simple_action_set_state (action, value);
331 const GActionEntry entries[] = {
332 { "foo", activate_foo },
333 { "bar", activate_bar, "s" },
334 { "toggle", NULL, NULL, "false" },
335 { "volume", NULL, NULL, "0", change_volume_state }
337 GSimpleActionGroup *actions;
340 actions = g_simple_action_group_new ();
341 g_simple_action_group_add_entries (actions, entries,
342 G_N_ELEMENTS (entries),
343 GINT_TO_POINTER (123));
345 g_assert (!foo_activated);
346 g_action_group_activate_action (G_ACTION_GROUP (actions), "foo", NULL);
347 g_assert (foo_activated);
348 foo_activated = FALSE;
350 g_assert (!bar_activated);
351 g_action_group_activate_action (G_ACTION_GROUP (actions), "bar",
352 g_variant_new_string ("param"));
353 g_assert (bar_activated);
354 g_assert (!foo_activated);
356 if (g_test_undefined ())
358 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
360 const GActionEntry bad_type = {
361 "bad-type", NULL, "ss"
364 g_simple_action_group_add_entries (actions, &bad_type, 1, NULL);
367 g_test_trap_assert_failed ();
369 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
371 const GActionEntry bad_state = {
372 "bad-state", NULL, NULL, "flse"
375 g_simple_action_group_add_entries (actions, &bad_state, 1, NULL);
378 g_test_trap_assert_failed ();
381 state = g_action_group_get_action_state (G_ACTION_GROUP (actions), "volume");
382 g_assert_cmpint (g_variant_get_int32 (state), ==, 0);
383 g_variant_unref (state);
386 g_action_group_change_action_state (G_ACTION_GROUP (actions), "volume",
387 g_variant_new_int32 (7));
388 state = g_action_group_get_action_state (G_ACTION_GROUP (actions), "volume");
389 g_assert_cmpint (g_variant_get_int32 (state), ==, 7);
390 g_variant_unref (state);
392 /* should not change */
393 g_action_group_change_action_state (G_ACTION_GROUP (actions), "volume",
394 g_variant_new_int32 (11));
395 state = g_action_group_get_action_state (G_ACTION_GROUP (actions), "volume");
396 g_assert_cmpint (g_variant_get_int32 (state), ==, 7);
397 g_variant_unref (state);
399 g_object_unref (actions);
403 GHashTable *activation_counts;
406 count_activation (const gchar *action)
410 if (activation_counts == NULL)
411 activation_counts = g_hash_table_new (g_str_hash, g_str_equal);
412 count = GPOINTER_TO_INT (g_hash_table_lookup (activation_counts, action));
414 g_hash_table_insert (activation_counts, (gpointer)action, GINT_TO_POINTER (count));
418 activation_count (const gchar *action)
420 if (activation_counts == NULL)
423 return GPOINTER_TO_INT (g_hash_table_lookup (activation_counts, action));
427 activate_action (GSimpleAction *action, GVariant *parameter, gpointer user_data)
429 count_activation (g_action_get_name (G_ACTION (action)));
433 activate_toggle (GSimpleAction *action, GVariant *parameter, gpointer user_data)
435 GVariant *old_state, *new_state;
437 count_activation (g_action_get_name (G_ACTION (action)));
439 old_state = g_action_get_state (G_ACTION (action));
440 new_state = g_variant_new_boolean (!g_variant_get_boolean (old_state));
441 g_simple_action_set_state (action, new_state);
442 g_variant_unref (old_state);
446 activate_radio (GSimpleAction *action, GVariant *parameter, gpointer user_data)
450 count_activation (g_action_get_name (G_ACTION (action)));
452 new_state = g_variant_new_string (g_variant_get_string (parameter, NULL));
453 g_simple_action_set_state (action, new_state);
457 compare_action_groups (GActionGroup *a, GActionGroup *b)
464 gboolean aenabled, benabled;
465 const GVariantType *aparameter_type, *bparameter_type;
466 const GVariantType *astate_type, *bstate_type;
467 GVariant *astate_hint, *bstate_hint;
468 GVariant *astate, *bstate;
470 alist = g_action_group_list_actions (a);
471 blist = g_action_group_list_actions (b);
472 equal = strv_strv_cmp (alist, blist);
474 for (i = 0; equal && alist[i]; i++)
476 ares = g_action_group_query_action (a, alist[i], &aenabled, &aparameter_type, &astate_type, &astate_hint, &astate);
477 bres = g_action_group_query_action (b, alist[i], &benabled, &bparameter_type, &bstate_type, &bstate_hint, &bstate);
481 equal = equal && (aenabled == benabled);
482 equal = equal && ((!aparameter_type && !bparameter_type) || g_variant_type_equal (aparameter_type, bparameter_type));
483 equal = equal && ((!astate_type && !bstate_type) || g_variant_type_equal (astate_type, bstate_type));
484 equal = equal && ((!astate_hint && !bstate_hint) || g_variant_equal (astate_hint, bstate_hint));
485 equal = equal && ((!astate && !bstate) || g_variant_equal (astate, bstate));
488 g_variant_unref (astate_hint);
490 g_variant_unref (bstate_hint);
492 g_variant_unref (astate);
494 g_variant_unref (bstate);
507 stop_loop (gpointer data)
509 GMainLoop *loop = data;
511 g_main_loop_quit (loop);
513 return G_SOURCE_REMOVE;
517 test_dbus_export (void)
519 GDBusConnection *bus;
520 GSimpleActionGroup *group;
521 GDBusActionGroup *proxy;
522 GSimpleAction *action;
524 static GActionEntry entries[] = {
525 { "undo", activate_action, NULL, NULL, NULL },
526 { "redo", activate_action, NULL, NULL, NULL },
527 { "cut", activate_action, NULL, NULL, NULL },
528 { "copy", activate_action, NULL, NULL, NULL },
529 { "paste", activate_action, NULL, NULL, NULL },
530 { "bold", activate_toggle, NULL, "true", NULL },
531 { "lang", activate_radio, "s", "'latin'", NULL },
533 GError *error = NULL;
537 loop = g_main_loop_new (NULL, FALSE);
539 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
541 group = g_simple_action_group_new ();
542 g_simple_action_group_add_entries (group, entries, G_N_ELEMENTS (entries), NULL);
544 id = g_dbus_connection_export_action_group (bus, "/", G_ACTION_GROUP (group), &error);
545 g_assert_no_error (error);
547 proxy = g_dbus_action_group_get (bus, g_dbus_connection_get_unique_name (bus), "/");
548 g_strfreev (g_action_group_list_actions (G_ACTION_GROUP (proxy)));
550 g_timeout_add (100, stop_loop, loop);
551 g_main_loop_run (loop);
553 /* test that the initial transfer works */
554 g_assert (G_IS_DBUS_ACTION_GROUP (proxy));
555 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
557 /* test that various changes get propagated from group to proxy */
558 action = g_simple_action_new_stateful ("italic", NULL, g_variant_new_boolean (FALSE));
559 g_simple_action_group_insert (group, G_ACTION (action));
560 g_object_unref (action);
562 g_timeout_add (100, stop_loop, loop);
563 g_main_loop_run (loop);
565 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
567 action = G_SIMPLE_ACTION (g_simple_action_group_lookup (group, "cut"));
568 g_simple_action_set_enabled (action, FALSE);
570 g_timeout_add (100, stop_loop, loop);
571 g_main_loop_run (loop);
573 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
575 action = G_SIMPLE_ACTION (g_simple_action_group_lookup (group, "bold"));
576 g_simple_action_set_state (action, g_variant_new_boolean (FALSE));
578 g_timeout_add (100, stop_loop, loop);
579 g_main_loop_run (loop);
581 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
583 g_simple_action_group_remove (group, "italic");
585 g_timeout_add (100, stop_loop, loop);
586 g_main_loop_run (loop);
588 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
590 /* test that activations and state changes propagate the other way */
592 g_assert_cmpint (activation_count ("copy"), ==, 0);
593 g_action_group_activate_action (G_ACTION_GROUP (proxy), "copy", NULL);
595 g_timeout_add (100, stop_loop, loop);
596 g_main_loop_run (loop);
598 g_assert_cmpint (activation_count ("copy"), ==, 1);
599 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
601 g_assert_cmpint (activation_count ("bold"), ==, 0);
602 g_action_group_activate_action (G_ACTION_GROUP (proxy), "bold", NULL);
604 g_timeout_add (100, stop_loop, loop);
605 g_main_loop_run (loop);
607 g_assert_cmpint (activation_count ("bold"), ==, 1);
608 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
609 v = g_action_group_get_action_state (G_ACTION_GROUP (group), "bold");
610 g_assert (g_variant_get_boolean (v));
613 g_action_group_change_action_state (G_ACTION_GROUP (proxy), "bold", g_variant_new_boolean (FALSE));
615 g_timeout_add (100, stop_loop, loop);
616 g_main_loop_run (loop);
618 g_assert_cmpint (activation_count ("bold"), ==, 1);
619 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
620 v = g_action_group_get_action_state (G_ACTION_GROUP (group), "bold");
621 g_assert (!g_variant_get_boolean (v));
624 g_dbus_connection_unexport_action_group (bus, id);
626 g_object_unref (proxy);
627 g_object_unref (group);
628 g_main_loop_unref (loop);
629 g_object_unref (bus);
633 do_export (gpointer data)
635 GActionGroup *group = data;
638 GError *error = NULL;
640 GDBusConnection *bus;
644 ctx = g_main_context_new ();
646 g_main_context_push_thread_default (ctx);
648 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
649 path = g_strdup_printf("/%p", data);
651 for (i = 0; i < 100000; i++)
653 id = g_dbus_connection_export_action_group (bus, path, G_ACTION_GROUP (group), &error);
654 g_assert_no_error (error);
656 action = g_simple_action_group_lookup (G_SIMPLE_ACTION_GROUP (group), "a");
657 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
658 !g_action_get_enabled (action));
660 g_dbus_connection_unexport_action_group (bus, id);
662 while (g_main_context_iteration (ctx, FALSE));
666 g_object_unref (bus);
668 g_main_context_pop_thread_default (ctx);
670 g_main_context_unref (ctx);
676 test_dbus_threaded (void)
678 GSimpleActionGroup *group[10];
680 static GActionEntry entries[] = {
681 { "a", activate_action, NULL, NULL, NULL },
682 { "b", activate_action, NULL, NULL, NULL },
686 for (i = 0; i < 10; i++)
688 group[i] = g_simple_action_group_new ();
689 g_simple_action_group_add_entries (group[i], entries, G_N_ELEMENTS (entries), NULL);
690 export[i] = g_thread_new ("export", do_export, group[i]);
693 for (i = 0; i < 10; i++)
694 g_thread_join (export[i]);
696 for (i = 0; i < 10; i++)
697 g_object_unref (group[i]);
701 main (int argc, char **argv)
704 g_test_init (&argc, &argv, NULL);
706 g_test_add_func ("/actions/basic", test_basic);
707 g_test_add_func ("/actions/simplegroup", test_simple_group);
708 g_test_add_func ("/actions/stateful", test_stateful);
709 g_test_add_func ("/actions/entries", test_entries);
710 g_test_add_func ("/actions/dbus/export", test_dbus_export);
711 g_test_add_func ("/actions/dbus/threaded", test_dbus_threaded);
713 return g_test_run ();