summaryrefslogtreecommitdiff
path: root/clientwin.c
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 /clientwin.c
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>
Diffstat (limited to 'clientwin.c')
-rw-r--r--clientwin.c214
1 files changed, 214 insertions, 0 deletions
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;
+}