From 9f4213d9d59c84c9c4811a69ee50d4baaab6dc58 Mon Sep 17 00:00:00 2001 From: Aurelien Gateau Date: Mon, 19 Jul 2010 12:53:38 +0200 Subject: Started to implement click-to-dump --- tools/Makefile.am | 4 +- tools/dbusmenu-dumper.c | 129 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 122 insertions(+), 11 deletions(-) (limited to 'tools') diff --git a/tools/Makefile.am b/tools/Makefile.am index 77d6eef..a36d224 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -10,11 +10,11 @@ dbusmenu_dumper_SOURCES = \ dbusmenu_dumper_CFLAGS = \ -I $(srcdir)/.. \ - $(DBUSMENUGLIB_CFLAGS) -Wall -Werror + $(DBUSMENUGLIB_CFLAGS) -I/usr/include/dbus-1.0 -Wall -Werror dbusmenu_dumper_LDADD = \ ../libdbusmenu-glib/libdbusmenu-glib.la \ - $(DBUSMENUGLIB_LIBS) + $(DBUSMENUGLIB_LIBS) -lX11 -ldbus-glib-1 doc_DATA = README.dbusmenu-bench diff --git a/tools/dbusmenu-dumper.c b/tools/dbusmenu-dumper.c index 55d631e..4a0dd03 100644 --- a/tools/dbusmenu-dumper.c +++ b/tools/dbusmenu-dumper.c @@ -21,10 +21,13 @@ with this program. If not, see . */ #include +#include #include #include +#include + static GMainLoop * mainloop = NULL; static void @@ -90,10 +93,104 @@ new_root_cb (DbusmenuClient * client, DbusmenuMenuitem * newroot) return; } +static Window +find_real_window(Display * display, Window w, int depth) +{ + if (depth > 5) { + return None; + } + /*static*/ Atom wm_state = XInternAtom(display, "WM_STATE", False); + Atom type; + int format; + unsigned long nitems, after; + unsigned char* prop; + if (XGetWindowProperty(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(display, w, &root, &parent, &children, &nchildren) != 0) { + unsigned int i; + for(i = 0; i < nchildren && ret == None; ++i) { + ret = find_real_window(display, children[ i ], depth + 1); + } + if (children != NULL) { + XFree(children); + } + } + return ret; +} + +static Window +get_window_under_cursor() +{ + Display * display = XOpenDisplay(NULL); + g_return_val_if_fail(display != NULL, None); + + Window root; + Window child; + uint mask; + int rootX, rootY, winX, winY; + XGrabServer(display); + Window root_window = DefaultRootWindow(display); + XQueryPointer(display, root_window, &root, &child, &rootX, &rootY, &winX, &winY, &mask); + if (child == None) { + return None; + } + return find_real_window(display, child, 0); +} static gchar * dbusname = NULL; static gchar * dbusobject = NULL; +static gboolean +init_dbus_vars_from_window(Window window) +{ + DBusGConnection *connection; + GError *error; + DBusGProxy *proxy; + + error = NULL; + connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error); + if (connection == NULL) { + g_printerr("Failed to open connection to bus: %s\n", error->message); + g_error_free(error); + return FALSE; + } + + proxy = dbus_g_proxy_new_for_name (connection, + "org.ayatana.AppMenu.Registrar", + "/org/ayatana/AppMenu/Registrar", + "org.ayatana.AppMenu.Registrar"); + + error = NULL; + if (!dbus_g_proxy_call (proxy, "GetMenuForWindow", &error, + G_TYPE_UINT, window, G_TYPE_INVALID, + G_TYPE_STRING, &dbusname, DBUS_TYPE_G_OBJECT_PATH, &dbusobject, G_TYPE_INVALID)) + { + g_printerr("ERROR: %s\n", error->message); + g_error_free(error); + g_object_unref(proxy); + return FALSE; + } + + if (!g_strcmp0(dbusobject, "/")) { + return FALSE; + } + + g_object_unref (proxy); + + return TRUE; +} + static gboolean option_dbusname (const gchar * arg, const gchar * value, gpointer data, GError ** error) { @@ -147,16 +244,30 @@ 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) { + Window window = get_window_under_cursor(); + if (window == None) { + g_printerr("ERROR: could not get the id for the pointed window\n"); + return 1; + } + g_debug("window: %u", (unsigned int)window); + if (!init_dbus_vars_from_window(window)) { + g_printerr("ERROR: could not find a menu for the pointed window\n"); + return 1; + } + g_debug("dbusname: %s, dbusobject: %s", dbusname, dbusobject); + } 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); -- cgit v1.2.3 From 6da7a3341f028d913fd3ad01d47a59f436b5e780 Mon Sep 17 00:00:00 2001 From: Aurelien Gateau Date: Mon, 19 Jul 2010 17:21:38 +0200 Subject: Use pkgconfig to find libx11 --- tools/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/Makefile.am b/tools/Makefile.am index a36d224..3cd5538 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -10,11 +10,11 @@ dbusmenu_dumper_SOURCES = \ dbusmenu_dumper_CFLAGS = \ -I $(srcdir)/.. \ - $(DBUSMENUGLIB_CFLAGS) -I/usr/include/dbus-1.0 -Wall -Werror + $(DBUSMENUGLIB_CFLAGS) $(DBUSMENUTOOLS_CFLAGS) -Wall -Werror dbusmenu_dumper_LDADD = \ ../libdbusmenu-glib/libdbusmenu-glib.la \ - $(DBUSMENUGLIB_LIBS) -lX11 -ldbus-glib-1 + $(DBUSMENUGLIB_LIBS) $(DBUSMENUTOOLS_LIBS) doc_DATA = README.dbusmenu-bench -- cgit v1.2.3 From 646c74694e86d6e5d479028a7dbd8cf9a1aca37a Mon Sep 17 00:00:00 2001 From: Aurelien Gateau Date: Tue, 20 Jul 2010 14:51:23 +0200 Subject: Ripped some code from wnckprop to do proper click-to-dump --- tools/Makefile.am | 4 +- tools/dbusmenu-dumper.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/Makefile.am b/tools/Makefile.am index 3cd5538..ab7a598 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -10,11 +10,11 @@ dbusmenu_dumper_SOURCES = \ dbusmenu_dumper_CFLAGS = \ -I $(srcdir)/.. \ - $(DBUSMENUGLIB_CFLAGS) $(DBUSMENUTOOLS_CFLAGS) -Wall -Werror + $(DBUSMENUGLIB_CFLAGS) $(DBUSMENUDUMPER_CFLAGS) -Wall -Werror dbusmenu_dumper_LDADD = \ ../libdbusmenu-glib/libdbusmenu-glib.la \ - $(DBUSMENUGLIB_LIBS) $(DBUSMENUTOOLS_LIBS) + $(DBUSMENUGLIB_LIBS) $(DBUSMENUDUMPER_LIBS) doc_DATA = README.dbusmenu-bench diff --git a/tools/dbusmenu-dumper.c b/tools/dbusmenu-dumper.c index 4a0dd03..3a47f21 100644 --- a/tools/dbusmenu-dumper.c +++ b/tools/dbusmenu-dumper.c @@ -23,6 +23,10 @@ with this program. If not, see . #include #include +#include +#include +#include + #include #include @@ -93,6 +97,12 @@ 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(Display * display, Window w, int depth) { @@ -148,6 +158,91 @@ get_window_under_cursor() return find_real_window(display, 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 (int argc, char **argv) +{ + gtk_init(&argc, &argv); + gboolean success; + g_idle_add (install_click_filter, (gpointer)(&success)); + gtk_main (); + return success; +} + static gchar * dbusname = NULL; static gchar * dbusobject = NULL; @@ -191,6 +286,7 @@ init_dbus_vars_from_window(Window window) return TRUE; } +/* Option parser *****************************************************/ static gboolean option_dbusname (const gchar * arg, const gchar * value, gpointer data, GError ** error) { @@ -245,6 +341,9 @@ main (int argc, char ** argv) } if (dbusname == NULL && dbusobject == NULL) { + if (!wait_for_click(argc, argv)) { + return 1; + } Window window = get_window_under_cursor(); if (window == None) { g_printerr("ERROR: could not get the id for the pointed window\n"); @@ -256,6 +355,7 @@ main (int argc, char ** argv) return 1; } g_debug("dbusname: %s, dbusobject: %s", dbusname, dbusobject); + return 1; } else { if (dbusname == NULL) { g_printerr("ERROR: dbus-name not specified\n"); -- cgit v1.2.3 From 463b05a77a8e21e60ffe197f58461b0fb02ed930 Mon Sep 17 00:00:00 2001 From: Aurelien Gateau Date: Tue, 20 Jul 2010 14:58:16 +0200 Subject: Clean up --- tools/dbusmenu-dumper.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) (limited to 'tools') diff --git a/tools/dbusmenu-dumper.c b/tools/dbusmenu-dumper.c index 3a47f21..4ddb057 100644 --- a/tools/dbusmenu-dumper.c +++ b/tools/dbusmenu-dumper.c @@ -104,17 +104,17 @@ click_filter (GdkXEvent *gdk_xevent, gpointer data); static Window -find_real_window(Display * display, Window w, int depth) +find_real_window (Window w, int depth) { if (depth > 5) { return None; } - /*static*/ Atom wm_state = XInternAtom(display, "WM_STATE", False); + /*static*/ Atom wm_state = XInternAtom(gdk_display, "WM_STATE", False); Atom type; int format; unsigned long nitems, after; unsigned char* prop; - if (XGetWindowProperty(display, w, wm_state, 0, 0, False, AnyPropertyType, + if (XGetWindowProperty(gdk_display, w, wm_state, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &after, &prop) == Success) { if (prop != NULL) { XFree(prop); @@ -127,10 +127,10 @@ find_real_window(Display * display, Window w, int depth) Window* children; unsigned int nchildren; Window ret = None; - if (XQueryTree(display, w, &root, &parent, &children, &nchildren) != 0) { + 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(display, children[ i ], depth + 1); + ret = find_real_window(children[ i ], depth + 1); } if (children != NULL) { XFree(children); @@ -140,22 +140,17 @@ find_real_window(Display * display, Window w, int depth) } static Window -get_window_under_cursor() +get_window_under_cursor (void) { - Display * display = XOpenDisplay(NULL); - g_return_val_if_fail(display != NULL, None); - Window root; Window child; uint mask; int rootX, rootY, winX, winY; - XGrabServer(display); - Window root_window = DefaultRootWindow(display); - XQueryPointer(display, root_window, &root, &child, &rootX, &rootY, &winX, &winY, &mask); + 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(display, child, 0); + return find_real_window(child, 0); } static void @@ -234,9 +229,8 @@ install_click_filter (gpointer data) } static gboolean -wait_for_click (int argc, char **argv) +wait_for_click (void) { - gtk_init(&argc, &argv); gboolean success; g_idle_add (install_click_filter, (gpointer)(&success)); gtk_main (); @@ -341,7 +335,8 @@ main (int argc, char ** argv) } if (dbusname == NULL && dbusobject == NULL) { - if (!wait_for_click(argc, argv)) { + gtk_init(&argc, &argv); + if (!wait_for_click()) { return 1; } Window window = get_window_under_cursor(); -- cgit v1.2.3 From 70961ba202ced579d434e19f185f442684814722 Mon Sep 17 00:00:00 2001 From: Aurelien Gateau Date: Tue, 20 Jul 2010 15:03:39 +0200 Subject: Unbreak command line parser --- tools/dbusmenu-dumper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/dbusmenu-dumper.c b/tools/dbusmenu-dumper.c index 4ddb057..82ca5c1 100644 --- a/tools/dbusmenu-dumper.c +++ b/tools/dbusmenu-dumper.c @@ -314,7 +314,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 @@ -350,7 +351,6 @@ main (int argc, char ** argv) return 1; } g_debug("dbusname: %s, dbusobject: %s", dbusname, dbusobject); - return 1; } else { if (dbusname == NULL) { g_printerr("ERROR: dbus-name not specified\n"); -- cgit v1.2.3