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
- 检查这些是否与您自己的显示区域相交。
我需要检查(在我的 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
- 检查这些是否与您自己的显示区域相交。