clientwin.c revision 8b5ec993
18b5ec993Smrg/*
28b5ec993Smrg * Copyright 2007 Kim woelders
38b5ec993Smrg *
48b5ec993Smrg * Permission to use, copy, modify, distribute, and sell this software and its
58b5ec993Smrg * documentation for any purpose is hereby granted without fee, provided that
68b5ec993Smrg * the above copyright notice appear in all copies and that both that copyright
78b5ec993Smrg * notice and this permission notice appear in supporting documentation, and
88b5ec993Smrg * that the name of the copyright holders not be used in advertising or
98b5ec993Smrg * publicity pertaining to distribution of the software without specific,
108b5ec993Smrg * written prior permission.  The copyright holders make no representations
118b5ec993Smrg * about the suitability of this software for any purpose.  It is provided "as
128b5ec993Smrg * is" without express or implied warranty.
138b5ec993Smrg *
148b5ec993Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
158b5ec993Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
168b5ec993Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
178b5ec993Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
188b5ec993Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
198b5ec993Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
208b5ec993Smrg * OF THIS SOFTWARE.
218b5ec993Smrg */
228b5ec993Smrg#include <X11/Xatom.h>
238b5ec993Smrg#include <X11/Xlib.h>
248b5ec993Smrg
258b5ec993Smrg#include "clientwin.h"
268b5ec993Smrg
278b5ec993Smrgstatic Atom atom_wm_state = None;
288b5ec993Smrg
298b5ec993Smrg/*
308b5ec993Smrg * Check if window has given property
318b5ec993Smrg */
328b5ec993Smrgstatic Bool
338b5ec993SmrgWindow_Has_Property(Display * dpy, Window win, Atom atom)
348b5ec993Smrg{
358b5ec993Smrg    Atom type_ret;
368b5ec993Smrg    int format_ret;
378b5ec993Smrg    unsigned char *prop_ret;
388b5ec993Smrg    unsigned long bytes_after, num_ret;
398b5ec993Smrg
408b5ec993Smrg    type_ret = None;
418b5ec993Smrg    prop_ret = NULL;
428b5ec993Smrg    XGetWindowProperty(dpy, win, atom, 0, 0, False, AnyPropertyType,
438b5ec993Smrg                       &type_ret, &format_ret, &num_ret,
448b5ec993Smrg                       &bytes_after, &prop_ret);
458b5ec993Smrg    if (prop_ret)
468b5ec993Smrg        XFree(prop_ret);
478b5ec993Smrg
488b5ec993Smrg    return (type_ret != None) ? True : False;
498b5ec993Smrg}
508b5ec993Smrg
518b5ec993Smrg/*
528b5ec993Smrg * Check if window is viewable
538b5ec993Smrg */
548b5ec993Smrgstatic Bool
558b5ec993SmrgWindow_Is_Viewable(Display * dpy, Window win)
568b5ec993Smrg{
578b5ec993Smrg    Bool ok;
588b5ec993Smrg    XWindowAttributes xwa;
598b5ec993Smrg
608b5ec993Smrg    XGetWindowAttributes(dpy, win, &xwa);
618b5ec993Smrg
628b5ec993Smrg    ok = (xwa.class == InputOutput) && (xwa.map_state == IsViewable);
638b5ec993Smrg
648b5ec993Smrg    return ok;
658b5ec993Smrg}
668b5ec993Smrg
678b5ec993Smrg/*
688b5ec993Smrg * Find a window that has WM_STATE set in the window tree below win.
698b5ec993Smrg * Unmapped/unviewable windows are not considered valid matches.
708b5ec993Smrg * Children are searched in top-down stacking order.
718b5ec993Smrg * The first matching window is returned, None if no match is found.
728b5ec993Smrg */
738b5ec993Smrgstatic Window
748b5ec993SmrgFind_Client_In_Children(Display * dpy, Window win)
758b5ec993Smrg{
768b5ec993Smrg    Window root, parent;
778b5ec993Smrg    Window *children;
788b5ec993Smrg    unsigned int n_children;
798b5ec993Smrg    int i;
808b5ec993Smrg
818b5ec993Smrg    if (!XQueryTree(dpy, win, &root, &parent, &children, &n_children))
828b5ec993Smrg        return None;
838b5ec993Smrg    if (!children)
848b5ec993Smrg        return None;
858b5ec993Smrg
868b5ec993Smrg    /* Check each child for WM_STATE and other validity */
878b5ec993Smrg    win = None;
888b5ec993Smrg    for (i = (int) n_children - 1; i >= 0; i--) {
898b5ec993Smrg        if (!Window_Is_Viewable(dpy, children[i])) {
908b5ec993Smrg            children[i] = None; /* Don't bother descending into this one */
918b5ec993Smrg            continue;
928b5ec993Smrg        }
938b5ec993Smrg        if (!Window_Has_Property(dpy, children[i], atom_wm_state))
948b5ec993Smrg            continue;
958b5ec993Smrg
968b5ec993Smrg        /* Got one */
978b5ec993Smrg        win = children[i];
988b5ec993Smrg        goto done;
998b5ec993Smrg    }
1008b5ec993Smrg
1018b5ec993Smrg    /* No children matched, now descend into each child */
1028b5ec993Smrg    for (i = (int) n_children - 1; i >= 0; i--) {
1038b5ec993Smrg        if (children[i] == None)
1048b5ec993Smrg            continue;
1058b5ec993Smrg        win = Find_Client_In_Children(dpy, children[i]);
1068b5ec993Smrg        if (win != None)
1078b5ec993Smrg            break;
1088b5ec993Smrg    }
1098b5ec993Smrg
1108b5ec993Smrg  done:
1118b5ec993Smrg    XFree(children);
1128b5ec993Smrg
1138b5ec993Smrg    return win;
1148b5ec993Smrg}
1158b5ec993Smrg
1168b5ec993Smrg/*
1178b5ec993Smrg * Find virtual roots (_NET_VIRTUAL_ROOTS)
1188b5ec993Smrg */
1198b5ec993Smrgstatic unsigned long *
1208b5ec993SmrgFind_Roots(Display * dpy, Window root, unsigned int *num)
1218b5ec993Smrg{
1228b5ec993Smrg    Atom type_ret;
1238b5ec993Smrg    int format_ret;
1248b5ec993Smrg    unsigned char *prop_ret;
1258b5ec993Smrg    unsigned long bytes_after, num_ret;
1268b5ec993Smrg    Atom atom;
1278b5ec993Smrg
1288b5ec993Smrg    *num = 0;
1298b5ec993Smrg    atom = XInternAtom(dpy, "_NET_VIRTUAL_ROOTS", False);
1308b5ec993Smrg    if (!atom)
1318b5ec993Smrg        return NULL;
1328b5ec993Smrg
1338b5ec993Smrg    type_ret = None;
1348b5ec993Smrg    prop_ret = NULL;
1358b5ec993Smrg    if (XGetWindowProperty(dpy, root, atom, 0, 0x7fffffff, False,
1368b5ec993Smrg                           XA_WINDOW, &type_ret, &format_ret, &num_ret,
1378b5ec993Smrg                           &bytes_after, &prop_ret) != Success)
1388b5ec993Smrg        return NULL;
1398b5ec993Smrg
1408b5ec993Smrg    if (prop_ret && type_ret == XA_WINDOW && format_ret == 32) {
1418b5ec993Smrg        *num = num_ret;
1428b5ec993Smrg        return ((unsigned long *) prop_ret);
1438b5ec993Smrg    }
1448b5ec993Smrg    if (prop_ret)
1458b5ec993Smrg        XFree(prop_ret);
1468b5ec993Smrg
1478b5ec993Smrg    return NULL;
1488b5ec993Smrg}
1498b5ec993Smrg
1508b5ec993Smrg/*
1518b5ec993Smrg * Find child window at pointer location
1528b5ec993Smrg */
1538b5ec993Smrgstatic Window
1548b5ec993SmrgFind_Child_At_Pointer(Display * dpy, Window win)
1558b5ec993Smrg{
1568b5ec993Smrg    Window root_return, child_return;
1578b5ec993Smrg    int dummyi;
1588b5ec993Smrg    unsigned int dummyu;
1598b5ec993Smrg
1608b5ec993Smrg    XQueryPointer(dpy, win, &root_return, &child_return,
1618b5ec993Smrg                  &dummyi, &dummyi, &dummyi, &dummyi, &dummyu);
1628b5ec993Smrg
1638b5ec993Smrg    return child_return;
1648b5ec993Smrg}
1658b5ec993Smrg
1668b5ec993Smrg/*
1678b5ec993Smrg * Find client window at pointer location
1688b5ec993Smrg *
1698b5ec993Smrg * root   is the root window.
1708b5ec993Smrg * subwin is the subwindow reported by a ButtonPress event on root.
1718b5ec993Smrg *
1728b5ec993Smrg * If the WM uses virtual roots subwin may be a virtual root.
1738b5ec993Smrg * If so, we descend the window stack at the pointer location and assume the
1748b5ec993Smrg * child is the client or one of its WM frame windows.
1758b5ec993Smrg * This will of course work only if the virtual roots are children of the real
1768b5ec993Smrg * root.
1778b5ec993Smrg */
1788b5ec993SmrgWindow
1798b5ec993SmrgFind_Client(Display * dpy, Window root, Window subwin)
1808b5ec993Smrg{
1818b5ec993Smrg    unsigned long *roots;
1828b5ec993Smrg    unsigned int i, n_roots;
1838b5ec993Smrg    Window win;
1848b5ec993Smrg
1858b5ec993Smrg    /* Check if subwin is a virtual root */
1868b5ec993Smrg    roots = Find_Roots(dpy, root, &n_roots);
1878b5ec993Smrg    for (i = 0; i < n_roots; i++) {
1888b5ec993Smrg        if (subwin != roots[i])
1898b5ec993Smrg            continue;
1908b5ec993Smrg        win = Find_Child_At_Pointer(dpy, subwin);
1918b5ec993Smrg        if (win == None)
1928b5ec993Smrg            return subwin;      /* No child - Return virtual root. */
1938b5ec993Smrg        subwin = win;
1948b5ec993Smrg        break;
1958b5ec993Smrg    }
1968b5ec993Smrg    if (roots)
1978b5ec993Smrg        XFree(roots);
1988b5ec993Smrg
1998b5ec993Smrg    if (atom_wm_state == None) {
2008b5ec993Smrg        atom_wm_state = XInternAtom(dpy, "WM_STATE", False);
2018b5ec993Smrg        if (!atom_wm_state)
2028b5ec993Smrg            return subwin;
2038b5ec993Smrg    }
2048b5ec993Smrg
2058b5ec993Smrg    /* Check if subwin has WM_STATE */
2068b5ec993Smrg    if (Window_Has_Property(dpy, subwin, atom_wm_state))
2078b5ec993Smrg        return subwin;
2088b5ec993Smrg
2098b5ec993Smrg    /* Attempt to find a client window in subwin's children */
2108b5ec993Smrg    win = Find_Client_In_Children(dpy, subwin);
2118b5ec993Smrg    if (win != None)
2128b5ec993Smrg        return win;             /* Found a client */
2138b5ec993Smrg
2148b5ec993Smrg    /* Did not find a client */
2158b5ec993Smrg    return subwin;
2168b5ec993Smrg}
217