4 #include "gdbus-sessionbus.h"
13 activate (GAction *action,
17 Activation *activation = user_data;
20 activation->params = g_variant_ref (parameter);
22 activation->params = NULL;
23 activation->did_run = TRUE;
29 Activation a = { 0, };
30 GSimpleAction *action;
32 GVariantType *parameter_type;
34 GVariantType *state_type;
37 action = g_simple_action_new ("foo", NULL);
38 g_assert (g_action_get_enabled (G_ACTION (action)));
39 g_assert (g_action_get_parameter_type (G_ACTION (action)) == NULL);
40 g_assert (g_action_get_state_type (G_ACTION (action)) == NULL);
41 g_assert (g_action_get_state_hint (G_ACTION (action)) == NULL);
42 g_assert (g_action_get_state (G_ACTION (action)) == NULL);
45 "parameter-type", ¶meter_type,
47 "state-type", &state_type,
50 g_assert_cmpstr (name, ==, "foo");
51 g_assert (parameter_type == NULL);
53 g_assert (state_type == NULL);
54 g_assert (state == NULL);
57 g_signal_connect (action, "activate", G_CALLBACK (activate), &a);
58 g_assert (!a.did_run);
59 g_action_activate (G_ACTION (action), NULL);
63 g_simple_action_set_enabled (action, FALSE);
64 g_action_activate (G_ACTION (action), NULL);
65 g_assert (!a.did_run);
67 if (g_test_undefined ())
69 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
71 g_action_activate (G_ACTION (action), g_variant_new_string ("xxx"));
74 g_test_trap_assert_failed ();
77 g_object_unref (action);
78 g_assert (!a.did_run);
80 action = g_simple_action_new ("foo", G_VARIANT_TYPE_STRING);
81 g_assert (g_action_get_enabled (G_ACTION (action)));
82 g_assert (g_variant_type_equal (g_action_get_parameter_type (G_ACTION (action)), G_VARIANT_TYPE_STRING));
83 g_assert (g_action_get_state_type (G_ACTION (action)) == NULL);
84 g_assert (g_action_get_state_hint (G_ACTION (action)) == NULL);
85 g_assert (g_action_get_state (G_ACTION (action)) == NULL);
87 g_signal_connect (action, "activate", G_CALLBACK (activate), &a);
88 g_assert (!a.did_run);
89 g_action_activate (G_ACTION (action), g_variant_new_string ("Hello world"));
91 g_assert_cmpstr (g_variant_get_string (a.params, NULL), ==, "Hello world");
92 g_variant_unref (a.params);
95 if (g_test_undefined ())
97 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
99 g_action_activate (G_ACTION (action), NULL);
103 g_test_trap_assert_failed ();
106 g_object_unref (action);
107 g_assert (!a.did_run);
111 strv_has_string (gchar **haystack,
116 for (n = 0; haystack != NULL && haystack[n] != NULL; n++)
118 if (g_strcmp0 (haystack[n], needle) == 0)
125 strv_strv_cmp (gchar **a, gchar **b)
129 for (n = 0; a[n] != NULL; n++)
131 if (!strv_has_string (b, a[n]))
135 for (n = 0; b[n] != NULL; n++)
137 if (!strv_has_string (a, b[n]))
145 strv_set_equal (gchar **strv, ...)
154 va_start (list, strv);
157 str = va_arg (list, const gchar *);
160 if (!strv_has_string (strv, str))
170 res = g_strv_length ((gchar**)strv) == count;
176 test_simple_group (void)
178 GSimpleActionGroup *group;
179 Activation a = { 0, };
180 GSimpleAction *simple;
185 simple = g_simple_action_new ("foo", NULL);
186 g_signal_connect (simple, "activate", G_CALLBACK (activate), &a);
187 g_assert (!a.did_run);
188 g_action_activate (G_ACTION (simple), NULL);
189 g_assert (a.did_run);
192 group = g_simple_action_group_new ();
193 g_simple_action_group_insert (group, G_ACTION (simple));
194 g_object_unref (simple);
196 g_assert (!a.did_run);
197 g_action_group_activate_action (G_ACTION_GROUP (group), "foo", NULL);
198 g_assert (a.did_run);
200 simple = g_simple_action_new_stateful ("bar", G_VARIANT_TYPE_STRING, g_variant_new_string ("hihi"));
201 g_simple_action_group_insert (group, G_ACTION (simple));
202 g_object_unref (simple);
204 g_assert (g_action_group_has_action (G_ACTION_GROUP (group), "foo"));
205 g_assert (g_action_group_has_action (G_ACTION_GROUP (group), "bar"));
206 g_assert (!g_action_group_has_action (G_ACTION_GROUP (group), "baz"));
207 actions = g_action_group_list_actions (G_ACTION_GROUP (group));
208 g_assert_cmpint (g_strv_length (actions), ==, 2);
209 g_assert (strv_set_equal (actions, "foo", "bar", NULL));
210 g_strfreev (actions);
211 g_assert (g_action_group_get_action_enabled (G_ACTION_GROUP (group), "foo"));
212 g_assert (g_action_group_get_action_enabled (G_ACTION_GROUP (group), "bar"));
213 g_assert (g_action_group_get_action_parameter_type (G_ACTION_GROUP (group), "foo") == NULL);
214 g_assert (g_variant_type_equal (g_action_group_get_action_parameter_type (G_ACTION_GROUP (group), "bar"), G_VARIANT_TYPE_STRING));
215 g_assert (g_action_group_get_action_state_type (G_ACTION_GROUP (group), "foo") == NULL);
216 g_assert (g_variant_type_equal (g_action_group_get_action_state_type (G_ACTION_GROUP (group), "bar"), G_VARIANT_TYPE_STRING));
217 g_assert (g_action_group_get_action_state_hint (G_ACTION_GROUP (group), "foo") == NULL);
218 g_assert (g_action_group_get_action_state_hint (G_ACTION_GROUP (group), "bar") == NULL);
219 g_assert (g_action_group_get_action_state (G_ACTION_GROUP (group), "foo") == NULL);
220 state = g_action_group_get_action_state (G_ACTION_GROUP (group), "bar");
221 g_assert (g_variant_type_equal (g_variant_get_type (state), G_VARIANT_TYPE_STRING));
222 g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hihi");
223 g_variant_unref (state);
225 g_action_group_change_action_state (G_ACTION_GROUP (group), "bar", g_variant_new_string ("boo"));
226 state = g_action_group_get_action_state (G_ACTION_GROUP (group), "bar");
227 g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "boo");
228 g_variant_unref (state);
230 action = g_simple_action_group_lookup (group, "bar");
231 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
232 g_assert (!g_action_group_get_action_enabled (G_ACTION_GROUP (group), "bar"));
234 g_simple_action_group_remove (group, "bar");
235 action = g_simple_action_group_lookup (group, "foo");
236 g_assert_cmpstr (g_action_get_name (action), ==, "foo");
237 action = g_simple_action_group_lookup (group, "bar");
238 g_assert (action == NULL);
241 g_object_unref (group);
242 g_assert (!a.did_run);
248 GSimpleAction *action;
251 action = g_simple_action_new_stateful ("foo", NULL, g_variant_new_string ("hihi"));
252 g_assert (g_action_get_enabled (G_ACTION (action)));
253 g_assert (g_action_get_parameter_type (G_ACTION (action)) == NULL);
254 g_assert (g_action_get_state_hint (G_ACTION (action)) == NULL);
255 g_assert (g_variant_type_equal (g_action_get_state_type (G_ACTION (action)),
256 G_VARIANT_TYPE_STRING));
257 state = g_action_get_state (G_ACTION (action));
258 g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hihi");
259 g_variant_unref (state);
261 if (g_test_undefined ())
263 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
265 g_simple_action_set_state (action, g_variant_new_int32 (123));
268 g_test_trap_assert_failed ();
271 g_simple_action_set_state (action, g_variant_new_string ("hello"));
272 state = g_action_get_state (G_ACTION (action));
273 g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "hello");
274 g_variant_unref (state);
276 g_object_unref (action);
278 action = g_simple_action_new ("foo", NULL);
280 if (g_test_undefined ())
282 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
284 g_simple_action_set_state (action, g_variant_new_int32 (123));
287 g_test_trap_assert_failed ();
290 g_object_unref (action);
293 static gboolean foo_activated = FALSE;
294 static gboolean bar_activated = FALSE;
297 activate_foo (GSimpleAction *simple,
301 g_assert (user_data == GINT_TO_POINTER (123));
302 g_assert (parameter == NULL);
303 foo_activated = TRUE;
307 activate_bar (GSimpleAction *simple,
311 g_assert (user_data == GINT_TO_POINTER (123));
312 g_assert_cmpstr (g_variant_get_string (parameter, NULL), ==, "param");
313 bar_activated = TRUE;
317 change_volume_state (GSimpleAction *action,
323 requested = g_variant_get_int32 (value);
325 /* Volume only goes from 0 to 10 */
326 if (0 <= requested && requested <= 10)
327 g_simple_action_set_state (action, value);
333 const GActionEntry entries[] = {
334 { "foo", activate_foo },
335 { "bar", activate_bar, "s" },
336 { "toggle", NULL, NULL, "false" },
337 { "volume", NULL, NULL, "0", change_volume_state }
339 GSimpleActionGroup *actions;
342 actions = g_simple_action_group_new ();
343 g_simple_action_group_add_entries (actions, entries,
344 G_N_ELEMENTS (entries),
345 GINT_TO_POINTER (123));
347 g_assert (!foo_activated);
348 g_action_group_activate_action (G_ACTION_GROUP (actions), "foo", NULL);
349 g_assert (foo_activated);
350 foo_activated = FALSE;
352 g_assert (!bar_activated);
353 g_action_group_activate_action (G_ACTION_GROUP (actions), "bar",
354 g_variant_new_string ("param"));
355 g_assert (bar_activated);
356 g_assert (!foo_activated);
358 if (g_test_undefined ())
360 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
362 const GActionEntry bad_type = {
363 "bad-type", NULL, "ss"
366 g_simple_action_group_add_entries (actions, &bad_type, 1, NULL);
369 g_test_trap_assert_failed ();
371 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
373 const GActionEntry bad_state = {
374 "bad-state", NULL, NULL, "flse"
377 g_simple_action_group_add_entries (actions, &bad_state, 1, NULL);
380 g_test_trap_assert_failed ();
383 state = g_action_group_get_action_state (G_ACTION_GROUP (actions), "volume");
384 g_assert_cmpint (g_variant_get_int32 (state), ==, 0);
385 g_variant_unref (state);
388 g_action_group_change_action_state (G_ACTION_GROUP (actions), "volume",
389 g_variant_new_int32 (7));
390 state = g_action_group_get_action_state (G_ACTION_GROUP (actions), "volume");
391 g_assert_cmpint (g_variant_get_int32 (state), ==, 7);
392 g_variant_unref (state);
394 /* should not change */
395 g_action_group_change_action_state (G_ACTION_GROUP (actions), "volume",
396 g_variant_new_int32 (11));
397 state = g_action_group_get_action_state (G_ACTION_GROUP (actions), "volume");
398 g_assert_cmpint (g_variant_get_int32 (state), ==, 7);
399 g_variant_unref (state);
401 g_object_unref (actions);
405 GHashTable *activation_counts;
408 count_activation (const gchar *action)
412 if (activation_counts == NULL)
413 activation_counts = g_hash_table_new (g_str_hash, g_str_equal);
414 count = GPOINTER_TO_INT (g_hash_table_lookup (activation_counts, action));
416 g_hash_table_insert (activation_counts, (gpointer)action, GINT_TO_POINTER (count));
420 activation_count (const gchar *action)
422 if (activation_counts == NULL)
425 return GPOINTER_TO_INT (g_hash_table_lookup (activation_counts, action));
429 activate_action (GSimpleAction *action, GVariant *parameter, gpointer user_data)
431 count_activation (g_action_get_name (G_ACTION (action)));
435 activate_toggle (GSimpleAction *action, GVariant *parameter, gpointer user_data)
437 GVariant *old_state, *new_state;
439 count_activation (g_action_get_name (G_ACTION (action)));
441 old_state = g_action_get_state (G_ACTION (action));
442 new_state = g_variant_new_boolean (!g_variant_get_boolean (old_state));
443 g_simple_action_set_state (action, new_state);
444 g_variant_unref (old_state);
448 activate_radio (GSimpleAction *action, GVariant *parameter, gpointer user_data)
452 count_activation (g_action_get_name (G_ACTION (action)));
454 new_state = g_variant_new_string (g_variant_get_string (parameter, NULL));
455 g_simple_action_set_state (action, new_state);
459 compare_action_groups (GActionGroup *a, GActionGroup *b)
466 gboolean aenabled, benabled;
467 const GVariantType *aparameter_type, *bparameter_type;
468 const GVariantType *astate_type, *bstate_type;
469 GVariant *astate_hint, *bstate_hint;
470 GVariant *astate, *bstate;
472 alist = g_action_group_list_actions (a);
473 blist = g_action_group_list_actions (b);
474 equal = strv_strv_cmp (alist, blist);
476 for (i = 0; equal && alist[i]; i++)
478 ares = g_action_group_query_action (a, alist[i], &aenabled, &aparameter_type, &astate_type, &astate_hint, &astate);
479 bres = g_action_group_query_action (b, alist[i], &benabled, &bparameter_type, &bstate_type, &bstate_hint, &bstate);
483 equal = equal && (aenabled == benabled);
484 equal = equal && ((!aparameter_type && !bparameter_type) || g_variant_type_equal (aparameter_type, bparameter_type));
485 equal = equal && ((!astate_type && !bstate_type) || g_variant_type_equal (astate_type, bstate_type));
486 equal = equal && ((!astate_hint && !bstate_hint) || g_variant_equal (astate_hint, bstate_hint));
487 equal = equal && ((!astate && !bstate) || g_variant_equal (astate, bstate));
490 g_variant_unref (astate_hint);
492 g_variant_unref (bstate_hint);
494 g_variant_unref (astate);
496 g_variant_unref (bstate);
509 stop_loop (gpointer data)
511 GMainLoop *loop = data;
513 g_main_loop_quit (loop);
515 return G_SOURCE_REMOVE;
519 test_dbus_export (void)
521 GDBusConnection *bus;
522 GSimpleActionGroup *group;
523 GDBusActionGroup *proxy;
524 GSimpleAction *action;
526 static GActionEntry entries[] = {
527 { "undo", activate_action, NULL, NULL, NULL },
528 { "redo", activate_action, NULL, NULL, NULL },
529 { "cut", activate_action, NULL, NULL, NULL },
530 { "copy", activate_action, NULL, NULL, NULL },
531 { "paste", activate_action, NULL, NULL, NULL },
532 { "bold", activate_toggle, NULL, "true", NULL },
533 { "lang", activate_radio, "s", "'latin'", NULL },
535 GError *error = NULL;
539 loop = g_main_loop_new (NULL, FALSE);
542 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
544 group = g_simple_action_group_new ();
545 g_simple_action_group_add_entries (group, entries, G_N_ELEMENTS (entries), NULL);
547 id = g_dbus_connection_export_action_group (bus, "/", G_ACTION_GROUP (group), &error);
548 g_assert_no_error (error);
550 proxy = g_dbus_action_group_get (bus, g_dbus_connection_get_unique_name (bus), "/");
551 g_strfreev (g_action_group_list_actions (G_ACTION_GROUP (proxy)));
553 g_timeout_add (100, stop_loop, loop);
554 g_main_loop_run (loop);
556 /* test that the initial transfer works */
557 g_assert (G_IS_DBUS_ACTION_GROUP (proxy));
558 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
560 /* test that various changes get propagated from group to proxy */
561 action = g_simple_action_new_stateful ("italic", NULL, g_variant_new_boolean (FALSE));
562 g_simple_action_group_insert (group, G_ACTION (action));
563 g_object_unref (action);
565 g_timeout_add (100, stop_loop, loop);
566 g_main_loop_run (loop);
568 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
570 action = G_SIMPLE_ACTION (g_simple_action_group_lookup (group, "cut"));
571 g_simple_action_set_enabled (action, FALSE);
573 g_timeout_add (100, stop_loop, loop);
574 g_main_loop_run (loop);
576 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
578 action = G_SIMPLE_ACTION (g_simple_action_group_lookup (group, "bold"));
579 g_simple_action_set_state (action, g_variant_new_boolean (FALSE));
581 g_timeout_add (100, stop_loop, loop);
582 g_main_loop_run (loop);
584 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
586 g_simple_action_group_remove (group, "italic");
588 g_timeout_add (100, stop_loop, loop);
589 g_main_loop_run (loop);
591 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
593 /* test that activations and state changes propagate the other way */
595 g_assert_cmpint (activation_count ("copy"), ==, 0);
596 g_action_group_activate_action (G_ACTION_GROUP (proxy), "copy", NULL);
598 g_timeout_add (100, stop_loop, loop);
599 g_main_loop_run (loop);
601 g_assert_cmpint (activation_count ("copy"), ==, 1);
602 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
604 g_assert_cmpint (activation_count ("bold"), ==, 0);
605 g_action_group_activate_action (G_ACTION_GROUP (proxy), "bold", NULL);
607 g_timeout_add (100, stop_loop, loop);
608 g_main_loop_run (loop);
610 g_assert_cmpint (activation_count ("bold"), ==, 1);
611 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
612 v = g_action_group_get_action_state (G_ACTION_GROUP (group), "bold");
613 g_assert (g_variant_get_boolean (v));
616 g_action_group_change_action_state (G_ACTION_GROUP (proxy), "bold", g_variant_new_boolean (FALSE));
618 g_timeout_add (100, stop_loop, loop);
619 g_main_loop_run (loop);
621 g_assert_cmpint (activation_count ("bold"), ==, 1);
622 g_assert (compare_action_groups (G_ACTION_GROUP (group), G_ACTION_GROUP (proxy)));
623 v = g_action_group_get_action_state (G_ACTION_GROUP (group), "bold");
624 g_assert (!g_variant_get_boolean (v));
627 g_dbus_connection_unexport_action_group (bus, id);
629 g_object_unref (proxy);
630 g_object_unref (group);
631 g_main_loop_unref (loop);
632 g_object_unref (bus);
638 do_export (gpointer data)
640 GActionGroup *group = data;
643 GError *error = NULL;
645 GDBusConnection *bus;
649 ctx = g_main_context_new ();
651 g_main_context_push_thread_default (ctx);
653 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
654 path = g_strdup_printf("/%p", data);
656 for (i = 0; i < 100000; i++)
658 id = g_dbus_connection_export_action_group (bus, path, G_ACTION_GROUP (group), &error);
659 g_assert_no_error (error);
661 action = g_simple_action_group_lookup (G_SIMPLE_ACTION_GROUP (group), "a");
662 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
663 !g_action_get_enabled (action));
665 g_dbus_connection_unexport_action_group (bus, id);
667 while (g_main_context_iteration (ctx, FALSE));
671 g_object_unref (bus);
673 g_main_context_pop_thread_default (ctx);
675 g_main_context_unref (ctx);
681 test_dbus_threaded (void)
683 GSimpleActionGroup *group[10];
685 static GActionEntry entries[] = {
686 { "a", activate_action, NULL, NULL, NULL },
687 { "b", activate_action, NULL, NULL, NULL },
693 for (i = 0; i < 10; i++)
695 group[i] = g_simple_action_group_new ();
696 g_simple_action_group_add_entries (group[i], entries, G_N_ELEMENTS (entries), NULL);
697 export[i] = g_thread_new ("export", do_export, group[i]);
700 for (i = 0; i < 10; i++)
701 g_thread_join (export[i]);
703 for (i = 0; i < 10; i++)
704 g_object_unref (group[i]);
710 main (int argc, char **argv)
713 g_test_init (&argc, &argv, NULL);
715 g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
717 g_test_add_func ("/actions/basic", test_basic);
718 g_test_add_func ("/actions/simplegroup", test_simple_group);
719 g_test_add_func ("/actions/stateful", test_stateful);
720 g_test_add_func ("/actions/entries", test_entries);
721 g_test_add_func ("/actions/dbus/export", test_dbus_export);
722 g_test_add_func ("/actions/dbus/threaded", test_dbus_threaded);
724 return g_test_run ();