summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKim Woelders <kim@woelders.dk>2008-06-22 01:12:13 -0400
committerJames Cloos <cloos@jhcloos.com>2008-06-22 01:12:13 -0400
commitc229611bcb7ee94bea5c075f5e15447e14c0f6ce (patch)
treecc753a96d011ece89685f5c3e0e37f5ce97fd1af
parentb7e88cd9d28a3d3e467b769f3efe87f7c2f4c0a5 (diff)
Fix window selection by pointer.
This should fix things in WM’s using virtual roots as well as in tabbing WM’s. Signed-off-by: James Cloos <cloos@jhcloos.com>
-rw-r--r--Makefile.am2
-rw-r--r--clientwin.c214
-rw-r--r--clientwin.h29
-rw-r--r--configure.ac2
-rw-r--r--dsimple.c8
-rw-r--r--dsimple.h2
-rw-r--r--xwininfo.c13
7 files changed, 255 insertions, 15 deletions
diff --git a/Makefile.am b/Makefile.am
index bb177d5..854f489 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,6 +25,8 @@ AM_CFLAGS = $(XWININFO_CFLAGS)
xwininfo_LDADD = $(XWININFO_LIBS)
xwininfo_SOURCES = \
+ clientwin.c \
+ clientwin.h \
dsimple.c \
dsimple.h \
xwininfo.c
diff --git a/clientwin.c b/clientwin.c
new file mode 100644
index 0000000..808adec
--- /dev/null
+++ b/clientwin.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2007 Kim woelders
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+
+static Atom atom_wm_state = None;
+
+/*
+ * Check if window has given property
+ */
+static Bool
+Window_Has_Property(Display * dpy, Window win, Atom atom)
+{
+ Atom type_ret;
+ int format_ret;
+ unsigned char *prop_ret;
+ unsigned long bytes_after, num_ret;
+
+ type_ret = None;
+ prop_ret = NULL;
+ XGetWindowProperty(dpy, win, atom, 0, 0, False, AnyPropertyType,
+ &type_ret, &format_ret, &num_ret,
+ &bytes_after, &prop_ret);
+ if (prop_ret)
+ XFree(prop_ret);
+
+ return (type_ret != None) ? True : False;
+}
+
+/*
+ * Check if window is viewable
+ */
+static Bool
+Window_Is_Viewable(Display * dpy, Window win)
+{
+ Bool ok;
+ XWindowAttributes xwa;
+
+ XGetWindowAttributes(dpy, win, &xwa);
+
+ ok = (xwa.class == InputOutput) && (xwa.map_state == IsViewable);
+
+ return ok;
+}
+
+/*
+ * Find a window that has WM_STATE set in the window tree below win.
+ * Unmapped/unviewable windows are not considered valid matches.
+ * Children are searched in top-down stacking order.
+ * The first matching window is returned, None if no match is found.
+ */
+Window
+Find_Client_In_Children(Display * dpy, Window win)
+{
+ Window root, parent;
+ Window *children;
+ unsigned int n_children;
+ int i;
+
+ if (!XQueryTree(dpy, win, &root, &parent, &children, &n_children))
+ return None;
+ if (!children)
+ return None;
+
+ /* Check each child for WM_STATE and other validity */
+ win = None;
+ for (i = (int) n_children - 1; i >= 0; i--) {
+ if (!Window_Is_Viewable(dpy, children[i])) {
+ children[i] = None; /* Don't bother descending into this one */
+ continue;
+ }
+ if (!Window_Has_Property(dpy, children[i], atom_wm_state))
+ continue;
+
+ /* Got one */
+ win = children[i];
+ goto done;
+ }
+
+ /* No children matched, now descend into each child */
+ for (i = (int) n_children - 1; i >= 0; i--) {
+ if (children[i] == None)
+ continue;
+ win = Find_Client_In_Children(dpy, children[i]);
+ if (win != None)
+ break;
+ }
+
+ done:
+ XFree(children);
+
+ return win;
+}
+
+/*
+ * Find virtual roots (_NET_VIRTUAL_ROOTS)
+ */
+unsigned long *
+Find_Roots(Display * dpy, Window root, unsigned int *num)
+{
+ Atom type_ret;
+ int format_ret;
+ unsigned char *prop_ret;
+ unsigned long bytes_after, num_ret;
+ Atom atom;
+
+ *num = 0;
+ atom = XInternAtom(dpy, "_NET_VIRTUAL_ROOTS", False);
+ if (!atom)
+ return NULL;
+
+ type_ret = None;
+ prop_ret = NULL;
+ if (XGetWindowProperty(dpy, root, atom, 0, 0x7fffffff, False,
+ XA_WINDOW, &type_ret, &format_ret, &num_ret,
+ &bytes_after, &prop_ret) != Success)
+ return NULL;
+
+ if (prop_ret && type_ret == XA_WINDOW && format_ret == 32) {
+ *num = num_ret;
+ return ((unsigned long *) prop_ret);
+ }
+ if (prop_ret)
+ XFree(prop_ret);
+
+ return NULL;
+}
+
+/*
+ * Find child window at pointer location
+ */
+static Window
+Find_Child_At_Pointer(Display * dpy, Window win)
+{
+ Window root_return, child_return;
+ int dummyi;
+ unsigned int dummyu;
+
+ XQueryPointer(dpy, win, &root_return, &child_return,
+ &dummyi, &dummyi, &dummyi, &dummyi, &dummyu);
+
+ return child_return;
+}
+
+/*
+ * Find client window at pointer location
+ *
+ * root is the root window.
+ * subwin is the subwindow reported by a ButtonPress event on root.
+ *
+ * If the WM uses virtual roots subwin may be a virtual root.
+ * If so, we descend the window stack at the pointer location and assume the
+ * child is the client or one of its WM frame windows.
+ * This will of course work only if the virtual roots are children of the real
+ * root.
+ */
+Window
+Find_Client(Display * dpy, Window root, Window subwin)
+{
+ unsigned long *roots;
+ unsigned int i, n_roots;
+ Window win;
+
+ /* Check if subwin is a virtual root */
+ roots = Find_Roots(dpy, root, &n_roots);
+ for (i = 0; i < n_roots; i++) {
+ if (subwin != roots[i])
+ continue;
+ win = Find_Child_At_Pointer(dpy, subwin);
+ if (win == None)
+ return subwin; /* No child - Return virtual root. */
+ subwin = win;
+ break;
+ }
+ if (roots)
+ XFree(roots);
+
+ if (atom_wm_state == None) {
+ atom_wm_state = XInternAtom(dpy, "WM_STATE", False);
+ if (!atom_wm_state)
+ return subwin;
+ }
+
+ /* Check if subwin has WM_STATE */
+ if (Window_Has_Property(dpy, subwin, atom_wm_state))
+ return subwin;
+
+ /* Attempt to find a client window in subwin's children */
+ win = Find_Client_In_Children(dpy, subwin);
+ if (win != None)
+ return win; /* Found a client */
+
+ /* Did not find a client */
+ return subwin;
+}
diff --git a/clientwin.h b/clientwin.h
new file mode 100644
index 0000000..9fc59b5
--- /dev/null
+++ b/clientwin.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2007 Kim woelders
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+#ifndef _CLIENTWIN_H_
+#define _CLIENTWIN_H_
+
+#include <X11/Xlib.h>
+
+extern Window Find_Client(Display * dpy, Window root, Window target_win);
+
+#endif
diff --git a/configure.ac b/configure.ac
index 4205a59..32b6e3f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -34,7 +34,7 @@ AC_PROG_INSTALL
AC_CHECK_FUNCS([strlcat])
# Checks for pkg-config packages
-PKG_CHECK_MODULES(XWININFO, xmuu xext x11)
+PKG_CHECK_MODULES(XWININFO, xext x11)
AC_SUBST(XWININFO_CFLAGS)
AC_SUBST(XWININFO_LIBS)
diff --git a/dsimple.c b/dsimple.c
index 03b72e7..171795b 100644
--- a/dsimple.c
+++ b/dsimple.c
@@ -41,6 +41,7 @@ from The Open Group.
* Written by Mark Lillibridge. Last updated 7/1/87
*/
+#include "clientwin.h"
#include "dsimple.h"
/*
@@ -233,7 +234,7 @@ Window Select_Window_Args(
* Routine to let user select a window using the mouse
*/
-Window Select_Window(Display *dpy)
+Window Select_Window(Display *dpy, int descend)
{
int status;
Cursor cursor;
@@ -272,6 +273,11 @@ Window Select_Window(Display *dpy)
XUngrabPointer(dpy, CurrentTime); /* Done with pointer */
+ if (!descend || (target_win == root))
+ return(target_win);
+
+ target_win = Find_Client(dpy, root, target_win);
+
return(target_win);
}
diff --git a/dsimple.h b/dsimple.h
index f73fce3..90a6c66 100644
--- a/dsimple.h
+++ b/dsimple.h
@@ -76,7 +76,7 @@ void usage(void);
* Send bugs, etc. to chariot@athena.mit.edu.
*/
-Window Select_Window(Display *);
+Window Select_Window(Display *, int);
Window Window_With_Name(Display *, Window, char *);
#ifdef __GNUC__
void Fatal_Error(char *, ...) __attribute__((__noreturn__));
diff --git a/xwininfo.c b/xwininfo.c
index 8d2c673..3f94b42 100644
--- a/xwininfo.c
+++ b/xwininfo.c
@@ -51,7 +51,6 @@ of the copyright holder.
#include <X11/Xatom.h>
#include <X11/Xos.h>
#include <X11/extensions/shape.h>
-#include <X11/Xmu/WinUtil.h>
#ifndef NO_I18N
#include <X11/Xlocale.h>
#endif
@@ -388,17 +387,7 @@ main(int argc, char **argv)
printf("xwininfo: Please select the window about which you\n");
printf(" would like information by clicking the\n");
printf(" mouse in that window.\n");
- window = Select_Window(dpy);
- if (window && !frame) {
- Window root;
- int dummyi;
- unsigned int dummy;
-
- if (XGetGeometry (dpy, window, &root, &dummyi, &dummyi,
- &dummy, &dummy, &dummy, &dummy) &&
- window != root)
- window = XmuClientWindow (dpy, window);
- }
+ window = Select_Window(dpy, !frame);
}
/*