clientwin.c revision 5e358eca
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
255e358ecaSmrg#include "clientwin.h"
265e358ecaSmrg
27afe13c8eSmrgstatic Atom atom_wm_state = None;
28afe13c8eSmrg
29afe13c8eSmrg/*
30afe13c8eSmrg * Check if window has given property
31afe13c8eSmrg */
32afe13c8eSmrgstatic Bool
33afe13c8eSmrgWindow_Has_Property(Display * dpy, Window win, Atom atom)
34afe13c8eSmrg{
35afe13c8eSmrg    Atom type_ret;
36afe13c8eSmrg    int format_ret;
37afe13c8eSmrg    unsigned char *prop_ret;
38afe13c8eSmrg    unsigned long bytes_after, num_ret;
39afe13c8eSmrg
40afe13c8eSmrg    type_ret = None;
41afe13c8eSmrg    prop_ret = NULL;
42afe13c8eSmrg    XGetWindowProperty(dpy, win, atom, 0, 0, False, AnyPropertyType,
43afe13c8eSmrg                       &type_ret, &format_ret, &num_ret,
44afe13c8eSmrg                       &bytes_after, &prop_ret);
45afe13c8eSmrg    if (prop_ret)
46afe13c8eSmrg        XFree(prop_ret);
47afe13c8eSmrg
48afe13c8eSmrg    return (type_ret != None) ? True : False;
49afe13c8eSmrg}
50afe13c8eSmrg
51afe13c8eSmrg/*
52afe13c8eSmrg * Check if window is viewable
53afe13c8eSmrg */
54afe13c8eSmrgstatic Bool
55afe13c8eSmrgWindow_Is_Viewable(Display * dpy, Window win)
56afe13c8eSmrg{
57afe13c8eSmrg    Bool ok;
58afe13c8eSmrg    XWindowAttributes xwa;
59afe13c8eSmrg
60afe13c8eSmrg    XGetWindowAttributes(dpy, win, &xwa);
61afe13c8eSmrg
62afe13c8eSmrg    ok = (xwa.class == InputOutput) && (xwa.map_state == IsViewable);
63afe13c8eSmrg
64afe13c8eSmrg    return ok;
65afe13c8eSmrg}
66afe13c8eSmrg
67afe13c8eSmrg/*
68afe13c8eSmrg * Find a window that has WM_STATE set in the window tree below win.
69afe13c8eSmrg * Unmapped/unviewable windows are not considered valid matches.
70afe13c8eSmrg * Children are searched in top-down stacking order.
71afe13c8eSmrg * The first matching window is returned, None if no match is found.
72afe13c8eSmrg */
735e358ecaSmrgstatic Window
74afe13c8eSmrgFind_Client_In_Children(Display * dpy, Window win)
75afe13c8eSmrg{
76afe13c8eSmrg    Window root, parent;
77afe13c8eSmrg    Window *children;
78afe13c8eSmrg    unsigned int n_children;
79afe13c8eSmrg    int i;
80afe13c8eSmrg
81afe13c8eSmrg    if (!XQueryTree(dpy, win, &root, &parent, &children, &n_children))
82afe13c8eSmrg        return None;
83afe13c8eSmrg    if (!children)
84afe13c8eSmrg        return None;
85afe13c8eSmrg
86afe13c8eSmrg    /* Check each child for WM_STATE and other validity */
87afe13c8eSmrg    win = None;
88afe13c8eSmrg    for (i = (int) n_children - 1; i >= 0; i--) {
89afe13c8eSmrg        if (!Window_Is_Viewable(dpy, children[i])) {
90afe13c8eSmrg            children[i] = None; /* Don't bother descending into this one */
91afe13c8eSmrg            continue;
92afe13c8eSmrg        }
93afe13c8eSmrg        if (!Window_Has_Property(dpy, children[i], atom_wm_state))
94afe13c8eSmrg            continue;
95afe13c8eSmrg
96afe13c8eSmrg        /* Got one */
97afe13c8eSmrg        win = children[i];
98afe13c8eSmrg        goto done;
99afe13c8eSmrg    }
100afe13c8eSmrg
101afe13c8eSmrg    /* No children matched, now descend into each child */
102afe13c8eSmrg    for (i = (int) n_children - 1; i >= 0; i--) {
103afe13c8eSmrg        if (children[i] == None)
104afe13c8eSmrg            continue;
105afe13c8eSmrg        win = Find_Client_In_Children(dpy, children[i]);
106afe13c8eSmrg        if (win != None)
107afe13c8eSmrg            break;
108afe13c8eSmrg    }
109afe13c8eSmrg
110afe13c8eSmrg  done:
111afe13c8eSmrg    XFree(children);
112afe13c8eSmrg
113afe13c8eSmrg    return win;
114afe13c8eSmrg}
115afe13c8eSmrg
116afe13c8eSmrg/*
117afe13c8eSmrg * Find virtual roots (_NET_VIRTUAL_ROOTS)
118afe13c8eSmrg */
1195e358ecaSmrgstatic unsigned long *
120afe13c8eSmrgFind_Roots(Display * dpy, Window root, unsigned int *num)
121afe13c8eSmrg{
122afe13c8eSmrg    Atom type_ret;
123afe13c8eSmrg    int format_ret;
124afe13c8eSmrg    unsigned char *prop_ret;
125afe13c8eSmrg    unsigned long bytes_after, num_ret;
126afe13c8eSmrg    Atom atom;
127afe13c8eSmrg
128afe13c8eSmrg    *num = 0;
129afe13c8eSmrg    atom = XInternAtom(dpy, "_NET_VIRTUAL_ROOTS", False);
130afe13c8eSmrg    if (!atom)
131afe13c8eSmrg        return NULL;
132afe13c8eSmrg
133afe13c8eSmrg    type_ret = None;
134afe13c8eSmrg    prop_ret = NULL;
135afe13c8eSmrg    if (XGetWindowProperty(dpy, root, atom, 0, 0x7fffffff, False,
136afe13c8eSmrg                           XA_WINDOW, &type_ret, &format_ret, &num_ret,
137afe13c8eSmrg                           &bytes_after, &prop_ret) != Success)
138afe13c8eSmrg        return NULL;
139afe13c8eSmrg
140afe13c8eSmrg    if (prop_ret && type_ret == XA_WINDOW && format_ret == 32) {
141afe13c8eSmrg        *num = num_ret;
142afe13c8eSmrg        return ((unsigned long *) prop_ret);
143afe13c8eSmrg    }
144afe13c8eSmrg    if (prop_ret)
145afe13c8eSmrg        XFree(prop_ret);
146afe13c8eSmrg
147afe13c8eSmrg    return NULL;
148afe13c8eSmrg}
149afe13c8eSmrg
150afe13c8eSmrg/*
151afe13c8eSmrg * Find child window at pointer location
152afe13c8eSmrg */
153afe13c8eSmrgstatic Window
154afe13c8eSmrgFind_Child_At_Pointer(Display * dpy, Window win)
155afe13c8eSmrg{
156afe13c8eSmrg    Window root_return, child_return;
157afe13c8eSmrg    int dummyi;
158afe13c8eSmrg    unsigned int dummyu;
159afe13c8eSmrg
160afe13c8eSmrg    XQueryPointer(dpy, win, &root_return, &child_return,
161afe13c8eSmrg                  &dummyi, &dummyi, &dummyi, &dummyi, &dummyu);
162afe13c8eSmrg
163afe13c8eSmrg    return child_return;
164afe13c8eSmrg}
165afe13c8eSmrg
166afe13c8eSmrg/*
167afe13c8eSmrg * Find client window at pointer location
168afe13c8eSmrg *
169afe13c8eSmrg * root   is the root window.
170afe13c8eSmrg * subwin is the subwindow reported by a ButtonPress event on root.
171afe13c8eSmrg *
172afe13c8eSmrg * If the WM uses virtual roots subwin may be a virtual root.
173afe13c8eSmrg * If so, we descend the window stack at the pointer location and assume the
174afe13c8eSmrg * child is the client or one of its WM frame windows.
175afe13c8eSmrg * This will of course work only if the virtual roots are children of the real
176afe13c8eSmrg * root.
177afe13c8eSmrg */
178afe13c8eSmrgWindow
179afe13c8eSmrgFind_Client(Display * dpy, Window root, Window subwin)
180afe13c8eSmrg{
181afe13c8eSmrg    unsigned long *roots;
182afe13c8eSmrg    unsigned int i, n_roots;
183afe13c8eSmrg    Window win;
184afe13c8eSmrg
185afe13c8eSmrg    /* Check if subwin is a virtual root */
186afe13c8eSmrg    roots = Find_Roots(dpy, root, &n_roots);
187afe13c8eSmrg    for (i = 0; i < n_roots; i++) {
188afe13c8eSmrg        if (subwin != roots[i])
189afe13c8eSmrg            continue;
190afe13c8eSmrg        win = Find_Child_At_Pointer(dpy, subwin);
191afe13c8eSmrg        if (win == None)
192afe13c8eSmrg            return subwin;      /* No child - Return virtual root. */
193afe13c8eSmrg        subwin = win;
194afe13c8eSmrg        break;
195afe13c8eSmrg    }
196afe13c8eSmrg    if (roots)
197afe13c8eSmrg        XFree(roots);
198afe13c8eSmrg
199afe13c8eSmrg    if (atom_wm_state == None) {
200afe13c8eSmrg        atom_wm_state = XInternAtom(dpy, "WM_STATE", False);
201afe13c8eSmrg        if (!atom_wm_state)
202afe13c8eSmrg            return subwin;
203afe13c8eSmrg    }
204afe13c8eSmrg
205afe13c8eSmrg    /* Check if subwin has WM_STATE */
206afe13c8eSmrg    if (Window_Has_Property(dpy, subwin, atom_wm_state))
207afe13c8eSmrg        return subwin;
208afe13c8eSmrg
209afe13c8eSmrg    /* Attempt to find a client window in subwin's children */
210afe13c8eSmrg    win = Find_Client_In_Children(dpy, subwin);
211afe13c8eSmrg    if (win != None)
212afe13c8eSmrg        return win;             /* Found a client */
213afe13c8eSmrg
214afe13c8eSmrg    /* Did not find a client */
215afe13c8eSmrg    return subwin;
216afe13c8eSmrg}
217