Fix QWindow::mapToGlobal()/mapFromGlobal() for multi-screen windows
Make these functions handle the case where a window spans multiple screens, and high-DPI scaling is enabled, and the local position (in the window) is not on the window primary screen (as returned by QWindow::screen()). This is done by detecting the case, and then calculating the correct position using the native coordinate system. [ChangeLog][QtGui] QWindow::mapToGlobal()/mapFromGlobal() now handle windows spanning screens correctly. Done-with: Friedemann Kleint<Friedemann.Kleint@qt.io> Task-number: QTBUG-73231 Change-Id: I3c31b741344d9e85e4f5d9e60bae75acce2db741 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
This commit is contained in:
parent
3da9d8a4fe
commit
3af7b27917
@ -41,7 +41,9 @@
|
||||
#include "qguiapplication.h"
|
||||
#include "qscreen.h"
|
||||
#include "qplatformintegration.h"
|
||||
#include "qplatformwindow.h"
|
||||
#include "private/qscreen_p.h"
|
||||
#include <private/qguiapplication_p.h>
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
|
||||
@ -376,6 +378,46 @@ QPoint QHighDpiScaling::mapPositionFromNative(const QPoint &pos, const QPlatform
|
||||
return (pos - topLeft) / scaleFactor + topLeft;
|
||||
}
|
||||
|
||||
QPoint QHighDpiScaling::mapPositionToGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window)
|
||||
{
|
||||
QPoint globalPosCandidate = pos + windowGlobalPosition;
|
||||
if (QGuiApplicationPrivate::screen_list.size() <= 1)
|
||||
return globalPosCandidate;
|
||||
|
||||
// The global position may be outside device independent screen geometry
|
||||
// in cases where a window spans screens. Detect this case and map via
|
||||
// native coordinates to the correct screen.
|
||||
auto currentScreen = window->screen();
|
||||
if (currentScreen && !currentScreen->geometry().contains(globalPosCandidate)) {
|
||||
auto nativeGlobalPos = QHighDpi::toNativePixels(globalPosCandidate, currentScreen);
|
||||
if (auto actualPlatformScreen = currentScreen->handle()->screenForPosition(nativeGlobalPos))
|
||||
return QHighDpi::fromNativePixels(nativeGlobalPos, actualPlatformScreen->screen());
|
||||
}
|
||||
|
||||
return globalPosCandidate;
|
||||
}
|
||||
|
||||
QPoint QHighDpiScaling::mapPositionFromGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window)
|
||||
{
|
||||
QPoint windowPosCandidate = pos - windowGlobalPosition;
|
||||
if (QGuiApplicationPrivate::screen_list.size() <= 1)
|
||||
return windowPosCandidate;
|
||||
|
||||
// Device independent global (screen) space may discontiguous when high-dpi scaling
|
||||
// is active. This means that the normal subtracting of the window global position from the
|
||||
// position-to-be-mapped may not work in cases where a window spans multiple screens.
|
||||
// Map both positions to native global space (using the correct screens), subtract there,
|
||||
// and then map the difference back using the scale factor for the window.
|
||||
QScreen *posScreen = QGuiApplication::screenAt(pos);
|
||||
if (posScreen && posScreen != window->screen()) {
|
||||
QPoint nativePos = QHighDpi::toNativePixels(pos, posScreen);
|
||||
QPoint windowNativePos = window->handle()->geometry().topLeft();
|
||||
return QHighDpi::fromNativeLocalPosition(nativePos - windowNativePos, window);
|
||||
}
|
||||
|
||||
return windowPosCandidate;
|
||||
}
|
||||
|
||||
qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen)
|
||||
{
|
||||
qreal factor = qreal(1.0);
|
||||
|
@ -83,8 +83,10 @@ public:
|
||||
static qreal factor(const QPlatformScreen *platformScreen);
|
||||
static QPoint origin(const QScreen *screen);
|
||||
static QPoint origin(const QPlatformScreen *platformScreen);
|
||||
static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen);
|
||||
static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen);
|
||||
static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen);
|
||||
static QPoint mapPositionToGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window);
|
||||
static QPoint mapPositionFromGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window);
|
||||
static QDpi logicalDpi();
|
||||
|
||||
private:
|
||||
|
@ -1670,9 +1670,9 @@ void QWindow::setGeometry(const QRect &rect)
|
||||
chicken and egg problem here: we cannot convert to native coordinates
|
||||
before we know which screen we are on.
|
||||
*/
|
||||
QScreen *QWindowPrivate::screenForGeometry(const QRect &newGeometry)
|
||||
QScreen *QWindowPrivate::screenForGeometry(const QRect &newGeometry) const
|
||||
{
|
||||
Q_Q(QWindow);
|
||||
Q_Q(const QWindow);
|
||||
QScreen *currentScreen = q->screen();
|
||||
QScreen *fallback = currentScreen;
|
||||
QPoint center = newGeometry.center();
|
||||
@ -2542,6 +2542,10 @@ QPoint QWindow::mapToGlobal(const QPoint &pos) const
|
||||
&& (d->platformWindow->isForeignWindow() || d->platformWindow->isEmbedded())) {
|
||||
return QHighDpi::fromNativeLocalPosition(d->platformWindow->mapToGlobal(QHighDpi::toNativeLocalPosition(pos, this)), this);
|
||||
}
|
||||
|
||||
if (QHighDpiScaling::isActive())
|
||||
return QHighDpiScaling::mapPositionToGlobal(pos, d->globalPosition(), this);
|
||||
|
||||
return pos + d->globalPosition();
|
||||
}
|
||||
|
||||
@ -2562,6 +2566,10 @@ QPoint QWindow::mapFromGlobal(const QPoint &pos) const
|
||||
&& (d->platformWindow->isForeignWindow() || d->platformWindow->isEmbedded())) {
|
||||
return QHighDpi::fromNativeLocalPosition(d->platformWindow->mapFromGlobal(QHighDpi::toNativeLocalPosition(pos, this)), this);
|
||||
}
|
||||
|
||||
if (QHighDpiScaling::isActive())
|
||||
return QHighDpiScaling::mapPositionFromGlobal(pos, d->globalPosition(), this);
|
||||
|
||||
return pos - d->globalPosition();
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,7 @@ public:
|
||||
void connectToScreen(QScreen *topLevelScreen);
|
||||
void disconnectFromScreen();
|
||||
void emitScreenChangedRecursion(QScreen *newScreen);
|
||||
QScreen *screenForGeometry(const QRect &rect);
|
||||
QScreen *screenForGeometry(const QRect &rect) const;
|
||||
|
||||
virtual void clearFocusObject();
|
||||
virtual QRectF closestAcceptableGeometry(const QRectF &rect) const;
|
||||
|
Loading…
Reference in New Issue
Block a user