Xlib。检查窗口是否重叠

时间:2019-03-25 14:23:47

标签: c++ x11 xlib

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

我尝试获取窗口的WM_STATE属性,并将其与NormalState进行比较。但是,当我重叠目标窗口时,没有执行我的条件(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;
}

此代码始终返回true。

1 个答案:

答案 0 :(得分:1)

顾名思义,该属性仅表示窗口是否被隐藏(例如,因为它已最小化),这是正常的。

如果要检查窗口上方的其他窗口并隐藏其中的一部分,则必须手动进行。

例如,这将获得所有顶级窗口的列表:

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);

您将需要:

  • 找出您自己的窗口在列表中的位置。 之后之后的任何窗口都在堆叠顺序的上方。
  • 查询您上方的每个窗口的桌面(_NET_WM_DESKTOP原子),消除当前桌面上未显示的任何窗口。
  • 查询您上方每个窗口的显示状态(_NET_WM_STATE原子,在列表中寻找_NET_WM_STATE_HIDDEN原子)。
  • 查询您上方每个显示窗口的大小。如果您要考虑非矩形窗口,可以使用Shape extension
  • 检查其中任何一个是否与您自己的显示区域相交。