macOS: Take window mask into account when computing QCocoaScreen::topLevelAt

Although not explicitly documented, this is the behavior in practice
on XCB and Windows, and we rely on this behavior in our implementation
of QApplication::widgetAt(), where we punch a temporary hole in the
widget using a mask if it has Qt::WA_TransparentForMouseEvents set.

Pick-to: 6.5 6.6
Fixes: QTBUG-41696
Task-number: QTBUG-119092
Change-Id: Ie7abc31b6930ee6b56fcdf391befc625c1ddf502
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Tor Arne Vestbø 2023-11-13 16:49:25 +01:00
parent 6658ccf5a1
commit 189f9873ae
2 changed files with 39 additions and 1 deletions

View File

@ -542,7 +542,12 @@ QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const
if (!w->isVisible()) if (!w->isVisible())
return; return;
if (!QHighDpi::toNativePixels(w->geometry(), w).contains(point)) auto nativeGeometry = QHighDpi::toNativePixels(w->geometry(), w);
if (!nativeGeometry.contains(point))
return;
QRegion mask = QHighDpi::toNativeLocalPosition(w->mask(), w);
if (!mask.isEmpty() && !mask.contains(point - nativeGeometry.topLeft()))
return; return;
window = w; window = w;

View File

@ -61,6 +61,8 @@ private slots:
void staticFunctions(); void staticFunctions();
void topLevelAt();
void settableStyleHints_data(); void settableStyleHints_data();
void settableStyleHints(); // Needs to run last as it changes style hints. void settableStyleHints(); // Needs to run last as it changes style hints.
}; };
@ -1325,6 +1327,37 @@ void tst_QGuiApplication::staticFunctions()
QPixmap::defaultDepth(); QPixmap::defaultDepth();
} }
void tst_QGuiApplication::topLevelAt()
{
int argc = 1;
char *argv[] = { const_cast<char*>("tst_qguiapplication") };
QGuiApplication app(argc, argv);
QWindow bottom;
bottom.setObjectName("Bottom");
bottom.setFlag(Qt::FramelessWindowHint);
bottom.setGeometry(200, 200, 200, 200);
bottom.showNormal();
QVERIFY(QTest::qWaitForWindowExposed(&bottom));
QTRY_COMPARE(app.topLevelAt(QPoint(300, 300)), &bottom);
QWindow top;
top.setObjectName("Top");
top.setFlag(Qt::FramelessWindowHint);
top.setGeometry(200, 200, 200, 200);
top.showNormal();
QVERIFY(QTest::qWaitForWindowExposed(&top));
top.raise();
QTRY_COMPARE(app.topLevelAt(QPoint(300, 300)), &top);
if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowMasks))
QSKIP("QWindow::setMask() is not supported.");
top.setMask(QRect(0, 0, 50, 50));
QTRY_COMPARE(app.topLevelAt(QPoint(300, 300)), &bottom);
QTRY_COMPARE(app.topLevelAt(QPoint(225, 225)), &top);
}
void tst_QGuiApplication::settableStyleHints_data() void tst_QGuiApplication::settableStyleHints_data()
{ {
QTest::addColumn<bool>("appInstance"); QTest::addColumn<bool>("appInstance");