1 /*
2 Confirm that no warnings/criticals get generated by including
3 multiple add/removes in a match w/o waiting on the mainloop to iterate.
4
5 Copyright 2013 Canonical Ltd.
6
7 Original sample code by Drew Bliss <drewb@valvesoftware.com>
8 Modified for automatic testing by Charles Kerr <charles.kerr@canonical.com>
9 */
10
11 #include <stdlib.h> /* exit() */
12 #include <gtk/gtk.h>
13 #include <libdbusmenu-glib/server.h>
14 #include <libdbusmenu-gtk/menu.h>
15 #include <libdbusmenu-gtk/parser.h>
16
17 static GMainLoop * loop = NULL;
18 static GtkWidget * top_gtk = NULL;
19 static DbusmenuMenuitem * top_dbusmenu = NULL;
20 static DbusmenuServer * menuservice = NULL;
21
22 static void
rebuild_menu(void)23 rebuild_menu (void)
24 {
25 GList * l;
26 GList * children;
27 int i;
28 const int n = 10;
29 static int count = 0;
30
31 if (top_gtk == NULL)
32 {
33 top_gtk = gtk_menu_new ();
34 gtk_widget_show (top_gtk);
35 top_dbusmenu = dbusmenu_gtk_parse_menu_structure (top_gtk);
36 menuservice = dbusmenu_server_new ("/org/ayatana/NotificationItem/test/Menu");
37 dbusmenu_server_set_root (menuservice, top_dbusmenu);
38 }
39
40 // remove all the previous children
41 children = gtk_container_get_children (GTK_CONTAINER(top_gtk));
42 for (l=children; l!=NULL; l=l->next)
43 gtk_widget_destroy (GTK_WIDGET (l->data));
44
45 // add a handful of new children
46 for (i=0; i<n; ++i)
47 {
48 char buf[80];
49 GtkWidget * child;
50
51 g_snprintf (buf, sizeof(buf), "Test item %d", ++count);
52 child = gtk_menu_item_new_with_label (buf);
53 gtk_menu_shell_append (GTK_MENU_SHELL(top_gtk), child);
54 gtk_widget_show (child);
55 }
56 }
57
58 /*
59 * Periodically rebuild the menu.
60 *
61 * After we've looped a couple of times with only one rebuild,
62 * attempt to reproduce the bug Drew reported by rebuilding multiple
63 * times before returning control to the main loop.
64 *
65 * If we survive doing this a handful of times without encountering
66 * a g_warning or g_critical, pass the test.
67 */
68 static gint
on_timer(gpointer unused G_GNUC_UNUSED)69 on_timer (gpointer unused G_GNUC_UNUSED)
70 {
71 static int iteration = 0;
72
73 ++iteration;
74
75 if (iteration > 5)
76 {
77 g_main_loop_quit (loop);
78 return G_SOURCE_REMOVE;
79 }
80
81 if (iteration <= 2)
82 {
83 rebuild_menu ();
84 }
85 else
86 {
87 int i;
88
89 for (i=0; i<iteration; ++i)
90 rebuild_menu ();
91 }
92
93 return G_SOURCE_CONTINUE;
94 }
95
96 static void
warning_counter(const gchar * log_domain,GLogLevelFlags log_level G_GNUC_UNUSED,const gchar * message,gpointer user_data G_GNUC_UNUSED)97 warning_counter (const gchar * log_domain,
98 GLogLevelFlags log_level G_GNUC_UNUSED,
99 const gchar * message,
100 gpointer user_data G_GNUC_UNUSED)
101 {
102 g_message ("Failing the test due to warning: %s %s", log_domain, message);
103 exit (EXIT_FAILURE);
104 }
105
106 int
main(int argc,char ** argv)107 main (int argc, char ** argv)
108 {
109 g_log_set_handler ("LIBDBUSMENU-GLIB", G_LOG_LEVEL_WARNING|G_LOG_LEVEL_CRITICAL, warning_counter, NULL);
110
111
112 gtk_init (&argc, &argv);
113 loop = g_main_loop_new (NULL, FALSE);
114 g_timeout_add (200, on_timer, NULL);
115 g_main_loop_run (loop);
116
117 return 0;
118 }
119