summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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--xprop.c16
7 files changed, 256 insertions, 17 deletions
diff --git a/Makefile.am b/Makefile.am
index e4fc5ad..d3fc24a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -27,6 +27,8 @@ xprop_LDADD = $(XPROP_LIBS)
xprop_SOURCES = \
dsimple.c \
dsimple.h \
+ clientwin.c \
+ clientwin.h \
xprop.c
appman_PRE = \
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 da8ebb8..78e4049 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,7 +38,7 @@ AC_PROG_INSTALL
AC_CHECK_HEADERS_ONCE([wchar.h wctype.h])
# Checks for pkg-config packages
-PKG_CHECK_MODULES(XPROP, xmuu x11)
+PKG_CHECK_MODULES(XPROP, x11)
AC_SUBST(XPROP_CFLAGS)
AC_SUBST(XPROP_LIBS)
diff --git a/dsimple.c b/dsimple.c
index 0c9fce8..2642e31 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"
/*
@@ -263,7 +264,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;
@@ -302,6 +303,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 7b53c3c..7557571 100644
--- a/dsimple.h
+++ b/dsimple.h
@@ -78,7 +78,7 @@ void usage(void);
* Send bugs, etc. to chariot@athena.mit.edu.
*/
-Window Select_Window(Display *);
+Window Select_Window(Display *, int descend);
Window Window_With_Name(Display *, Window, const char *);
#ifdef __GNUC__
void Fatal_Error(char *, ...) __attribute__((__noreturn__));
diff --git a/xprop.c b/xprop.c
index c489486..f1bf02a 100644
--- a/xprop.c
+++ b/xprop.c
@@ -51,7 +51,6 @@ from The Open Group.
#endif
#include <X11/Xatom.h>
-#include <X11/Xmu/WinUtil.h>
#include "dsimple.h"
@@ -1702,19 +1701,8 @@ main (int argc, char **argv)
if ((remove_props != NULL || set_props != NULL) && argc > 0)
usage();
- if (target_win == None) {
- 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);
if (remove_props != NULL) {
int count;