clientwin.c revision a005d216
1/*
2 * Copyright 2007 Kim woelders
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  The copyright holders make no representations
11 * about the suitability of this software for any purpose.  It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22#include <X11/Xatom.h>
23#include <X11/Xlib.h>
24
25static Atom atom_wm_state = None;
26
27/*
28 * Check if window has given property
29 */
30static Bool
31Window_Has_Property(Display * dpy, Window win, Atom atom)
32{
33    Atom type_ret;
34    int format_ret;
35    unsigned char *prop_ret;
36    unsigned long bytes_after, num_ret;
37
38    type_ret = None;
39    prop_ret = NULL;
40    XGetWindowProperty(dpy, win, atom, 0, 0, False, AnyPropertyType,
41                       &type_ret, &format_ret, &num_ret,
42                       &bytes_after, &prop_ret);
43    if (prop_ret)
44        XFree(prop_ret);
45
46    return (type_ret != None) ? True : False;
47}
48
49/*
50 * Check if window is viewable
51 */
52static Bool
53Window_Is_Viewable(Display * dpy, Window win)
54{
55    Bool ok;
56    XWindowAttributes xwa;
57
58    XGetWindowAttributes(dpy, win, &xwa);
59
60    ok = (xwa.class == InputOutput) && (xwa.map_state == IsViewable);
61
62    return ok;
63}
64
65/*
66 * Find a window that has WM_STATE set in the window tree below win.
67 * Unmapped/unviewable windows are not considered valid matches.
68 * Children are searched in top-down stacking order.
69 * The first matching window is returned, None if no match is found.
70 */
71Window
72Find_Client_In_Children(Display * dpy, Window win)
73{
74    Window root, parent;
75    Window *children;
76    unsigned int n_children;
77    int i;
78
79    if (!XQueryTree(dpy, win, &root, &parent, &children, &n_children))
80        return None;
81    if (!children)
82        return None;
83
84    /* Check each child for WM_STATE and other validity */
85    win = None;
86    for (i = (int) n_children - 1; i >= 0; i--) {
87        if (!Window_Is_Viewable(dpy, children[i])) {
88            children[i] = None; /* Don't bother descending into this one */
89            continue;
90        }
91        if (!Window_Has_Property(dpy, children[i], atom_wm_state))
92            continue;
93
94        /* Got one */
95        win = children[i];
96        goto done;
97    }
98
99    /* No children matched, now descend into each child */
100    for (i = (int) n_children - 1; i >= 0; i--) {
101        if (children[i] == None)
102            continue;
103        win = Find_Client_In_Children(dpy, children[i]);
104        if (win != None)
105            break;
106    }
107
108  done:
109    XFree(children);
110
111    return win;
112}
113
114/*
115 * Find virtual roots (_NET_VIRTUAL_ROOTS)
116 */
117unsigned long *
118Find_Roots(Display * dpy, Window root, unsigned int *num)
119{
120    Atom type_ret;
121    int format_ret;
122    unsigned char *prop_ret;
123    unsigned long bytes_after, num_ret;
124    Atom atom;
125
126    *num = 0;
127    atom = XInternAtom(dpy, "_NET_VIRTUAL_ROOTS", False);
128    if (!atom)
129        return NULL;
130
131    type_ret = None;
132    prop_ret = NULL;
133    if (XGetWindowProperty(dpy, root, atom, 0, 0x7fffffff, False,
134                           XA_WINDOW, &type_ret, &format_ret, &num_ret,
135                           &bytes_after, &prop_ret) != Success)
136        return NULL;
137
138    if (prop_ret && type_ret == XA_WINDOW && format_ret == 32) {
139        *num = num_ret;
140        return ((unsigned long *) prop_ret);
141    }
142    if (prop_ret)
143        XFree(prop_ret);
144
145    return NULL;
146}
147
148/*
149 * Find child window at pointer location
150 */
151static Window
152Find_Child_At_Pointer(Display * dpy, Window win)
153{
154    Window root_return, child_return;
155    int dummyi;
156    unsigned int dummyu;
157
158    XQueryPointer(dpy, win, &root_return, &child_return,
159                  &dummyi, &dummyi, &dummyi, &dummyi, &dummyu);
160
161    return child_return;
162}
163
164/*
165 * Find client window at pointer location
166 *
167 * root   is the root window.
168 * subwin is the subwindow reported by a ButtonPress event on root.
169 *
170 * If the WM uses virtual roots subwin may be a virtual root.
171 * If so, we descend the window stack at the pointer location and assume the
172 * child is the client or one of its WM frame windows.
173 * This will of course work only if the virtual roots are children of the real
174 * root.
175 */
176Window
177Find_Client(Display * dpy, Window root, Window subwin)
178{
179    unsigned long *roots;
180    unsigned int i, n_roots;
181    Window win;
182
183    /* Check if subwin is a virtual root */
184    roots = Find_Roots(dpy, root, &n_roots);
185    for (i = 0; i < n_roots; i++) {
186        if (subwin != roots[i])
187            continue;
188        win = Find_Child_At_Pointer(dpy, subwin);
189        if (win == None)
190            return subwin;      /* No child - Return virtual root. */
191        subwin = win;
192        break;
193    }
194    if (roots)
195        XFree(roots);
196
197    if (atom_wm_state == None) {
198        atom_wm_state = XInternAtom(dpy, "WM_STATE", False);
199        if (!atom_wm_state)
200            return subwin;
201    }
202
203    /* Check if subwin has WM_STATE */
204    if (Window_Has_Property(dpy, subwin, atom_wm_state))
205        return subwin;
206
207    /* Attempt to find a client window in subwin's children */
208    win = Find_Client_In_Children(dpy, subwin);
209    if (win != None)
210        return win;             /* Found a client */
211
212    /* Did not find a client */
213    return subwin;
214}
215