summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKim Woelders <kim@woelders.dk>2008-06-22 01:16:31 -0400
committerJames Cloos <cloos@jhcloos.com>2008-06-22 01:16:31 -0400
commit3dcc66bbbc74c41c2b4509a785c3688fd75387a1 (patch)
treeadcee83f642d2e21d3030c50e4a542e6ad731eed
parent23b60f871f76878572b2acec59dd6c47e3acd0e0 (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.c9
-rw-r--r--dsimple.h2
-rw-r--r--xwd.c19
7 files changed, 256 insertions, 21 deletions
diff --git a/Makefile.am b/Makefile.am
index 0199d35..8e193a9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,6 +25,8 @@ xwd_CFLAGS = $(XWD_CFLAGS)
xwd_LDADD = $(XWD_LIBS)
xwd_SOURCES = \
+ clientwin.c \
+ clientwin.h \
dsimple.c \
dsimple.h \
list.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 260dee4..2580530 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,7 +33,7 @@ AM_PROG_CC_C_O
AC_PROG_INSTALL
# Checks for pkg-config packages
-PKG_CHECK_MODULES(XWD, xmuu x11)
+PKG_CHECK_MODULES(XWD, x11)
AC_SUBST(XWD_CFLAGS)
AC_SUBST(XWD_LIBS)
diff --git a/dsimple.c b/dsimple.c
index c84ac3b..6fd77df 100644
--- a/dsimple.c
+++ b/dsimple.c
@@ -44,6 +44,7 @@ from The Open Group.
#ifdef BUILD_PRINTSUPPORT
#include <X11/XprintUtil/xprintutil.h>
#endif /* BUILD_PRINTSUPPORT */
+#include "clientwin.h"
#include "dsimple.h"
/*
@@ -503,8 +504,7 @@ void blip()
* Routine to let user select a window using the mouse
*/
-Window Select_Window(dpy)
- Display *dpy;
+Window Select_Window(Display *dpy, int descend)
{
int status;
Cursor cursor;
@@ -543,6 +543,11 @@ Window Select_Window(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 d4dbd01..d6b8d69 100644
--- a/dsimple.h
+++ b/dsimple.h
@@ -91,7 +91,7 @@ void usage(void);
unsigned long Resolve_Color(Window, char *);
Pixmap Bitmap_To_Pixmap(Display *, Drawable, GC, Pixmap, int, int);
-Window Select_Window(Display *);
+Window Select_Window(Display *, int);
void blip(void);
Window Window_With_Name(Display *, Window, char *);
#ifdef __GNUC__
diff --git a/xwd.c b/xwd.c
index 82d43ef..944faab 100644
--- a/xwd.c
+++ b/xwd.c
@@ -74,7 +74,6 @@ in this Software without prior written authorization from The Open Group.
#include <X11/Xlib.h>
#include <X11/Xutil.h>
-#include <X11/Xmu/WinUtil.h>
typedef unsigned long Pixel;
#include "X11/XWDFile.h"
@@ -199,22 +198,8 @@ main(argc, argv)
/*
* Let the user select the target window.
*/
- if (!target_win) {
- target_win = Select_Window(dpy);
- }
-
- if (target_win != None && !frame_only) {
- Window root;
- int dummyi;
- unsigned int dummy;
-
- if (XGetGeometry (dpy, target_win, &root, &dummyi, &dummyi,
- &dummy, &dummy, &dummy, &dummy) &&
- target_win != root) {
- target_win = XmuClientWindow (dpy, target_win);
- }
- }
-
+ if (target_win == None)
+ target_win = Select_Window(dpy, !frame_only);
/*
* Dump it!