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