diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/Makefile.am | 7 | ||||
-rwxr-xr-x | tools/dbusmenu-bench | 2 | ||||
-rw-r--r-- | tools/dbusmenu-dumper.c | 251 | ||||
-rw-r--r-- | tools/testapp/Makefile.am | 8 | ||||
-rw-r--r-- | tools/testapp/main.c | 49 |
5 files changed, 275 insertions, 42 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am index 77d6eef..48993f1 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -10,11 +10,14 @@ dbusmenu_dumper_SOURCES = \ dbusmenu_dumper_CFLAGS = \ -I $(srcdir)/.. \ - $(DBUSMENUGLIB_CFLAGS) -Wall -Werror + $(DBUSMENUGLIB_CFLAGS) \ + $(DBUSMENUDUMPER_CFLAGS) \ + -Wall -Werror dbusmenu_dumper_LDADD = \ ../libdbusmenu-glib/libdbusmenu-glib.la \ - $(DBUSMENUGLIB_LIBS) + $(DBUSMENUGLIB_LIBS) \ + $(DBUSMENUDUMPER_LIBS) doc_DATA = README.dbusmenu-bench diff --git a/tools/dbusmenu-bench b/tools/dbusmenu-bench index 4b58da8..dcf5f6f 100755 --- a/tools/dbusmenu-bench +++ b/tools/dbusmenu-bench @@ -35,7 +35,7 @@ from xml.etree import ElementTree as ET import dbus -DBUS_INTERFACE = "org.ayatana.dbusmenu" +DBUS_INTERFACE = "com.canonical.dbusmenu" DBUS_SERVICE = "org.dbusmenu.test" DBUS_PATH = "/MenuBar" diff --git a/tools/dbusmenu-dumper.c b/tools/dbusmenu-dumper.c index 55d631e..2db437d 100644 --- a/tools/dbusmenu-dumper.c +++ b/tools/dbusmenu-dumper.c @@ -22,25 +22,38 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <glib.h> +#include <gdk/gdk.h> +#include <gdk/gdkx.h> +#include <gtk/gtk.h> + #include <libdbusmenu-glib/client.h> #include <libdbusmenu-glib/menuitem.h> +#include <X11/Xlib.h> + static GMainLoop * mainloop = NULL; +static gint +list_str_cmp (gconstpointer a, gconstpointer b) +{ + return g_strcmp0((gchar *)a, (gchar *)b); +} + static void print_menuitem (DbusmenuMenuitem * item, int depth) { gchar * space = g_strnfill(depth, ' '); g_print("%s\"id\": %d", space, dbusmenu_menuitem_get_id(item)); - GList * properties = dbusmenu_menuitem_properties_list(item); + GList * properties_raw = dbusmenu_menuitem_properties_list(item); + GList * properties = g_list_sort(properties_raw, list_str_cmp); GList * property; for (property = properties; property != NULL; property = g_list_next(property)) { - GValue value = {0}; - g_value_init(&value, G_TYPE_STRING); - g_value_transform(dbusmenu_menuitem_property_get_value(item, (gchar *)property->data), &value); - g_print(",\n%s\"%s\": \"%s\"", space, (gchar *)property->data, g_value_get_string(&value)); - g_value_unset(&value); + GVariant * variant = dbusmenu_menuitem_property_get_variant(item, (gchar *)property->data); + gchar * str = g_variant_print(variant, FALSE); + g_print(",\n%s\"%s\": %s", space, (gchar *)property->data, str); + g_free(str); + g_variant_unref(variant); } g_list_free(properties); @@ -90,11 +103,200 @@ new_root_cb (DbusmenuClient * client, DbusmenuMenuitem * newroot) return; } +/* Window clicking ***************************************************/ +static GdkFilterReturn +click_filter (GdkXEvent *gdk_xevent, + GdkEvent *event, + gpointer data); + +static Window +find_real_window (Window w, int depth) +{ + if (depth > 5) { + return None; + } + /*static*/ Atom wm_state = XInternAtom(gdk_display, "WM_STATE", False); + Atom type; + int format; + unsigned long nitems, after; + unsigned char* prop; + if (XGetWindowProperty(gdk_display, w, wm_state, 0, 0, False, AnyPropertyType, + &type, &format, &nitems, &after, &prop) == Success) { + if (prop != NULL) { + XFree(prop); + } + if (type != None) { + return w; + } + } + Window root, parent; + Window* children; + unsigned int nchildren; + Window ret = None; + if (XQueryTree(gdk_display, w, &root, &parent, &children, &nchildren) != 0) { + unsigned int i; + for(i = 0; i < nchildren && ret == None; ++i) { + ret = find_real_window(children[ i ], depth + 1); + } + if (children != NULL) { + XFree(children); + } + } + return ret; +} + +static Window +get_window_under_cursor (void) +{ + Window root; + Window child; + uint mask; + int rootX, rootY, winX, winY; + XQueryPointer(gdk_display, gdk_x11_get_default_root_xwindow(), &root, &child, &rootX, &rootY, &winX, &winY, &mask); + if (child == None) { + return None; + } + return find_real_window(child, 0); +} + +static void +uninstall_click_filter (void) +{ + GdkWindow *root; + + root = gdk_get_default_root_window (); + gdk_window_remove_filter (root, (GdkFilterFunc) click_filter, NULL); + + gdk_pointer_ungrab (GDK_CURRENT_TIME); + gdk_keyboard_ungrab (GDK_CURRENT_TIME); + + gtk_main_quit (); +} + +static GdkFilterReturn +click_filter (GdkXEvent *gdk_xevent, + GdkEvent *event, + gpointer data) + +{ + XEvent *xevent = (XEvent *) gdk_xevent; + gboolean *success = (gboolean *)data; + + switch (xevent->type) { + case ButtonPress: + uninstall_click_filter(); + *success = TRUE; + return GDK_FILTER_REMOVE; + case KeyPress: + if (xevent->xkey.keycode == XKeysymToKeycode(gdk_display, XK_Escape)) { + uninstall_click_filter(); + *success = FALSE; + return GDK_FILTER_REMOVE; + } + break; + default: + break; + } + + return GDK_FILTER_CONTINUE; +} + +static gboolean +install_click_filter (gpointer data) +{ + GdkGrabStatus status; + GdkCursor *cross; + GdkWindow *root; + + root = gdk_get_default_root_window(); + + gdk_window_add_filter(root, (GdkFilterFunc) click_filter, data); + + cross = gdk_cursor_new(GDK_CROSS); + status = gdk_pointer_grab(root, FALSE, GDK_BUTTON_PRESS_MASK, + NULL, cross, GDK_CURRENT_TIME); + gdk_cursor_unref(cross); + + if (status != GDK_GRAB_SUCCESS) { + g_warning("Pointer grab failed.\n"); + uninstall_click_filter(); + return FALSE; + } + + status = gdk_keyboard_grab(root, FALSE, GDK_CURRENT_TIME); + if (status != GDK_GRAB_SUCCESS) { + g_warning("Keyboard grab failed.\n"); + uninstall_click_filter(); + return FALSE; + } + + gdk_flush(); + return FALSE; +} + +static gboolean +wait_for_click (void) +{ + gboolean success; + g_idle_add (install_click_filter, (gpointer)(&success)); + gtk_main (); + return success; +} static gchar * dbusname = NULL; static gchar * dbusobject = NULL; static gboolean +init_dbus_vars_from_window(Window window) +{ + GError *error; + GDBusProxy *proxy; + + error = NULL; + + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "com.canonical.AppMenu.Registrar", + "/com/canonical/AppMenu/Registrar", + "com.canonical.AppMenu.Registrar", + NULL, + &error); + if (error != NULL) { + g_warning("Unable to get registrar proxy: %s", error->message); + g_error_free(error); + return FALSE; + } + + error = NULL; + GVariant * retval; + GVariant * args[1]; + args[0] = g_variant_new("u", window); + + retval = g_dbus_proxy_call_sync(proxy, + "GetMenuForWindow", + g_variant_new_tuple(args, 1), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + + if (error != NULL) { + g_warning("Unable to call 'GetMenuForWindow' on registrar: %s", error->message); + g_error_free(error); + return FALSE; + } + + g_variant_get(retval, "(so)", &dbusname, &dbusobject); + + g_variant_unref(retval); + g_object_unref(proxy); + + return TRUE; +} + +/* Option parser *****************************************************/ +static gboolean option_dbusname (const gchar * arg, const gchar * value, gpointer data, GError ** error) { if (dbusname != NULL) { @@ -127,7 +329,8 @@ usage (void) static GOptionEntry general_options[] = { {"dbus-name", 'd', 0, G_OPTION_ARG_CALLBACK, option_dbusname, "The name of the program to connect to (i.e. org.test.bob", "dbusname"}, - {"dbus-object", 'o', 0, G_OPTION_ARG_CALLBACK, option_dbusobject, "The path to the Dbus object (i.e /org/test/bob/alvin)", "dbusobject"} + {"dbus-object", 'o', 0, G_OPTION_ARG_CALLBACK, option_dbusobject, "The path to the Dbus object (i.e /org/test/bob/alvin)", "dbusobject"}, + {NULL} }; int @@ -147,16 +350,32 @@ main (int argc, char ** argv) return 1; } - if (dbusname == NULL) { - g_printerr("ERROR: dbus-name not specified\n"); - usage(); - return 1; - } + if (dbusname == NULL && dbusobject == NULL) { + gtk_init(&argc, &argv); + if (!wait_for_click()) { + return 1; + } + Window window = get_window_under_cursor(); + if (window == None) { + g_printerr("ERROR: could not get the id for the pointed window\n"); + return 1; + } + if (!init_dbus_vars_from_window(window)) { + g_printerr("ERROR: could not find a menu for the pointed window\n"); + return 1; + } + } else { + if (dbusname == NULL) { + g_printerr("ERROR: dbus-name not specified\n"); + usage(); + return 1; + } - if (dbusobject == NULL) { - g_printerr("ERROR: dbus-object not specified\n"); - usage(); - return 1; + if (dbusobject == NULL) { + g_printerr("ERROR: dbus-object not specified\n"); + usage(); + return 1; + } } DbusmenuClient * client = dbusmenu_client_new (dbusname, dbusobject); diff --git a/tools/testapp/Makefile.am b/tools/testapp/Makefile.am index a8b42dd..39de532 100644 --- a/tools/testapp/Makefile.am +++ b/tools/testapp/Makefile.am @@ -1,4 +1,10 @@ +if USE_GTK3 +VER=3 +else +VER= +endif + libexec_PROGRAMS = dbusmenu-testapp dbusmenu_testapp_SOURCES = \ @@ -12,6 +18,6 @@ dbusmenu_testapp_CFLAGS = \ dbusmenu_testapp_LDADD = \ $(builddir)/../../libdbusmenu-glib/libdbusmenu-glib.la \ - $(builddir)/../../libdbusmenu-gtk/libdbusmenu-gtk.la \ + $(builddir)/../../libdbusmenu-gtk/libdbusmenu-gtk$(VER).la \ $(DBUSMENUGTK_LIBS) \ $(DBUSMENUTESTS_LIBS) diff --git a/tools/testapp/main.c b/tools/testapp/main.c index f489407..67e962d 100644 --- a/tools/testapp/main.c +++ b/tools/testapp/main.c @@ -26,9 +26,7 @@ License version 3 and version 2.1 along with this program. If not, see <http://www.gnu.org/licenses/> */ #include <glib.h> - -#include <dbus/dbus-glib.h> -#include <dbus/dbus-glib-bindings.h> +#include <gio/gio.h> #include <json-glib/json-glib.h> @@ -117,6 +115,24 @@ void init_menu(DbusmenuMenuitem *root, const char *filename) } } +static void +on_bus (GDBusConnection * connection, const gchar * name, gpointer user_data) +{ + DbusmenuServer *server = dbusmenu_server_new("/MenuBar"); + DbusmenuMenuitem *root = dbusmenu_menuitem_new_with_id(0); + init_menu(root, (gchar *)user_data); + dbusmenu_server_set_root(server, root); + + return; +} + +static void +name_lost (GDBusConnection * connection, const gchar * name, gpointer user_data) +{ + g_error("Unable to get name '%s' on DBus", name); + return; +} + int main (int argc, char ** argv) { g_type_init(); @@ -127,25 +143,14 @@ int main (int argc, char ** argv) } const char *filename = argv[1]; - GError * error = NULL; - DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL); - DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); - guint nameret = 0; - - if (!org_freedesktop_DBus_request_name(bus_proxy, "org.dbusmenu.test", 0, &nameret, &error)) { - g_error("Unable to call to request name"); - return 1; - } - - if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { - g_error("Unable to get name"); - return 1; - } - - DbusmenuServer *server = dbusmenu_server_new("/MenuBar"); - DbusmenuMenuitem *root = dbusmenu_menuitem_new_with_id(0); - init_menu(root, filename); - dbusmenu_server_set_root(server, root); + g_bus_own_name(G_BUS_TYPE_SESSION, + "org.dbusmenu.test", + G_BUS_NAME_OWNER_FLAGS_NONE, + on_bus, + NULL, + name_lost, + (gpointer)filename, + NULL); g_main_loop_run(g_main_loop_new(NULL, FALSE)); |