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