#include <xcb/xcb.h>
#include <xcb/xproto.h>
#include <stdlib.h>
#include <string.h>
#include "clientwin.h"
#include "dsimple.h"
static xcb_atom_t atom_wm_state = XCB_ATOM_NONE;
static Bool
Window_Has_Property(xcb_connection_t * dpy, xcb_window_t win, xcb_atom_t atom)
{
xcb_get_property_cookie_t prop_cookie;
xcb_get_property_reply_t *prop_reply;
prop_cookie = xcb_get_property (dpy, False, win, atom,
XCB_GET_PROPERTY_TYPE_ANY, 0, 0);
prop_reply = xcb_get_property_reply (dpy, prop_cookie, NULL);
if (prop_reply) {
xcb_atom_t reply_type = prop_reply->type;
free (prop_reply);
if (reply_type != XCB_NONE)
return True;
}
return False;
}
static Bool
Window_Is_Viewable(xcb_connection_t * dpy, xcb_window_t win)
{
Bool ok = False;
xcb_get_window_attributes_cookie_t attr_cookie;
xcb_get_window_attributes_reply_t *xwa;
attr_cookie = xcb_get_window_attributes (dpy, win);
xwa = xcb_get_window_attributes_reply (dpy, attr_cookie, NULL);
if (xwa) {
ok = (xwa->_class == XCB_WINDOW_CLASS_INPUT_OUTPUT) &&
(xwa->map_state == XCB_MAP_STATE_VIEWABLE);
free (xwa);
}
return ok;
}
static xcb_window_t
Find_Client_In_Children(xcb_connection_t * dpy, xcb_window_t win)
{
xcb_query_tree_cookie_t qt_cookie;
xcb_query_tree_reply_t *tree;
xcb_window_t *children;
unsigned int n_children;
int i;
qt_cookie = xcb_query_tree (dpy, win);
tree = xcb_query_tree_reply (dpy, qt_cookie, NULL);
if (!tree)
return XCB_WINDOW_NONE;
n_children = xcb_query_tree_children_length (tree);
if (!n_children) {
free (tree);
return XCB_WINDOW_NONE;
}
children = xcb_query_tree_children (tree);
win = XCB_WINDOW_NONE;
for (i = (int) n_children - 1; i >= 0; i--) {
if (!Window_Is_Viewable(dpy, children[i])) {
children[i] = XCB_WINDOW_NONE;
continue;
}
if (!Window_Has_Property(dpy, children[i], atom_wm_state))
continue;
win = children[i];
goto done;
}
for (i = (int) n_children - 1; i >= 0; i--) {
if (children[i] == XCB_WINDOW_NONE)
continue;
win = Find_Client_In_Children(dpy, children[i]);
if (win != XCB_WINDOW_NONE)
break;
}
done:
free (tree);
return win;
}
static xcb_window_t *
Find_Roots(xcb_connection_t * dpy, xcb_window_t root, unsigned int *num)
{
xcb_atom_t atom_virtual_root;
xcb_get_property_cookie_t prop_cookie;
xcb_get_property_reply_t *prop_reply;
xcb_window_t *prop_ret = NULL;
*num = 0;
atom_virtual_root = Get_Atom (dpy, "_NET_VIRTUAL_ROOTS");
if (atom_virtual_root == XCB_ATOM_NONE)
return NULL;
prop_cookie = xcb_get_property (dpy, False, root, atom_virtual_root,
XCB_ATOM_WINDOW, 0, 0x7fffffff);
prop_reply = xcb_get_property_reply (dpy, prop_cookie, NULL);
if (!prop_reply)
return NULL;
if ((prop_reply->value_len > 0) && (prop_reply->type == XCB_ATOM_WINDOW)
&& (prop_reply->format == 32)) {
int length = xcb_get_property_value_length (prop_reply);
prop_ret = malloc(length);
if (prop_ret) {
memcpy (prop_ret, xcb_get_property_value(prop_reply), length);
*num = prop_reply->value_len;
}
}
free (prop_reply);
return prop_ret;
}
static xcb_window_t
Find_Child_At_Pointer(xcb_connection_t * dpy, xcb_window_t win)
{
xcb_window_t child_return = XCB_WINDOW_NONE;
xcb_query_pointer_cookie_t qp_cookie;
xcb_query_pointer_reply_t *qp_reply;
qp_cookie = xcb_query_pointer (dpy, win);
qp_reply = xcb_query_pointer_reply (dpy, qp_cookie, NULL);
if (qp_reply) {
child_return = qp_reply->child;
free (qp_reply);
}
return child_return;
}
xcb_window_t
Find_Client(xcb_connection_t * dpy, xcb_window_t root, xcb_window_t subwin)
{
xcb_window_t *roots;
unsigned int i, n_roots;
xcb_window_t win;
roots = Find_Roots(dpy, root, &n_roots);
for (i = 0; i < n_roots; i++) {
if (subwin != roots[i])
continue;
win = Find_Child_At_Pointer(dpy, subwin);
if (win == XCB_WINDOW_NONE)
return subwin;
subwin = win;
break;
}
free (roots);
if (atom_wm_state == XCB_ATOM_NONE) {
atom_wm_state = Get_Atom(dpy, "WM_STATE");
if (atom_wm_state == XCB_ATOM_NONE)
return subwin;
}
if (Window_Has_Property(dpy, subwin, atom_wm_state))
return subwin;
win = Find_Client_In_Children(dpy, subwin);
if (win != XCB_WINDOW_NONE)
return win;
return subwin;
}