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