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