clientwin.c 6.0 KB

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