18b5ec993Smrg/* 28b5ec993Smrg * Copyright 2007 Kim woelders 38b5ec993Smrg * 48b5ec993Smrg * Permission to use, copy, modify, distribute, and sell this software and its 58b5ec993Smrg * documentation for any purpose is hereby granted without fee, provided that 68b5ec993Smrg * the above copyright notice appear in all copies and that both that copyright 78b5ec993Smrg * notice and this permission notice appear in supporting documentation, and 88b5ec993Smrg * that the name of the copyright holders not be used in advertising or 98b5ec993Smrg * publicity pertaining to distribution of the software without specific, 108b5ec993Smrg * written prior permission. The copyright holders make no representations 118b5ec993Smrg * about the suitability of this software for any purpose. It is provided "as 128b5ec993Smrg * is" without express or implied warranty. 138b5ec993Smrg * 148b5ec993Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 158b5ec993Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 168b5ec993Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 178b5ec993Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 188b5ec993Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 198b5ec993Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 208b5ec993Smrg * OF THIS SOFTWARE. 218b5ec993Smrg */ 228b5ec993Smrg#include <X11/Xatom.h> 238b5ec993Smrg#include <X11/Xlib.h> 248b5ec993Smrg 258b5ec993Smrg#include "clientwin.h" 268b5ec993Smrg 278b5ec993Smrgstatic Atom atom_wm_state = None; 288b5ec993Smrg 298b5ec993Smrg/* 308b5ec993Smrg * Check if window has given property 318b5ec993Smrg */ 328b5ec993Smrgstatic Bool 338b5ec993SmrgWindow_Has_Property(Display * dpy, Window win, Atom atom) 348b5ec993Smrg{ 358b5ec993Smrg Atom type_ret; 368b5ec993Smrg int format_ret; 378b5ec993Smrg unsigned char *prop_ret; 388b5ec993Smrg unsigned long bytes_after, num_ret; 398b5ec993Smrg 408b5ec993Smrg type_ret = None; 418b5ec993Smrg prop_ret = NULL; 428b5ec993Smrg XGetWindowProperty(dpy, win, atom, 0, 0, False, AnyPropertyType, 438b5ec993Smrg &type_ret, &format_ret, &num_ret, 448b5ec993Smrg &bytes_after, &prop_ret); 458b5ec993Smrg if (prop_ret) 468b5ec993Smrg XFree(prop_ret); 478b5ec993Smrg 488b5ec993Smrg return (type_ret != None) ? True : False; 498b5ec993Smrg} 508b5ec993Smrg 518b5ec993Smrg/* 528b5ec993Smrg * Check if window is viewable 538b5ec993Smrg */ 548b5ec993Smrgstatic Bool 558b5ec993SmrgWindow_Is_Viewable(Display * dpy, Window win) 568b5ec993Smrg{ 578b5ec993Smrg Bool ok; 588b5ec993Smrg XWindowAttributes xwa; 598b5ec993Smrg 608b5ec993Smrg XGetWindowAttributes(dpy, win, &xwa); 618b5ec993Smrg 628b5ec993Smrg ok = (xwa.class == InputOutput) && (xwa.map_state == IsViewable); 638b5ec993Smrg 648b5ec993Smrg return ok; 658b5ec993Smrg} 668b5ec993Smrg 678b5ec993Smrg/* 688b5ec993Smrg * Find a window that has WM_STATE set in the window tree below win. 698b5ec993Smrg * Unmapped/unviewable windows are not considered valid matches. 708b5ec993Smrg * Children are searched in top-down stacking order. 718b5ec993Smrg * The first matching window is returned, None if no match is found. 728b5ec993Smrg */ 738b5ec993Smrgstatic Window 748b5ec993SmrgFind_Client_In_Children(Display * dpy, Window win) 758b5ec993Smrg{ 768b5ec993Smrg Window root, parent; 778b5ec993Smrg Window *children; 788b5ec993Smrg unsigned int n_children; 798b5ec993Smrg int i; 808b5ec993Smrg 818b5ec993Smrg if (!XQueryTree(dpy, win, &root, &parent, &children, &n_children)) 828b5ec993Smrg return None; 838b5ec993Smrg if (!children) 848b5ec993Smrg return None; 858b5ec993Smrg 868b5ec993Smrg /* Check each child for WM_STATE and other validity */ 878b5ec993Smrg win = None; 888b5ec993Smrg for (i = (int) n_children - 1; i >= 0; i--) { 898b5ec993Smrg if (!Window_Is_Viewable(dpy, children[i])) { 908b5ec993Smrg children[i] = None; /* Don't bother descending into this one */ 918b5ec993Smrg continue; 928b5ec993Smrg } 938b5ec993Smrg if (!Window_Has_Property(dpy, children[i], atom_wm_state)) 948b5ec993Smrg continue; 958b5ec993Smrg 968b5ec993Smrg /* Got one */ 978b5ec993Smrg win = children[i]; 988b5ec993Smrg goto done; 998b5ec993Smrg } 1008b5ec993Smrg 1018b5ec993Smrg /* No children matched, now descend into each child */ 1028b5ec993Smrg for (i = (int) n_children - 1; i >= 0; i--) { 1038b5ec993Smrg if (children[i] == None) 1048b5ec993Smrg continue; 1058b5ec993Smrg win = Find_Client_In_Children(dpy, children[i]); 1068b5ec993Smrg if (win != None) 1078b5ec993Smrg break; 1088b5ec993Smrg } 1098b5ec993Smrg 1108b5ec993Smrg done: 1118b5ec993Smrg XFree(children); 1128b5ec993Smrg 1138b5ec993Smrg return win; 1148b5ec993Smrg} 1158b5ec993Smrg 1168b5ec993Smrg/* 1178b5ec993Smrg * Find virtual roots (_NET_VIRTUAL_ROOTS) 1188b5ec993Smrg */ 1198b5ec993Smrgstatic unsigned long * 1208b5ec993SmrgFind_Roots(Display * dpy, Window root, unsigned int *num) 1218b5ec993Smrg{ 1228b5ec993Smrg Atom type_ret; 1238b5ec993Smrg int format_ret; 1248b5ec993Smrg unsigned char *prop_ret; 1258b5ec993Smrg unsigned long bytes_after, num_ret; 1268b5ec993Smrg Atom atom; 1278b5ec993Smrg 1288b5ec993Smrg *num = 0; 1298b5ec993Smrg atom = XInternAtom(dpy, "_NET_VIRTUAL_ROOTS", False); 1308b5ec993Smrg if (!atom) 1318b5ec993Smrg return NULL; 1328b5ec993Smrg 1338b5ec993Smrg type_ret = None; 1348b5ec993Smrg prop_ret = NULL; 1358b5ec993Smrg if (XGetWindowProperty(dpy, root, atom, 0, 0x7fffffff, False, 1368b5ec993Smrg XA_WINDOW, &type_ret, &format_ret, &num_ret, 1378b5ec993Smrg &bytes_after, &prop_ret) != Success) 1388b5ec993Smrg return NULL; 1398b5ec993Smrg 1408b5ec993Smrg if (prop_ret && type_ret == XA_WINDOW && format_ret == 32) { 1418b5ec993Smrg *num = num_ret; 1428b5ec993Smrg return ((unsigned long *) prop_ret); 1438b5ec993Smrg } 1448b5ec993Smrg if (prop_ret) 1458b5ec993Smrg XFree(prop_ret); 1468b5ec993Smrg 1478b5ec993Smrg return NULL; 1488b5ec993Smrg} 1498b5ec993Smrg 1508b5ec993Smrg/* 1518b5ec993Smrg * Find child window at pointer location 1528b5ec993Smrg */ 1538b5ec993Smrgstatic Window 1548b5ec993SmrgFind_Child_At_Pointer(Display * dpy, Window win) 1558b5ec993Smrg{ 1568b5ec993Smrg Window root_return, child_return; 1578b5ec993Smrg int dummyi; 1588b5ec993Smrg unsigned int dummyu; 1598b5ec993Smrg 1608b5ec993Smrg XQueryPointer(dpy, win, &root_return, &child_return, 1618b5ec993Smrg &dummyi, &dummyi, &dummyi, &dummyi, &dummyu); 1628b5ec993Smrg 1638b5ec993Smrg return child_return; 1648b5ec993Smrg} 1658b5ec993Smrg 1668b5ec993Smrg/* 1678b5ec993Smrg * Find client window at pointer location 1688b5ec993Smrg * 1698b5ec993Smrg * root is the root window. 1708b5ec993Smrg * subwin is the subwindow reported by a ButtonPress event on root. 1718b5ec993Smrg * 1728b5ec993Smrg * If the WM uses virtual roots subwin may be a virtual root. 1738b5ec993Smrg * If so, we descend the window stack at the pointer location and assume the 1748b5ec993Smrg * child is the client or one of its WM frame windows. 1758b5ec993Smrg * This will of course work only if the virtual roots are children of the real 1768b5ec993Smrg * root. 1778b5ec993Smrg */ 1788b5ec993SmrgWindow 1798b5ec993SmrgFind_Client(Display * dpy, Window root, Window subwin) 1808b5ec993Smrg{ 1818b5ec993Smrg unsigned long *roots; 1828b5ec993Smrg unsigned int i, n_roots; 1838b5ec993Smrg Window win; 1848b5ec993Smrg 1858b5ec993Smrg /* Check if subwin is a virtual root */ 1868b5ec993Smrg roots = Find_Roots(dpy, root, &n_roots); 1878b5ec993Smrg for (i = 0; i < n_roots; i++) { 1888b5ec993Smrg if (subwin != roots[i]) 1898b5ec993Smrg continue; 1908b5ec993Smrg win = Find_Child_At_Pointer(dpy, subwin); 1918b5ec993Smrg if (win == None) 1928b5ec993Smrg return subwin; /* No child - Return virtual root. */ 1938b5ec993Smrg subwin = win; 1948b5ec993Smrg break; 1958b5ec993Smrg } 1968b5ec993Smrg if (roots) 1978b5ec993Smrg XFree(roots); 1988b5ec993Smrg 1998b5ec993Smrg if (atom_wm_state == None) { 2008b5ec993Smrg atom_wm_state = XInternAtom(dpy, "WM_STATE", False); 2018b5ec993Smrg if (!atom_wm_state) 2028b5ec993Smrg return subwin; 2038b5ec993Smrg } 2048b5ec993Smrg 2058b5ec993Smrg /* Check if subwin has WM_STATE */ 2068b5ec993Smrg if (Window_Has_Property(dpy, subwin, atom_wm_state)) 2078b5ec993Smrg return subwin; 2088b5ec993Smrg 2098b5ec993Smrg /* Attempt to find a client window in subwin's children */ 2108b5ec993Smrg win = Find_Client_In_Children(dpy, subwin); 2118b5ec993Smrg if (win != None) 2128b5ec993Smrg return win; /* Found a client */ 2138b5ec993Smrg 2148b5ec993Smrg /* Did not find a client */ 2158b5ec993Smrg return subwin; 2168b5ec993Smrg} 217