Add IsOverlapped method
This commit is contained in:
parent
a37e28d2f3
commit
50a0e7da64
6 changed files with 367 additions and 1 deletions
|
|
@ -33,6 +33,259 @@ namespace {
|
||||||
constexpr auto kXCBFrameExtentsAtomName = "_GTK_FRAME_EXTENTS"_cs;
|
constexpr auto kXCBFrameExtentsAtomName = "_GTK_FRAME_EXTENTS"_cs;
|
||||||
|
|
||||||
#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION
|
#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||||
|
std::optional<bool> XCBWindowMapped(xcb_window_t window) {
|
||||||
|
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||||
|
if (!connection) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto cookie = xcb_get_window_attributes(connection, window);
|
||||||
|
const auto reply = xcb_get_window_attributes_reply(
|
||||||
|
connection,
|
||||||
|
cookie,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
if (!reply) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto guard = gsl::finally([&] { free(reply); });
|
||||||
|
return reply->map_state == XCB_MAP_STATE_VIEWABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<bool> XCBWindowHidden(xcb_window_t window) {
|
||||||
|
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||||
|
if (!connection) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto stateAtom = base::Platform::XCB::GetAtom(
|
||||||
|
connection,
|
||||||
|
"_NET_WM_STATE");
|
||||||
|
|
||||||
|
const auto stateHiddenAtom = base::Platform::XCB::GetAtom(
|
||||||
|
connection,
|
||||||
|
"_NET_WM_STATE_HIDDEN");
|
||||||
|
|
||||||
|
if (!stateAtom.has_value() || !stateHiddenAtom.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto cookie = xcb_get_property(
|
||||||
|
connection,
|
||||||
|
false,
|
||||||
|
window,
|
||||||
|
*stateAtom,
|
||||||
|
XCB_ATOM_ATOM,
|
||||||
|
0,
|
||||||
|
1024);
|
||||||
|
|
||||||
|
const auto reply = xcb_get_property_reply(
|
||||||
|
connection,
|
||||||
|
cookie,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
if (!reply) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto guard = gsl::finally([&] { free(reply); });
|
||||||
|
if (reply->type != XCB_ATOM_ATOM || reply->format != 32) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto atomsStart = reinterpret_cast<xcb_atom_t*>(
|
||||||
|
xcb_get_property_value(reply));
|
||||||
|
|
||||||
|
const auto states = std::vector<xcb_atom_t>(
|
||||||
|
atomsStart,
|
||||||
|
atomsStart + reply->length);
|
||||||
|
|
||||||
|
return ranges::contains(states, *stateHiddenAtom);
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect XCBWindowGeometry(xcb_window_t window) {
|
||||||
|
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||||
|
if (!connection) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto cookie = xcb_get_geometry(connection, window);
|
||||||
|
const auto reply = xcb_get_geometry_reply(
|
||||||
|
connection,
|
||||||
|
cookie,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
if (!reply) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto guard = gsl::finally([&] { free(reply); });
|
||||||
|
return QRect(reply->x, reply->y, reply->width, reply->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<uint> XCBCurrentWorkspace() {
|
||||||
|
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||||
|
if (!connection) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto root = base::Platform::XCB::GetRootWindowFromQt();
|
||||||
|
if (!root.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto currentDesktopAtom = base::Platform::XCB::GetAtom(
|
||||||
|
connection,
|
||||||
|
"_NET_CURRENT_DESKTOP");
|
||||||
|
|
||||||
|
if (!currentDesktopAtom.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto cookie = xcb_get_property(
|
||||||
|
connection,
|
||||||
|
false,
|
||||||
|
*root,
|
||||||
|
*currentDesktopAtom,
|
||||||
|
XCB_ATOM_CARDINAL,
|
||||||
|
0,
|
||||||
|
1024);
|
||||||
|
|
||||||
|
const auto reply = xcb_get_property_reply(
|
||||||
|
connection,
|
||||||
|
cookie,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
if (!reply) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto guard = gsl::finally([&] { free(reply); });
|
||||||
|
return (reply->type == XCB_ATOM_CARDINAL)
|
||||||
|
? std::make_optional(
|
||||||
|
*reinterpret_cast<ulong*>(xcb_get_property_value(reply)))
|
||||||
|
: std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<uint> XCBWindowWorkspace(xcb_window_t window) {
|
||||||
|
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||||
|
if (!connection) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto desktopAtom = base::Platform::XCB::GetAtom(
|
||||||
|
connection,
|
||||||
|
"_NET_WM_DESKTOP");
|
||||||
|
|
||||||
|
if (!desktopAtom.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto cookie = xcb_get_property(
|
||||||
|
connection,
|
||||||
|
false,
|
||||||
|
window,
|
||||||
|
*desktopAtom,
|
||||||
|
XCB_ATOM_CARDINAL,
|
||||||
|
0,
|
||||||
|
1024);
|
||||||
|
|
||||||
|
const auto reply = xcb_get_property_reply(
|
||||||
|
connection,
|
||||||
|
cookie,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
if (!reply) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto guard = gsl::finally([&] { free(reply); });
|
||||||
|
return (reply->type == XCB_ATOM_CARDINAL)
|
||||||
|
? std::make_optional(
|
||||||
|
*reinterpret_cast<ulong*>(xcb_get_property_value(reply)))
|
||||||
|
: std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<bool> XCBIsOverlapped(
|
||||||
|
not_null<QWidget*> widget,
|
||||||
|
const QRect &rect) {
|
||||||
|
const auto window = widget->window()->winId();
|
||||||
|
Expects(window != XCB_WINDOW_NONE);
|
||||||
|
|
||||||
|
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||||
|
if (!connection) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto root = base::Platform::XCB::GetRootWindowFromQt();
|
||||||
|
if (!root.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto windowWorkspace = XCBWindowWorkspace(
|
||||||
|
window);
|
||||||
|
|
||||||
|
const auto currentWorkspace = XCBCurrentWorkspace();
|
||||||
|
|
||||||
|
if (windowWorkspace.has_value()
|
||||||
|
&& currentWorkspace.has_value()
|
||||||
|
&& *windowWorkspace != *currentWorkspace
|
||||||
|
&& *windowWorkspace != 0xFFFFFFFF) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto cookie = xcb_query_tree(connection, *root);
|
||||||
|
const auto reply = xcb_query_tree_reply(connection, cookie, nullptr);
|
||||||
|
if (!reply) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto guard = gsl::finally([&] { free(reply); });
|
||||||
|
|
||||||
|
const auto tree = xcb_query_tree_children(reply);
|
||||||
|
auto aboveTheWindow = false;
|
||||||
|
|
||||||
|
for (auto i = 0, l = xcb_query_tree_children_length(reply); i < l; ++i) {
|
||||||
|
if (window == tree[i]) {
|
||||||
|
aboveTheWindow = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aboveTheWindow) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto geometry = XCBWindowGeometry(tree[i]);
|
||||||
|
if (!rect.intersects(geometry)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto workspace = XCBWindowWorkspace(tree[i]);
|
||||||
|
if (workspace.has_value()
|
||||||
|
&& windowWorkspace.has_value()
|
||||||
|
&& *workspace != *windowWorkspace
|
||||||
|
&& *workspace != 0xFFFFFFFF) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto mapped = XCBWindowMapped(tree[i]);
|
||||||
|
if (mapped.has_value() && !*mapped) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto hidden = XCBWindowHidden(tree[i]);
|
||||||
|
if (hidden.has_value()
|
||||||
|
&& *hidden) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool SetXCBFrameExtents(QWindow *window, const QMargins &extents) {
|
bool SetXCBFrameExtents(QWindow *window, const QMargins &extents) {
|
||||||
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||||
if (!connection) {
|
if (!connection) {
|
||||||
|
|
@ -189,12 +442,24 @@ void ClearTransientParent(not_null<QWidget*> widget) {
|
||||||
if (::Platform::IsX11()) {
|
if (::Platform::IsX11()) {
|
||||||
xcb_delete_property(
|
xcb_delete_property(
|
||||||
base::Platform::XCB::GetConnectionFromQt(),
|
base::Platform::XCB::GetConnectionFromQt(),
|
||||||
widget->windowHandle()->winId(),
|
widget->winId(),
|
||||||
XCB_ATOM_WM_TRANSIENT_FOR);
|
XCB_ATOM_WM_TRANSIENT_FOR);
|
||||||
}
|
}
|
||||||
#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION
|
#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<bool> IsOverlapped(
|
||||||
|
not_null<QWidget*> widget,
|
||||||
|
const QRect &rect) {
|
||||||
|
#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||||
|
if (::Platform::IsX11()) {
|
||||||
|
return XCBIsOverlapped(widget, rect);
|
||||||
|
}
|
||||||
|
#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
bool WindowExtentsSupported() {
|
bool WindowExtentsSupported() {
|
||||||
#ifdef DESKTOP_APP_QT_PATCHED
|
#ifdef DESKTOP_APP_QT_PATCHED
|
||||||
if (::Platform::IsWayland()) {
|
if (::Platform::IsWayland()) {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include "ui/platform/mac/ui_utility_mac.h"
|
#include "ui/platform/mac/ui_utility_mac.h"
|
||||||
|
|
||||||
#include "ui/integration.h"
|
#include "ui/integration.h"
|
||||||
|
#include "base/qt_adapters.h"
|
||||||
|
|
||||||
#include <QtGui/QPainter>
|
#include <QtGui/QPainter>
|
||||||
#include <QtGui/QtEvents>
|
#include <QtGui/QtEvents>
|
||||||
|
|
@ -99,6 +100,12 @@ void DrainMainQueue() {
|
||||||
void IgnoreAllActivation(not_null<QWidget*> widget) {
|
void IgnoreAllActivation(not_null<QWidget*> widget) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<bool> IsOverlapped(
|
||||||
|
not_null<QWidget*> widget,
|
||||||
|
const QRect &rect) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
TitleControls::Layout TitleControlsLayout() {
|
TitleControls::Layout TitleControlsLayout() {
|
||||||
return TitleControls::Layout{
|
return TitleControls::Layout{
|
||||||
.left = {
|
.left = {
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,10 @@ void BringToBack(not_null<QWidget*> widget);
|
||||||
void IgnoreAllActivation(not_null<QWidget*> widget);
|
void IgnoreAllActivation(not_null<QWidget*> widget);
|
||||||
void ClearTransientParent(not_null<QWidget*> widget);
|
void ClearTransientParent(not_null<QWidget*> widget);
|
||||||
|
|
||||||
|
[[nodiscard]] std::optional<bool> IsOverlapped(
|
||||||
|
not_null<QWidget*> widget,
|
||||||
|
const QRect &rect);
|
||||||
|
|
||||||
[[nodiscard]] constexpr bool UseMainQueueGeneric();
|
[[nodiscard]] constexpr bool UseMainQueueGeneric();
|
||||||
void DrainMainQueue(); // Needed only if UseMainQueueGeneric() is false.
|
void DrainMainQueue(); // Needed only if UseMainQueueGeneric() is false.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,11 @@
|
||||||
#include <QtWidgets/QApplication>
|
#include <QtWidgets/QApplication>
|
||||||
#include <QtGui/QWindow>
|
#include <QtGui/QWindow>
|
||||||
|
|
||||||
|
#include <wrl/client.h>
|
||||||
|
#include <Shobjidl.h>
|
||||||
|
|
||||||
|
using namespace Microsoft::WRL;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
|
|
@ -45,6 +50,55 @@ void IgnoreAllActivation(not_null<QWidget*> widget) {
|
||||||
ShowWindow(handle, SW_SHOW);
|
ShowWindow(handle, SW_SHOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<bool> IsOverlapped(
|
||||||
|
not_null<QWidget*> widget,
|
||||||
|
const QRect &rect) {
|
||||||
|
const auto handle = reinterpret_cast<HWND>(widget->window()->winId());
|
||||||
|
Expects(handle != nullptr);
|
||||||
|
|
||||||
|
ComPtr<IVirtualDesktopManager> virtualDesktopManager;
|
||||||
|
HRESULT hr = CoCreateInstance(
|
||||||
|
CLSID_VirtualDesktopManager,
|
||||||
|
nullptr,
|
||||||
|
CLSCTX_ALL,
|
||||||
|
IID_PPV_ARGS(&virtualDesktopManager));
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
BOOL isCurrent;
|
||||||
|
hr = virtualDesktopManager->IsWindowOnCurrentVirtualDesktop(
|
||||||
|
handle,
|
||||||
|
&isCurrent);
|
||||||
|
if (SUCCEEDED(hr) && !isCurrent) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<HWND> visited;
|
||||||
|
const RECT nativeRect{
|
||||||
|
rect.left(),
|
||||||
|
rect.top(),
|
||||||
|
rect.right(),
|
||||||
|
rect.bottom(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto curHandle = handle;
|
||||||
|
curHandle != nullptr && !ranges::contains(visited, curHandle);
|
||||||
|
curHandle = GetWindow(curHandle, GW_HWNDPREV)) {
|
||||||
|
visited.push_back(curHandle);
|
||||||
|
if (curHandle == handle) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
RECT testRect, intersection;
|
||||||
|
if (IsWindowVisible(curHandle)
|
||||||
|
&& GetWindowRect(curHandle, &testRect)
|
||||||
|
&& IntersectRect(&intersection, &nativeRect, &testRect)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ShowWindowMenu(QWindow *window) {
|
bool ShowWindowMenu(QWindow *window) {
|
||||||
const auto pos = QCursor::pos();
|
const auto pos = QCursor::pos();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,13 @@
|
||||||
//
|
//
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
|
|
||||||
|
#include "ui/platform/ui_platform_utility.h"
|
||||||
#include "ui/style/style_core.h"
|
#include "ui/style/style_core.h"
|
||||||
|
|
||||||
#include <QtWidgets/QApplication>
|
#include <QtWidgets/QApplication>
|
||||||
#include <QtGui/QWindow>
|
#include <QtGui/QWindow>
|
||||||
#include <QtGui/QtEvents>
|
#include <QtGui/QtEvents>
|
||||||
|
#include <private/qhighdpiscaling_p.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
|
@ -179,6 +181,36 @@ QPixmap PixmapFromImage(QImage &&image) {
|
||||||
return QPixmap::fromImage(std::move(image), Qt::ColorOnly);
|
return QPixmap::fromImage(std::move(image), Qt::ColorOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsContentVisible(
|
||||||
|
not_null<QWidget*> widget,
|
||||||
|
const QRect &rect) {
|
||||||
|
Expects(widget->window()->windowHandle());
|
||||||
|
|
||||||
|
const auto activeOrNotOverlapped = [&] {
|
||||||
|
if (const auto active = widget->isActiveWindow()) {
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto mappedRect = QHighDpi::toNativePixels(
|
||||||
|
rect.isNull()
|
||||||
|
? QRect(
|
||||||
|
widget->mapToGlobal(QPoint()),
|
||||||
|
widget->mapToGlobal(
|
||||||
|
QPoint(widget->width(), widget->height())))
|
||||||
|
: QRect(
|
||||||
|
widget->mapToGlobal(rect.topLeft()),
|
||||||
|
widget->mapToGlobal(rect.bottomRight())),
|
||||||
|
widget->window()->windowHandle());
|
||||||
|
|
||||||
|
const auto overlapped = Platform::IsOverlapped(widget, mappedRect);
|
||||||
|
return overlapped.has_value() && !*overlapped;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return activeOrNotOverlapped
|
||||||
|
&& widget->isVisible()
|
||||||
|
&& !widget->window()->isMinimized();
|
||||||
|
}
|
||||||
|
|
||||||
void DisableCustomScaling() {
|
void DisableCustomScaling() {
|
||||||
qunsetenv("QT_DEVICE_PIXEL_RATIO");
|
qunsetenv("QT_DEVICE_PIXEL_RATIO");
|
||||||
qunsetenv("QT_SCALE_FACTOR");
|
qunsetenv("QT_SCALE_FACTOR");
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,10 @@ QPointer<const Widget> MakeWeak(not_null<const Widget*> object) {
|
||||||
|
|
||||||
[[nodiscard]] QPixmap PixmapFromImage(QImage &&image);
|
[[nodiscard]] QPixmap PixmapFromImage(QImage &&image);
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsContentVisible(
|
||||||
|
not_null<QWidget*> widget,
|
||||||
|
const QRect &rect = QRect());
|
||||||
|
|
||||||
void DisableCustomScaling();
|
void DisableCustomScaling();
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue