Xlib。检查 window 是否重叠

Xlib. Check if window is overlapped

我需要检查(在我的 C++ 应用程序中)应用程序的 window 是否与另一个 window 重叠(部分或完全)。我如何使用 xlib 获取此信息?

我尝试获取 window 的 WM_STATE 属性 并将其与 NormalState 进行比较。但是,当我重叠目标 window 时,我的条件 (state != NormalState) 没有被执行。我还尝试将 _NET_WM_STATE 属性 与 _NET_WM_STATE_HIDDEN 进行比较,但此方法没有给出所需的结果。

我尝试实施 spectras 解决方案建议的,现在它看起来像工作变体(注意:GetWindowProperty 是我对相应 Xlib 函数的包装):

bool ApplicationHelper::IsWindowOverlapped(const void* hWnd, _XDisplay* pd)
{
    Display* pDisplay = pd == nullptr ? XOpenDisplay(nullptr) : pd;
    if(pDisplay == nullptr)
    {
        return true;
    }
    auto root = XDefaultRootWindow(pDisplay);
    Window parent;
    /*Window* windowList;
    unsigned nchildren;
    if (!XQueryTree(pDisplay, root, &root, &parent, &windowList, &nchildren))
    {
        if(pd == nullptr)
        {
            XCloseDisplay(pDisplay);
        }
        return true;
    }*/

    Atom propCleints = XInternAtom(pDisplay, "_NET_CLIENT_LIST_STACKING", True);
    unsigned long ulBytesReturned = 0;
    Window *windowList = (Window *)GetWindowProperty(pDisplay, root, propCleints, &ulBytesReturned);
    unsigned long nchildren = ulBytesReturned / sizeof(Window);
    int32_t actualDesktop = GetWindowDesktop(pDisplay, (TWindow) hWnd);

    WindowRect targetWindowRect;
    GetWindowRect(hWnd, targetWindowRect, pDisplay);
    GdkRectangle targetGdkRect;
    targetGdkRect.x = targetWindowRect.x;
    targetGdkRect.y = targetWindowRect.y;
    targetGdkRect.width = targetWindowRect.width;
    targetGdkRect.height = targetWindowRect.height;
    bool handleWindow = false;
    bool res = false;
    for (unsigned long i = 0; i < nchildren; ++i)
    {
        auto window = windowList[i];
        if((Window)hWnd == window)
        {
            handleWindow = true;
            continue;
        }
        if(handleWindow)
        {
            if((GetWindowDesktop(pDisplay, window) != actualDesktop) || IsWindowHidden((void*)window, pDisplay))
            {
                continue;
            }
            else
            {
                WindowRect rc;
                GetWindowRect((void*)window, rc, pDisplay);
                GdkRectangle gdkRect;
                gdkRect.x = rc.x;
                gdkRect.y = rc.y;
                gdkRect.width = rc.width;
                gdkRect.height = rc.height;
                if(gdk_rectangle_intersect(&targetGdkRect, &gdkRect, nullptr))
                {
                    res = true;
                    break;
                }
            }
        }
    }
    XFree(windowList);
    if(pd == nullptr)
    {
        XCloseDisplay(pDisplay);
    }

    return res;
}

此代码总是 returns 正确。

正常的,正如它的名字所说,属性 只表示 window 是否被隐藏(例如因为它被最小化)。

如果您想检查其他 windows 在您的上方并隐藏其中的一部分,您必须手动进行。

例如,这会获取所有顶级 windows:

的列表
auto root = XDefaultRootWindow(display);
Window parent;
Window * children;
unsigned nchildren;
if (!XQueryTree(display, root, &root, &parent, &children, &nchildren)) {
    std::cout <<"Failed to query top level windows list\n";
    return 1;
}

for (unsigned idx = 0; idx < nchildren; ++idx) {
    auto window = children[idx];
    // do something with window
}

XFree(children);

您将需要:

  • 找出您自己的 window 在列表中的位置。在 之后 的任何 window 在堆叠顺序中位于上方。
  • 查询你上面每个window的桌面(_NET_WM_DESKTOP原子),去掉当前桌面上没有显示的window。
  • 查询你上面每个window的显示状态(_NET_WM_STATE原子,在列表中寻找_NET_WM_STATE_HIDDEN原子)。
  • 查询上面显示的每个 window 的大小。如果您想考虑非矩形 windows
  • ,可能会使用 Shape extension
  • 检查这些是否与您自己的显示区域相交。