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