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