diff options
-rw-r--r-- | configure.ac | 7 | ||||
-rw-r--r-- | libdbusmenu-glib/Makefile.am | 1 | ||||
-rw-r--r-- | libdbusmenu-glib/server.c | 62 | ||||
-rw-r--r-- | libdbusmenu-gtk/client.c | 14 | ||||
-rw-r--r-- | tests/Makefile.am | 21 | ||||
-rw-r--r-- | tests/json-loader.c | 24 | ||||
-rw-r--r-- | tests/test-json-client.c | 23 | ||||
-rwxr-xr-x | tests/test-json-instruction-count | 6 | ||||
-rw-r--r-- | tests/test-json-server.c | 18 | ||||
-rw-r--r-- | tools/dbusmenu-dumper.c | 54 |
10 files changed, 178 insertions, 52 deletions
diff --git a/configure.ac b/configure.ac index 42c5b3d..e397cb5 100644 --- a/configure.ac +++ b/configure.ac @@ -1,11 +1,11 @@ -AC_INIT(libdbusmenu, 0.5.95, ted@canonical.com) +AC_INIT(libdbusmenu, 0.5.96, ted@canonical.com) AC_COPYRIGHT([Copyright 2009,2010 Canonical]) AC_PREREQ(2.62) AM_CONFIG_HEADER(config.h) -AM_INIT_AUTOMAKE(libdbusmenu, 0.5.95, [-Wno-portability]) +AM_INIT_AUTOMAKE(libdbusmenu, 0.5.96, [-Wno-portability]) AM_MAINTAINER_MODE @@ -118,7 +118,8 @@ AM_CONDITIONAL([WANT_TESTS], [test "x$enable_tests" != "xno"]) AS_IF([test "x$enable_tests" != "xno"],[ PKG_CHECK_MODULES(DBUSMENUTESTS, json-glib-1.0 >= $JSON_GLIB_REQUIRED_VERSION - gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION, + gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION + valgrind, [have_tests=yes] ) ]) diff --git a/libdbusmenu-glib/Makefile.am b/libdbusmenu-glib/Makefile.am index 6fc3fb8..fa7c8cb 100644 --- a/libdbusmenu-glib/Makefile.am +++ b/libdbusmenu-glib/Makefile.am @@ -6,6 +6,7 @@ EXTRA_DIST = \ clean-namespaces.xslt \ dbusmenu-glib-0.4.pc.in \ dbus-menu.xml \ + dbus-menu-clean.xml \ client-marshal.list \ menuitem-marshal.list \ server-marshal.list diff --git a/libdbusmenu-glib/server.c b/libdbusmenu-glib/server.c index 0eff073..e67ec58 100644 --- a/libdbusmenu-glib/server.c +++ b/libdbusmenu-glib/server.c @@ -64,6 +64,8 @@ struct _DbusmenuServerPrivate GArray * prop_array; guint property_idle; + + GHashTable * lookup_cache; }; #define DBUSMENU_SERVER_GET_PRIVATE(o) (DBUSMENU_SERVER(o)->priv) @@ -392,6 +394,8 @@ dbusmenu_server_init (DbusmenuServer *self) priv->find_server_signal = 0; priv->dbus_registration = 0; + priv->lookup_cache = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref); + default_text_direction(self); priv->status = DBUSMENU_STATUS_NORMAL; priv->icon_dirs = NULL; @@ -464,10 +468,50 @@ dbusmenu_server_finalize (GObject *object) priv->icon_dirs = NULL; } + if (priv->lookup_cache) { + g_hash_table_destroy(priv->lookup_cache); + priv->lookup_cache = NULL; + } + G_OBJECT_CLASS (dbusmenu_server_parent_class)->finalize (object); return; } +static DbusmenuMenuitem * +lookup_menuitem_by_id (DbusmenuServer * server, gint id) +{ + DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server); + + DbusmenuMenuitem *res = (DbusmenuMenuitem *) g_hash_table_lookup(priv->lookup_cache, GINT_TO_POINTER(id)); + if (!res && id == 0) { + return priv->root; + } + + return res; +} + +static void +cache_remove_entries_for_menuitem (GHashTable * cache, DbusmenuMenuitem * item) +{ + g_hash_table_remove(cache, GINT_TO_POINTER(dbusmenu_menuitem_get_id(item))); + + GList *child, *children = dbusmenu_menuitem_get_children(item); + for (child = children; child != NULL; child = child->next) { + cache_remove_entries_for_menuitem(cache, child->data); + } +} + +static void +cache_add_entries_for_menuitem (GHashTable * cache, DbusmenuMenuitem * item) +{ + g_hash_table_insert(cache, GINT_TO_POINTER(dbusmenu_menuitem_get_id(item)), g_object_ref(item)); + + GList *child, *children = dbusmenu_menuitem_get_children(item); + for (child = children; child != NULL; child = child->next) { + cache_add_entries_for_menuitem(cache, child->data); + } +} + static void set_property (GObject * obj, guint id, const GValue * value, GParamSpec * pspec) { @@ -494,6 +538,7 @@ set_property (GObject * obj, guint id, const GValue * value, GParamSpec * pspec) if (priv->root != NULL) { dbusmenu_menuitem_foreach(priv->root, menuitem_signals_remove, obj); dbusmenu_menuitem_set_root(priv->root, FALSE); + cache_remove_entries_for_menuitem(priv->lookup_cache, priv->root); GList * properties = dbusmenu_menuitem_properties_list(priv->root); GList * iter; @@ -509,6 +554,7 @@ set_property (GObject * obj, guint id, const GValue * value, GParamSpec * pspec) priv->root = DBUSMENU_MENUITEM(g_value_get_object(value)); if (priv->root != NULL) { g_object_ref(G_OBJECT(priv->root)); + cache_add_entries_for_menuitem(priv->lookup_cache, priv->root); dbusmenu_menuitem_set_root(priv->root, TRUE); dbusmenu_menuitem_foreach(priv->root, menuitem_signals_create, obj); @@ -1175,6 +1221,7 @@ static void menuitem_child_added (DbusmenuMenuitem * parent, DbusmenuMenuitem * child, guint pos, DbusmenuServer * server) { menuitem_signals_create(child, server); + cache_add_entries_for_menuitem(server->priv->lookup_cache, child); g_list_foreach(dbusmenu_menuitem_get_children(child), added_check_children, server); layout_update_signal(server); @@ -1185,6 +1232,7 @@ static void menuitem_child_removed (DbusmenuMenuitem * parent, DbusmenuMenuitem * child, DbusmenuServer * server) { menuitem_signals_remove(child, server); + cache_remove_entries_for_menuitem(server->priv->lookup_cache, child); layout_update_signal(server); return; } @@ -1273,7 +1321,7 @@ bus_get_layout (DbusmenuServer * server, GVariant * params, GDBusMethodInvocatio GVariant * items = NULL; if (priv->root != NULL) { - DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, parent); + DbusmenuMenuitem * mi = lookup_menuitem_by_id(server, parent); if (mi != NULL) { items = dbusmenu_menuitem_build_variant(mi, props, recurse); @@ -1332,7 +1380,7 @@ bus_get_property (DbusmenuServer * server, GVariant * params, GDBusMethodInvocat g_variant_get(params, "(i&s)", &id, &property); - DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id); + DbusmenuMenuitem * mi = lookup_menuitem_by_id(server, id); if (mi == NULL) { g_dbus_method_invocation_return_error(invocation, @@ -1375,7 +1423,7 @@ bus_get_properties (DbusmenuServer * server, GVariant * params, GDBusMethodInvoc gint32 id; g_variant_get(params, "(i)", &id); - DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id); + DbusmenuMenuitem * mi = lookup_menuitem_by_id(server, id); if (mi == NULL) { g_dbus_method_invocation_return_error(invocation, @@ -1438,7 +1486,7 @@ bus_get_group_properties (DbusmenuServer * server, GVariant * params, GDBusMetho gint32 id; while (g_variant_iter_loop(ids, "i", &id)) { - DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id); + DbusmenuMenuitem * mi = lookup_menuitem_by_id(server, id); if (mi == NULL) continue; if (!builder_init) { @@ -1537,7 +1585,7 @@ bus_get_children (DbusmenuServer * server, GVariant * params, GDBusMethodInvocat return; } - DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id); + DbusmenuMenuitem * mi = lookup_menuitem_by_id(server, id); if (mi == NULL) { g_dbus_method_invocation_return_error(invocation, @@ -1620,7 +1668,7 @@ bus_event (DbusmenuServer * server, GVariant * params, GDBusMethodInvocation * i g_variant_get(params, "(isvu)", &id, &etype, &data, &ts); - DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id); + DbusmenuMenuitem * mi = lookup_menuitem_by_id(server, id); if (mi == NULL) { g_dbus_method_invocation_return_error(invocation, @@ -1673,7 +1721,7 @@ bus_about_to_show (DbusmenuServer * server, GVariant * params, GDBusMethodInvoca gint32 id; g_variant_get(params, "(i)", &id); - DbusmenuMenuitem * mi = dbusmenu_menuitem_find_id(priv->root, id); + DbusmenuMenuitem * mi = lookup_menuitem_by_id(server, id); if (mi == NULL) { g_dbus_method_invocation_return_error(invocation, diff --git a/libdbusmenu-gtk/client.c b/libdbusmenu-gtk/client.c index f507a56..60af93f 100644 --- a/libdbusmenu-gtk/client.c +++ b/libdbusmenu-gtk/client.c @@ -787,22 +787,13 @@ menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * variant, Db process_disposition(mi, gmi, variant, gtkclient); } else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_ACCESSIBLE_DESC)) { process_a11y_desc(mi, gmi, variant, gtkclient); + } else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_SHORTCUT)) { + refresh_shortcut(gtkclient, mi); } return; } -/* Special handler for the shortcut changing as we need to have the - client for that one to get the accel group. */ -static void -menu_shortcut_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * value, DbusmenuGtkClient * client) -{ - if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_SHORTCUT)) { - refresh_shortcut(client, mi); - } - return; -} - /* The new menuitem signal only happens if we don't have a type handler for the type of the item. This should be an error condition and we're printing out a message. */ @@ -918,7 +909,6 @@ dbusmenu_gtkclient_newitem_base (DbusmenuGtkClient * client, DbusmenuMenuitem * /* DbusmenuMenuitem signals */ g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(menu_prop_change_cb), client); - g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(menu_shortcut_change_cb), client); g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_CHILD_REMOVED, G_CALLBACK(delete_child), client); g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_CHILD_MOVED, G_CALLBACK(move_child), client); diff --git a/tests/Makefile.am b/tests/Makefile.am index 6824c1c..82f6a9d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -16,7 +16,8 @@ TESTS = \ if WANT_DBUSMENUDUMPER TESTS += \ - test-json + test-json \ + test-json-instruction endif if WANT_LIBDBUSMENUGTK @@ -208,7 +209,7 @@ test-json: test-json-client test-json-server Makefile.am @echo export UBUNTU_MENUPROXY="" >> $@ @echo export G_DEBUG=fatal_criticals >> $@ @echo $(XVFB_RUN) >> $@ - @echo $(DBUS_RUNNER) --task ./test-json-client --task-name Client --parameter $(top_builddir)/tools/dbusmenu-dumper --parameter test-json-01.output.json --ignore-return --task ./test-json-server --task-name Server --parameter $(srcdir)/test-json-01.json --ignore-return >> $@ + @echo $(DBUS_RUNNER) --task ./test-json-client --wait-for org.dbusmenu.test --task-name Client --parameter $(top_builddir)/tools/dbusmenu-dumper --parameter test-json-01.output.json --ignore-return --task ./test-json-server --task-name Server --parameter $(srcdir)/test-json-01.json --ignore-return >> $@ @echo diff $(srcdir)/test-json-01.json test-json-01.output.json \> /dev/null >> $@ @chmod +x $@ @@ -242,6 +243,22 @@ test_json_client_LDADD = \ $(DBUSMENUTESTS_LIBS) \ $(DBUSMENUGLIB_LIBS) +######################### +# Test JSON Instructions +######################### + +test-json-instruction: test-json-client test-json-server test-json-instruction-count Makefile.am + @echo "#!/bin/bash" > $@ + @echo export UBUNTU_MENUPROXY="" >> $@ + @echo export G_DEBUG=fatal_criticals >> $@ + @echo $(XVFB_RUN) >> $@ + @echo $(DBUS_RUNNER) --task $(builddir)/test-json-client --wait-for org.dbusmenu.test --task-name Client --parameter $(top_builddir)/tools/dbusmenu-dumper --parameter /dev/null --ignore-return --task libtool --parameter --mode=execute --parameter $(srcdir)/test-json-instruction-count --parameter $(builddir)/test-json-server --task-name Server --parameter $(srcdir)/test-json-01.json --ignore-return >> $@ + @chmod +x $@ + +EXTRA_DIST += \ + test-json-instruction-count + + ###################### # Test Glib Submenu ###################### diff --git a/tests/json-loader.c b/tests/json-loader.c index 7f0ec8e..94982c4 100644 --- a/tests/json-loader.c +++ b/tests/json-loader.c @@ -24,6 +24,18 @@ with this program. If not, see <http://www.gnu.org/licenses/>. static GVariant * node2variant (JsonNode * node, const gchar * name); static void +array_byte_foreach (JsonArray * array, guint index, JsonNode * node, gpointer user_data) +{ + g_return_if_fail(JSON_NODE_TYPE(node) == JSON_NODE_VALUE); + g_return_if_fail(json_node_get_value_type(node) == G_TYPE_INT || json_node_get_value_type(node) == G_TYPE_INT64); + + GVariantBuilder * builder = (GVariantBuilder *)user_data; + + g_variant_builder_add_value(builder, g_variant_new_byte(json_node_get_int(node))); + return; +} + +static void array_foreach (JsonArray * array, guint index, JsonNode * node, gpointer user_data) { GVariantBuilder * builder = (GVariantBuilder *)user_data; @@ -79,11 +91,17 @@ node2variant (JsonNode * node, const gchar * name) } if (JSON_NODE_TYPE(node) == JSON_NODE_ARRAY) { + JsonArray * array = json_node_get_array(node); GVariantBuilder builder; - g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY); - JsonArray * array = json_node_get_array(node); - json_array_foreach_element(array, array_foreach, &builder); + if (g_strcmp0(name, "icon-data") == 0) { + g_variant_builder_init(&builder, G_VARIANT_TYPE("ay")); + json_array_foreach_element(array, array_byte_foreach, &builder); + } else { + g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY); + json_array_foreach_element(array, array_foreach, &builder); + } + return g_variant_builder_end(&builder); } diff --git a/tests/test-json-client.c b/tests/test-json-client.c index d4e782b..8900902 100644 --- a/tests/test-json-client.c +++ b/tests/test-json-client.c @@ -27,14 +27,6 @@ GMainLoop * mainloop = NULL; gboolean timeout_func (gpointer user_data) { - g_warning("Timeout without getting name"); - g_main_loop_quit(mainloop); - return FALSE; -} - -void -name_appeared (GDBusConnection * connection, const gchar * name, const gchar * owner, gpointer user_data) -{ char ** argv = (char **)user_data; g_usleep(500000); @@ -52,25 +44,18 @@ name_appeared (GDBusConnection * connection, const gchar * name, const gchar * o g_file_replace_contents(ofile, output, g_utf8_strlen(output, -1), NULL, FALSE, 0, NULL, NULL, NULL); } + g_spawn_command_line_sync("gdbus call --session --dest org.dbusmenu.test --object-path /org/test --method com.canonical.dbusmenu.Event 0 clicked \"<0>\" 0", NULL, NULL, NULL, NULL); + g_main_loop_quit(mainloop); - return; + return TRUE; } int main (int argc, char ** argv) { g_type_init(); - g_debug("Wait for friends"); - - g_bus_watch_name(G_BUS_TYPE_SESSION, - "org.dbusmenu.test", - G_BUS_NAME_WATCHER_FLAGS_NONE, - name_appeared, - NULL, - argv, - NULL); - g_timeout_add_seconds(2, timeout_func, NULL); + g_timeout_add_seconds(1, timeout_func, argv); mainloop = g_main_loop_new(NULL, FALSE); g_main_loop_run(mainloop); diff --git a/tests/test-json-instruction-count b/tests/test-json-instruction-count new file mode 100755 index 0000000..3a4db97 --- /dev/null +++ b/tests/test-json-instruction-count @@ -0,0 +1,6 @@ +#!/bin/sh + +COMMAND=$@ +INSTRUCTIONS=`valgrind --tool=callgrind --callgrind-out-file=/dev/null --instr-atstart=no --collect-atstart=no --combine-dumps=yes $COMMAND 2>&1 > /dev/null | grep refs | grep I | tail --lines=1 | cut -d ":" -f 2 | sed -e 's/^[ \t]*//'` + +echo "Instructions needed to execute '$COMMAND': $INSTRUCTIONS" diff --git a/tests/test-json-server.c b/tests/test-json-server.c index 083de60..7165838 100644 --- a/tests/test-json-server.c +++ b/tests/test-json-server.c @@ -22,6 +22,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <glib.h> #include <gio/gio.h> +#include "callgrind.h" #include <libdbusmenu-glib/server.h> #include <libdbusmenu-glib/menuitem.h> @@ -29,11 +30,14 @@ with this program. If not, see <http://www.gnu.org/licenses/>. static GMainLoop * mainloop = NULL; -static gboolean -timer_func (gpointer data) +static void +root_activate (void) { + g_debug("Dumping callgrind data"); + CALLGRIND_DUMP_STATS_AT("exported"); + CALLGRIND_STOP_INSTRUMENTATION; g_main_loop_quit(mainloop); - return FALSE; + return; } static void @@ -50,9 +54,13 @@ on_bus (GDBusConnection * connection, const gchar * name, gpointer user_data) return; } - dbusmenu_server_set_root(server, root); + g_signal_connect(G_OBJECT(root), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(root_activate), NULL); - g_timeout_add(10000, timer_func, NULL); + g_debug("Starting Callgrind"); + CALLGRIND_START_INSTRUMENTATION; + CALLGRIND_ZERO_STATS; + CALLGRIND_TOGGLE_COLLECT; + dbusmenu_server_set_root(server, root); return; } diff --git a/tools/dbusmenu-dumper.c b/tools/dbusmenu-dumper.c index 2db437d..6dcdb2f 100644 --- a/tools/dbusmenu-dumper.c +++ b/tools/dbusmenu-dumper.c @@ -28,6 +28,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <libdbusmenu-glib/client.h> #include <libdbusmenu-glib/menuitem.h> +#include <libdbusmenu-glib/menuitem-private.h> #include <X11/Xlib.h> @@ -77,6 +78,7 @@ print_menuitem (DbusmenuMenuitem * item, int depth) return; } +/* Prints the final JSON file recursively */ static gboolean root_timeout (gpointer data) { @@ -90,6 +92,51 @@ root_timeout (gpointer data) return FALSE; } +/* Variables to deal with the number of items that we're watching to + realized */ +static int realized_count = 0; +static DbusmenuMenuitem * root = NULL; + +/* Decrements the realization count, and if it gets to the end prints + out everything. */ +static void +decrement_count (void) +{ + realized_count--; + + if (realized_count == 0) { + root_timeout(root); + } + + return; +} + +/* Checks whether we need to watch a menu item, and recurses down to + it's children as well */ +static void +check_realizations (DbusmenuMenuitem * item) +{ + g_return_if_fail(DBUSMENU_IS_MENUITEM(item)); + + if (!dbusmenu_menuitem_realized(item)) { + realized_count++; + + g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_REALIZED, G_CALLBACK(decrement_count), NULL); + } + + GList * children = dbusmenu_menuitem_get_children(item); + if (children != NULL) { + GList * child; + for (child = children; child != NULL; child = g_list_next(child)) { + check_realizations(DBUSMENU_MENUITEM(child->data)); + } + } + + return; +} + +/* A setup for when we get our first root. We set up the basic realization + counter and set it to run. We'll print when it counts down */ static void new_root_cb (DbusmenuClient * client, DbusmenuMenuitem * newroot) { @@ -99,7 +146,12 @@ new_root_cb (DbusmenuClient * client, DbusmenuMenuitem * newroot) return; } - g_timeout_add_seconds(2, root_timeout, newroot); + root = newroot; + check_realizations(root); + + realized_count++; + decrement_count(); + return; } |