Ra'Jiska
Ra'Jiska

Reputation: 1049

X11 Retrieve Topmost Window According To An Area Position

I ma currently looking retrieve the window present at a certain position. I've already retrieved the list of windows but I'm not sure how to proceed to retrieve the topmost one.

Here is what I have accomplished so far (contains a testing main):

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>

typedef struct
{
    int x;
    int y;
    int w;
    int h;
} area_coords_t;

static inline Window get_toplevel_parent(Display * display, Window window)
{
    Window parent;
    Window root;
    Window * children;
    unsigned int num_children;

    while (1) {
        if (0 == XQueryTree(display, window, &root, &parent, &children, &num_children)) {
            fprintf(stderr, "XQueryTree error\n");
            abort(); //change to whatever error handling you prefer
        }
        if (children) { //must test for null
            XFree(children);
        }
        if (window == root || parent == root) {
            return window;
        }
        else {
            window = parent;
        }
    }
}

static inline void print_windows(Display *display, area_coords_t *area)
{
    Window *list;
    Window toplevel;
    Atom prop = XInternAtom(display, "_NET_CLIENT_LIST",False);
    Atom type;
    unsigned long len;
    XWindowAttributes attr;

    if (XGetWindowProperty(display, XDefaultRootWindow(display), prop,
        0, 1024, False, XA_WINDOW, &type, &(int) { 0 }, &len, &(unsigned long) { 0 }, (unsigned char **) &list) != Success)
        return;
    for (unsigned long it = 0; it < len; ++it)
    {
        toplevel = get_toplevel_parent(display, list[it]);
        XGetWindowAttributes(display, toplevel, &attr);
        /* Retrieve only windows in the given area */
        //if (area->x >= attr.x && area->x <= attr.x + attr.width && area->y >= attr.y && area->y <= attr.y + attr.height)
        printf("%dx%dx%dx%d\n", attr.x, attr.y, attr.width, attr.height);
    }
}

int main(void)
{
    Display *display = XOpenDisplay(NULL);
    /* Should retrieve a window occupying at least a pixel at of the bottom right part of the screen of a 1920x1080 screen */
    area_coords_t coords = { 1920 / 2, 1080 / 2, 1920 / 2, 1080 / 2 };

    print_windows(display, &coords);
    return 0;
}

The problem with that is the windows do not seem to be ordered.

How can I retrieve the topmost window to ensure I get the appropriate window for a given position ?

Upvotes: 2

Views: 703

Answers (1)

Andrew Henle
Andrew Henle

Reputation: 1

XQueryTree() returns the windows in stacking order, topmost last.

Description

The XQueryTree() function returns the root ID, the parent window ID, a pointer to the list of children windows (NULL when there are no children), and the number of children in the list for the specified window. The children are listed in current stacking order, from bottommost (first) to topmost (last). XQueryTree() returns zero if it fails and nonzero if it succeeds. To free a non-NULL children list when it is no longer needed, use XFree().

I've never used the call for this purpose, and haven't done direct X11 programming in years, but from that I'd imagine you could just loop through the returned list from querying the root window and save the window ID of any window covering your desired location to the same variable every time. Since the last one found covering that location is the topmost (at least it was when you made the call...), that would be the window ID of the visible window at that location.

Upvotes: 2

Related Questions