From fd6821740fece8650cac7494a2cffe63e2bebb9c Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 29 Jun 2015 10:25:24 +0200 Subject: Highdpi changes for Windows Adapt the Windows plugin to work with the new cross-platform high-DPI scaling. Task-number: QTBUG-38993 Task-number: QTBUG-46615 Change-Id: I108d319255925a290b75611e95ef006d4aaf7ace Reviewed-by: Lars Knoll --- .../platforms/windows/qwindowsbackingstore.cpp | 5 ++-- src/plugins/platforms/windows/qwindowsdrag.cpp | 28 ++++++++++++++++---- .../platforms/windows/qwindowsintegration.cpp | 3 ++- .../platforms/windows/qwindowskeymapper.cpp | 4 ++- src/plugins/platforms/windows/qwindowsscreen.cpp | 7 +++++ src/plugins/platforms/windows/qwindowsscreen.h | 1 + src/plugins/platforms/windows/qwindowstheme.cpp | 4 ++- src/plugins/platforms/windows/qwindowswindow.cpp | 30 +++++++++++++++++----- 8 files changed, 65 insertions(+), 17 deletions(-) (limited to 'src/plugins/platforms/windows') diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index fe56d3dddc..3f19e4401a 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -38,6 +38,7 @@ #include #include +#include #include @@ -82,8 +83,8 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, const Qt::WindowFlags flags = window->flags(); if ((flags & Qt::FramelessWindowHint) && QWindowsWindow::setWindowLayered(rw->handle(), flags, hasAlpha, rw->opacity()) && hasAlpha) { // Windows with alpha: Use blend function to update. - QRect r = window->frameGeometry(); - QPoint frameOffset(window->frameMargins().left(), window->frameMargins().top()); + QRect r = QHighDpi::toNativePixels(window->frameGeometry(), window); + QPoint frameOffset(QHighDpi::toNativePixels(QPoint(window->frameMargins().left(), window->frameMargins().top()), window)); QRect dirtyRect = br.translated(offset + frameOffset); SIZE size = {r.width(), r.height()}; diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 65ea7ea210..d24cba3c68 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -33,6 +33,7 @@ #include "qwindowsdrag.h" #include "qwindowscontext.h" +#include "qwindowsscreen.h" #ifndef QT_NO_CLIPBOARD # include "qwindowsclipboard.h" #endif @@ -50,6 +51,7 @@ #include #include #include +#include #include #include @@ -278,6 +280,13 @@ QDebug operator<<(QDebug d, const QWindowsOleDropSource::CursorEntry &e) } #endif // !QT_NO_DEBUG_OUTPUT +static qreal dragScaleFactor() +{ + const QWindowsScreenManager &screenManager = QWindowsContext::instance()->screenManager(); + const QWindowsScreen *screen = screenManager.screenAtDp(QWindowsCursor::mousePosition()); + return screen ? QHighDpiScaling::factor(screen) : qreal(1); +} + /*! \brief Blend custom pixmap with cursors. */ @@ -288,11 +297,21 @@ void QWindowsOleDropSource::createCursors() const QPixmap pixmap = drag->pixmap(); const bool hasPixmap = !pixmap.isNull(); + const qreal scaleFactor = dragScaleFactor(); + const bool scalePixmap = hasPixmap + && m_mode != TouchDrag // Touch drag: pixmap is shown in a separate QWindow, which will be scaled. + && (scaleFactor != 1 && scaleFactor != qRound(pixmap.devicePixelRatio())); + const QPixmap scaledPixmap = scalePixmap + ? pixmap.scaled((QSizeF(pixmap.size()) * scaleFactor).toSize(), + Qt::KeepAspectRatio, Qt::SmoothTransformation) + : pixmap; Qt::DropAction actions[] = { Qt::MoveAction, Qt::CopyAction, Qt::LinkAction, Qt::IgnoreAction }; int actionCount = int(sizeof(actions) / sizeof(actions[0])); if (!hasPixmap) --actionCount; // No Qt::IgnoreAction unless pixmap - const QPoint hotSpot = drag->hotSpot(); + const QPoint hotSpot = scalePixmap + ? (QPointF(drag->hotSpot()) * scaleFactor).toPoint() + : drag->hotSpot(); for (int cnum = 0; cnum < actionCount; ++cnum) { const Qt::DropAction action = actions[cnum]; QPixmap cursorPixmap = drag->dragCursor(action); @@ -312,15 +331,14 @@ void QWindowsOleDropSource::createCursors() if (hasPixmap) { const int x1 = qMin(-hotSpot.x(), 0); - const int x2 = qMax(pixmap.width() - hotSpot.x(), cursorPixmap.width()); + const int x2 = qMax(scaledPixmap.width() - hotSpot.x(), cursorPixmap.width()); const int y1 = qMin(-hotSpot.y(), 0); - const int y2 = qMax(pixmap.height() - hotSpot.y(), cursorPixmap.height()); + const int y2 = qMax(scaledPixmap.height() - hotSpot.y(), cursorPixmap.height()); QPixmap newCursor(x2 - x1 + 1, y2 - y1 + 1); newCursor.fill(Qt::transparent); QPainter p(&newCursor); - const QRect srcRect = pixmap.rect(); const QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y())); - p.drawPixmap(pmDest, pixmap, srcRect); + p.drawPixmap(pmDest, scaledPixmap); p.drawPixmap(qMax(0, hotSpot.x()),qMax(0, hotSpot.y()), cursorPixmap); newPixmap = newCursor; newHotSpot = QPoint(qMax(0, hotSpot.x()), qMax(0, hotSpot.y())); diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 26e071cba1..05c7e6b240 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -63,6 +63,7 @@ # include "qwindowssessionmanager.h" #endif #include +#include #include #include @@ -302,7 +303,7 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const { QWindowsWindowData requested; requested.flags = window->flags(); - requested.geometry = window->geometry(); + requested.geometry = QHighDpi::toNativePixels(window->geometry(), window); // Apply custom margins (see QWindowsWindow::setCustomMargins())). const QVariant customMarginsV = window->property("_q_windowsCustomMargins"); if (customMarginsV.isValid()) diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index e6fec9c8f4..3636bb7893 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #if defined(WM_APPCOMMAND) @@ -791,9 +792,10 @@ static void showSystemMenu(QWindow* w) #undef enabled #undef disabled #endif // !Q_OS_WINCE + const QPoint pos = QHighDpi::toNativePixels(topLevel->geometry().topLeft(), topLevel); const int ret = TrackPopupMenuEx(menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD, - topLevel->geometry().x(), topLevel->geometry().y(), + pos.x(), pos.y(), topLevelHwnd, 0); if (ret) diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 5863629a01..391735a035 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -287,6 +288,12 @@ QWindowsScreen *QWindowsScreen::screenOf(const QWindow *w) return 0; } +qreal QWindowsScreen::pixelDensity() const +{ + const qreal physicalDpi = m_data.geometry.width() / m_data.physicalSizeMM.width() * qreal(25.4); + return qRound(physicalDpi / 96); +} + /*! \brief Determine siblings in a virtual desktop system. diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 76161b2ae7..67e7ff644b 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -87,6 +87,7 @@ public: QImage::Format format() const Q_DECL_OVERRIDE { return m_data.format; } QSizeF physicalSize() const Q_DECL_OVERRIDE { return m_data.physicalSizeMM; } QDpi logicalDpi() const Q_DECL_OVERRIDE { return m_data.dpi; } + qreal pixelDensity() const Q_DECL_OVERRIDE; qreal devicePixelRatio() const Q_DECL_OVERRIDE { return 1.0; } qreal refreshRate() const Q_DECL_OVERRIDE { return m_data.refreshRateHz; } QString name() const Q_DECL_OVERRIDE { return m_data.name; } diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index a000f107a9..a541fd4629 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -67,6 +67,7 @@ #include #include #include +#include #include #include @@ -494,7 +495,8 @@ static QPixmap loadIconFromShell32(int resourceId, QSizeF size) QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const { - const int scaleFactor = 1; // HIGDPI Fixme: ? + const QScreen *primaryScreen = QGuiApplication::primaryScreen(); + const int scaleFactor = primaryScreen ? qRound(QHighDpiScaling::factor(primaryScreen)) : 1; const QSizeF pixmapSize = size * scaleFactor; int resourceId = -1; LPCTSTR iconName = 0; diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 78e6315705..87747a74fd 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -50,6 +50,7 @@ #include #include // QWINDOWSIZE_MAX #include +#include #include #include @@ -703,6 +704,20 @@ void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChang } } + +// Scaling helpers for size constraints. +static QSize toNativeSizeConstrained(QSize dip, const QWindow *w) +{ + if (QHighDpiScaling::isActive()) { + const qreal factor = QHighDpiScaling::factor(w); + if (dip.width() > 0 && dip.width() < QWINDOWSIZE_MAX) + dip.rwidth() *= factor; + if (dip.height() > 0 && dip.height() < QWINDOWSIZE_MAX) + dip.rheight() *= factor; + } + return dip; +} + /*! \class QWindowsGeometryHint \brief Stores geometry constraints and provides utility functions. @@ -715,8 +730,8 @@ void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChang */ QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w, const QMargins &cm) : - minimumSize(w->minimumSize()), - maximumSize(w->maximumSize()), + minimumSize(toNativeSizeConstrained(w->minimumSize(), w)), + maximumSize(toNativeSizeConstrained(w->maximumSize(), w)), customMargins(cm) { } @@ -1621,7 +1636,9 @@ void QWindowsWindow::setWindowState(Qt::WindowState state) bool QWindowsWindow::isFullScreen_sys() const { - return window()->isTopLevel() && geometry_sys() == window()->screen()->geometry(); + const QWindow *w = window(); + return w->isTopLevel() + && geometry_sys() == QHighDpi::toNativePixels(w->screen()->geometry(), w); } /*! @@ -1691,7 +1708,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) // Use geometry of QWindow::screen() within creation or the virtual screen the // window is in (QTBUG-31166, QTBUG-30724). const QScreen *screen = window()->screen(); - const QRect r = screen->geometry(); + const QRect r = QHighDpi::toNativePixels(screen->geometry(), window()); const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; const bool wasSync = testFlag(SynchronousGeometryChangeEvent); setFlag(SynchronousGeometryChangeEvent); @@ -1808,8 +1825,7 @@ bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow * const QRect suggestedFrameGeometry(windowPos->x, windowPos->y, windowPos->cx, windowPos->cy); const QRect suggestedGeometry = suggestedFrameGeometry - margins; - const QRectF correctedGeometryF = - qt_window_private(const_cast(qWindow))->closestAcceptableGeometry(suggestedGeometry); + const QRectF correctedGeometryF = qWindow->handle()->windowClosestAcceptableGeometry(suggestedGeometry); if (!correctedGeometryF.isValid()) return false; const QRect correctedFrameGeometry = correctedGeometryF.toRect() + margins; @@ -2048,7 +2064,7 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re const bool fixedHeight = minimumSize.height() == maximumSize.height(); if (!fixedWidth && !fixedHeight) return false; - const QPoint localPos = w->mapFromGlobal(globalPos); + const QPoint localPos = w->mapFromGlobal(QHighDpi::fromNativePixels(globalPos, w)); const QSize size = w->size(); if (fixedHeight) { if (localPos.y() >= size.height()) { -- cgit v1.2.3