From c47b04696a9d1dab04c4a59ed9ce4c28aa00fe98 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 28 Jul 2014 14:34:50 +0200 Subject: Add devicePixelRatio support to the Windows QPA plugin. This adds support for the environment variable QT_DEVICE_PIXEL_RATIO for the Windows platform plugin. Task-number: QTBUG-38993 Task-number: QTBUG-38858 Change-Id: I6831eb6d3a09a80be7bbef46395e91531b61cc50 Reviewed-by: Alessandro Portale Reviewed-by: Paul Olav Tvete --- .../platforms/windows/qwindowsbackingstore.cpp | 38 ++++--- .../platforms/windows/qwindowsbackingstore.h | 8 +- src/plugins/platforms/windows/qwindowscontext.cpp | 5 +- src/plugins/platforms/windows/qwindowsdrag.cpp | 27 +++-- .../platforms/windows/qwindowsinputcontext.cpp | 6 +- .../platforms/windows/qwindowsintegration.cpp | 11 +- .../platforms/windows/qwindowskeymapper.cpp | 6 +- .../platforms/windows/qwindowsmousehandler.cpp | 24 +++-- .../platforms/windows/qwindowsnativeimage.h | 2 + src/plugins/platforms/windows/qwindowsscaling.cpp | 79 ++++++++++++++ src/plugins/platforms/windows/qwindowsscaling.h | 114 +++++++++++++++++++++ src/plugins/platforms/windows/qwindowsscreen.cpp | 86 +++++++++++----- src/plugins/platforms/windows/qwindowsscreen.h | 17 ++- .../platforms/windows/qwindowstabletsupport.cpp | 10 +- src/plugins/platforms/windows/qwindowswindow.cpp | 71 +++++++------ src/plugins/platforms/windows/qwindowswindow.h | 30 ++++-- src/plugins/platforms/windows/windows.pri | 6 +- 17 files changed, 420 insertions(+), 120 deletions(-) create mode 100644 src/plugins/platforms/windows/qwindowsscaling.cpp create mode 100644 src/plugins/platforms/windows/qwindowsscaling.h (limited to 'src/plugins/platforms/windows') diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index 34a9c1df5f..40d1108f60 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -43,6 +43,7 @@ #include "qwindowswindow.h" #include "qwindowsnativeimage.h" #include "qwindowscontext.h" +#include "qwindowsscaling.h" #include #include @@ -75,12 +76,10 @@ QPaintDevice *QWindowsBackingStore::paintDevice() return &m_image->image(); } -void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, - const QPoint &offset) +void QWindowsBackingStore::flushDp(QWindow *window, const QRect &br, const QPoint &offset) { Q_ASSERT(window); - const QRect br = region.boundingRect(); if (QWindowsContext::verbose > 1) qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window << offset << br; QWindowsWindow *rw = QWindowsWindow::baseWindowOf(window); @@ -90,8 +89,9 @@ 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()); + const QMargins marginsDP = rw->frameMarginsDp(); + const QRect r = rw->geometryDp() + marginsDP; + const QPoint frameOffset(marginsDP.left(), marginsDP.top()); QRect dirtyRect = br.translated(offset + frameOffset); SIZE size = {r.width(), r.height()}; @@ -135,14 +135,15 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, } } -void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) +void QWindowsBackingStore::resize(const QSize &sizeDip, const QRegion ®ionDip) { + const QSize size = sizeDip * QWindowsScaling::factor(); if (m_image.isNull() || m_image->image().size() != size) { #ifndef QT_NO_DEBUG_OUTPUT if (QWindowsContext::verbose && lcQpaBackingStore().isDebugEnabled()) { qCDebug(lcQpaBackingStore) - << __FUNCTION__ << ' ' << window() << ' ' << size << ' ' << region - << " from: " << (m_image.isNull() ? QSize() : m_image->image().size()); + << __FUNCTION__ << ' ' << window() << ' ' << size << ' ' << sizeDip << ' ' + << regionDip << " from: " << (m_image.isNull() ? QSize() : m_image->image().size()); } #endif const QImage::Format format = window()->format().hasAlpha() ? @@ -151,10 +152,10 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) QWindowsNativeImage *oldwni = m_image.data(); QWindowsNativeImage *newwni = new QWindowsNativeImage(size.width(), size.height(), format); - if (oldwni && !region.isEmpty()) { + if (oldwni && !regionDip.isEmpty()) { const QImage &oldimg(oldwni->image()); QImage &newimg(newwni->image()); - QRegion staticRegion(region); + QRegion staticRegion = QWindowsScaling::mapToNative(regionDip); staticRegion &= QRect(0, 0, oldimg.width(), oldimg.height()); staticRegion &= QRect(0, 0, newimg.width(), newimg.height()); QPainter painter(&newimg); @@ -163,35 +164,38 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) painter.drawImage(rect, oldimg, rect); } + if (QWindowsScaling::isActive()) + newwni->setDevicePixelRatio(QWindowsScaling::factor()); m_image.reset(newwni); } } Q_GUI_EXPORT void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); -bool QWindowsBackingStore::scroll(const QRegion &area, int dx, int dy) +bool QWindowsBackingStore::scroll(const QRegion &areaDip, int dxDip, int dyDip) { if (m_image.isNull() || m_image->image().isNull()) return false; - const QVector rects = area.rects(); + const QPoint dp = QPoint(dxDip, dyDip) * QWindowsScaling::factor(); + const QVector rects = areaDip.rects(); for (int i = 0; i < rects.size(); ++i) - qt_scrollRectInImage(m_image->image(), rects.at(i), QPoint(dx, dy)); + qt_scrollRectInImage(m_image->image(), QWindowsScaling::mapToNative(rects.at(i)), dp); return true; } -void QWindowsBackingStore::beginPaint(const QRegion ®ion) +void QWindowsBackingStore::beginPaint(const QRegion ®ionDip) { if (QWindowsContext::verbose > 1) - qCDebug(lcQpaBackingStore) <<__FUNCTION__ << region; + qCDebug(lcQpaBackingStore) <<__FUNCTION__ << regionDip; if (m_image->image().hasAlphaChannel()) { QPainter p(&m_image->image()); p.setCompositionMode(QPainter::CompositionMode_Source); const QColor blank = Qt::transparent; - foreach (const QRect &r, region.rects()) - p.fillRect(r, blank); + foreach (const QRect &r, regionDip.rects()) + p.fillRect(QWindowsScaling::mapToNative(r), blank); } } diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h index e19b8a4db1..9c9500dabb 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.h +++ b/src/plugins/platforms/windows/qwindowsbackingstore.h @@ -43,6 +43,7 @@ #define QWINDOWSBACKINGSTORE_H #include "qtwindows_additional.h" +#include "qwindowsscaling.h" #include #include @@ -60,7 +61,12 @@ public: ~QWindowsBackingStore(); QPaintDevice *paintDevice() Q_DECL_OVERRIDE; - void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE + { + flushDp(window, QWindowsScaling::mapToNative(region.boundingRect()), + offset * QWindowsScaling::factor()); + } + void flushDp(QWindow *window, const QRect &boundingRect, const QPoint &offset); void resize(const QSize &size, const QRegion &r) Q_DECL_OVERRIDE; bool scroll(const QRegion &area, int dx, int dy) Q_DECL_OVERRIDE; void beginPaint(const QRegion &) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index d4c9646b17..b6a9f28aed 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -59,6 +59,7 @@ #endif #include "qwindowsscreen.h" #include "qwindowstheme.h" +#include "qwindowsscaling.h" #include #include @@ -1212,7 +1213,9 @@ bool QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg) } } - QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, pos, globalPos, + QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, + pos / QWindowsScaling::factor(), + globalPos / QWindowsScaling::factor(), QWindowsKeyMapper::queryKeyboardModifiers()); return true; } diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 716d892472..e1b4aca0c4 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -41,6 +41,7 @@ #include "qwindowsdrag.h" #include "qwindowscontext.h" +#include "qwindowsscaling.h" #ifndef QT_NO_CLIPBOARD # include "qwindowsclipboard.h" #endif @@ -50,6 +51,7 @@ #include "qwindowswindow.h" #include "qwindowsmousehandler.h" #include "qwindowscursor.h" +#include "qwindowsscaling.h" #include #include @@ -295,12 +297,19 @@ void QWindowsOleDropSource::createCursors() const QDrag *drag = m_drag->currentDrag(); const QPixmap pixmap = drag->pixmap(); const bool hasPixmap = !pixmap.isNull(); + const int scaleFactor = QWindowsScaling::factor(); + const QSize pixmapSizeDp = pixmap.size() * scaleFactor; + 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 drawPixmap = scalePixmap + ? pixmap.scaled(pixmapSizeDp, 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 = drag->hotSpot() * scaleFactor; for (int cnum = 0; cnum < actionCount; ++cnum) { const Qt::DropAction action = actions[cnum]; QPixmap cursorPixmap = drag->dragCursor(action); @@ -320,15 +329,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(pixmapSizeDp.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(pixmapSizeDp.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, drawPixmap); p.drawPixmap(qMax(0, hotSpot.x()),qMax(0, hotSpot.y()), cursorPixmap); newPixmap = newCursor; newHotSpot = QPoint(qMax(0, hotSpot.x()), qMax(0, hotSpot.y())); @@ -454,7 +462,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) if (!m_touchDragWindow) m_touchDragWindow = new QWindowsDragCursorWindow; m_touchDragWindow->setPixmap(e.pixmap); - m_touchDragWindow->setFramePosition(QWindowsCursor::mousePosition() - e.hotSpot); + m_touchDragWindow->setFramePosition((QWindowsCursor::mousePosition() - e.hotSpot) / QWindowsScaling::factor()); if (!m_touchDragWindow->isVisible()) m_touchDragWindow->show(); break; @@ -530,7 +538,9 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState, QGuiApplicationPrivate::mouse_buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); const QPlatformDragQtResponse response = - QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), m_lastPoint, actions); + QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), + m_lastPoint / QWindowsScaling::factor(), + actions); m_answerRect = response.answerRect(); const Qt::DropAction action = response.acceptedAction(); @@ -622,7 +632,8 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, QWindowsDrag *windowsDrag = QWindowsDrag::instance(); const QPlatformDropQtResponse response = - QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(), m_lastPoint, + QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(), + m_lastPoint / QWindowsScaling::factor(), translateToQDragDropActions(*pdwEffect)); if (response.isAccepted()) { diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index f8676c30f7..2284c47ed6 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -44,6 +44,7 @@ #include "qwindowswindow.h" #include "qwindowsintegration.h" #include "qwindowsmousehandler.h" +#include "qwindowsscaling.h" #include #include @@ -214,9 +215,10 @@ void QWindowsInputContext::cursorRectChanged() if (!m_compositionContext.hwnd) return; const QInputMethod *inputMethod = QGuiApplication::inputMethod(); - QRect cursorRectangle = inputMethod->cursorRectangle().toRect(); - if (!cursorRectangle.isValid()) + const QRect cursorRectangleDip = inputMethod->cursorRectangle().toRect(); + if (!cursorRectangleDip.isValid()) return; + const QRect cursorRectangle = QWindowsScaling::mapToNative(cursorRectangleDip); qCDebug(lcQpaInputMethods) << __FUNCTION__<< cursorRectangle; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 7c50ac69c2..7afda853e8 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -41,6 +41,7 @@ ****************************************************************************/ #include "qwindowsintegration.h" +#include "qwindowsscaling.h" #include "qwindowswindow.h" #include "qwindowscontext.h" #include "qwindowsopenglcontext.h" @@ -229,6 +230,12 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mL m_context.setProcessDpiAwareness(dpiAwareness); dpiAwarenessSet = true; } + // Determine suitable scale factor, don't mix Windows and Qt scaling + if (dpiAwareness != QtWindows::ProcessDpiUnaware) + QWindowsScaling::setFactor(QWindowsScaling::determineUiScaleFactor()); + qCDebug(lcQpaWindows) + << __FUNCTION__ << "DpiAwareness=" << dpiAwareness <<",Scaling=" + << QWindowsScaling::factor(); } QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate() @@ -289,7 +296,7 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const { QWindowsWindowData requested; requested.flags = window->flags(); - requested.geometry = window->geometry(); + requested.geometry = QWindowsScaling::mapToNative(window->geometry()); // Apply custom margins (see QWindowsWindow::setCustomMargins())). const QVariant customMarginsV = window->property("_q_windowsCustomMargins"); if (customMarginsV.isValid()) @@ -310,7 +317,7 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const window->setFlags(obtained.flags); // Trigger geometry change signals of QWindow. if ((obtained.flags & Qt::Desktop) != Qt::Desktop && requested.geometry != obtained.geometry) - QWindowSystemInterface::handleGeometryChange(window, obtained.geometry); + QWindowSystemInterface::handleGeometryChange(window, QWindowsScaling::mapFromNative(obtained.geometry)); } #ifndef QT_NO_OPENGL diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index dc1de047fe..540236bda7 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -43,6 +43,7 @@ #include "qwindowscontext.h" #include "qwindowswindow.h" #include "qwindowsguieventdispatcher.h" +#include "qwindowsscaling.h" #include #include @@ -767,11 +768,10 @@ static void showSystemMenu(QWindow* w) #undef enabled #undef disabled #endif // !Q_OS_WINCE + const QPoint topLeft = topLevel->geometry().topLeft() * QWindowsScaling::factor(); const int ret = TrackPopupMenuEx(menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD, - topLevel->geometry().x(), topLevel->geometry().y(), - topLevelHwnd, - 0); + topLeft.x(), topLeft.y(), topLevelHwnd, 0); if (ret) qWindowsWndProc(topLevelHwnd, WM_SYSCOMMAND, ret, 0); } diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 4633378342..2e677102a5 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -191,8 +191,10 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, const QPoint globalPosition = winEventPosition; const QPoint clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition); const Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons(); - QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition, - globalPosition, buttons, + QWindowSystemInterface::handleFrameStrutMouseEvent(window, + clientPosition / QWindowsScaling::factor(), + globalPosition / QWindowsScaling::factor(), + buttons, QWindowsKeyMapper::queryKeyboardModifiers(), source); return false; // Allow further event processing (dragging of windows). @@ -334,7 +336,10 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, m_windowUnderMouse = currentWindowUnderMouse; } - QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons, + QWindowSystemInterface::handleMouseEvent(window, + winEventPosition / QWindowsScaling::factor(), + globalPosition / QWindowsScaling::factor(), + buttons, QWindowsKeyMapper::queryKeyboardModifiers(), source); m_previousCaptureWindow = hasCapture ? window : 0; @@ -388,10 +393,11 @@ bool QWindowsMouseHandler::translateMouseWheelEvent(QWindow *window, HWND, } if (handleEvent) { + const QPoint posDip = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos) / QWindowsScaling::factor(); QWindowSystemInterface::handleWheelEvent(receiver, - QWindowsGeometryHint::mapFromGlobal(receiver, globalPos), - globalPos, - delta, orientation, mods); + posDip, globalPos / QWindowsScaling::factor(), + delta / QWindowsScaling::factor(), + orientation, mods); } return true; @@ -419,6 +425,7 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND, Q_ASSERT(QWindowsContext::user32dll.getTouchInputInfo); QWindowsContext::user32dll.getTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT)); + const qreal screenPosFactor = 0.01 / qreal(QWindowsScaling::factor()); for (int i = 0; i < winTouchPointCount; ++i) { const TOUCHINPUT &winTouchInput = winTouchInputs[i]; int id = m_touchInputIDToTouchPointID.value(winTouchInput.dwID, -1); @@ -432,10 +439,9 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND, if (m_lastTouchPositions.contains(id)) touchPoint.normalPosition = m_lastTouchPositions.value(id); - QPointF screenPos = QPointF(qreal(winTouchInput.x) / qreal(100.), qreal(winTouchInput.y) / qreal(100.)); + const QPointF screenPos = QPointF(winTouchInput.x, winTouchInput.y) * screenPosFactor; if (winTouchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA) - touchPoint.area.setSize(QSizeF(qreal(winTouchInput.cxContact) / qreal(100.), - qreal(winTouchInput.cyContact) / qreal(100.))); + touchPoint.area.setSize(QSizeF(winTouchInput.cxContact, winTouchInput.cyContact) * screenPosFactor); touchPoint.area.moveCenter(screenPos); QPointF normalPosition = QPointF(screenPos.x() / screenGeometry.width(), screenPos.y() / screenGeometry.height()); diff --git a/src/plugins/platforms/windows/qwindowsnativeimage.h b/src/plugins/platforms/windows/qwindowsnativeimage.h index 399bead323..98b7fc9bc5 100644 --- a/src/plugins/platforms/windows/qwindowsnativeimage.h +++ b/src/plugins/platforms/windows/qwindowsnativeimage.h @@ -67,6 +67,8 @@ public: HDC hdc() const { return m_hdc; } + void setDevicePixelRatio(qreal scaleFactor) { m_image.setDevicePixelRatio(scaleFactor); } + static QImage::Format systemFormat(); private: diff --git a/src/plugins/platforms/windows/qwindowsscaling.cpp b/src/plugins/platforms/windows/qwindowsscaling.cpp new file mode 100644 index 0000000000..fcc3440b42 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsscaling.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsscaling.h" +#include "qwindowsscreen.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QWindowsScaling + \brief Windows scaling utilities + + \internal + \ingroup qt-lighthouse-win +*/ + +int QWindowsScaling::m_factor = 1; + +static const char devicePixelRatioEnvVar[] = "QT_DEVICE_PIXEL_RATIO"; + +// Suggest a scale factor by checking monitor sizes. +int QWindowsScaling::determineUiScaleFactor() +{ + if (!qEnvironmentVariableIsSet(devicePixelRatioEnvVar)) + return 1; + const QByteArray envDevicePixelRatioEnv = qgetenv(devicePixelRatioEnvVar); + // Auto: Suggest a scale factor by checking monitor resolution. + if (envDevicePixelRatioEnv == QByteArrayLiteral("auto")) { + const int maxResolution = QWindowsScreen::maxMonitorHorizResolution(); + return maxResolution > 180 ? maxResolution / 96 : 1; + } + // Get factor from environment + bool ok = false; + const int envFactor = envDevicePixelRatioEnv.toInt(&ok); + return ok && envFactor > 0 ? envFactor : 1; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsscaling.h b/src/plugins/platforms/windows/qwindowsscaling.h new file mode 100644 index 0000000000..99fec7c810 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsscaling.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSSCALING_H +#define QWINDOWSSCALING_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +enum +#if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_CC_MSVC) + : int +#endif +{ QWINDOWSIZE_MAX = 16777215 }; + +class QWindowsScaling { +public: + static bool isActive() { return m_factor > 1; } + static int factor() { return m_factor; } + static void setFactor(int factor) { m_factor = factor; } + static int determineUiScaleFactor(); + + // Scaling helpers for size constraints. + static int mapToNativeConstrained(int qt) + { return m_factor != 1 && qt > 0 && qt < QWINDOWSIZE_MAX ? qt * m_factor : qt; } + + static int mapFromNativeConstrained(int dp) + { return m_factor != 1 && dp > 0 && dp < QWINDOWSIZE_MAX ? dp / m_factor : dp; } + + static QSize mapToNativeConstrained(const QSize &qt) + { return QSize(mapToNativeConstrained(qt.width()), mapToNativeConstrained(qt.height())); } + + static QRect mapToNative(const QRect &qRect) + { + return QRect(qRect.x() * m_factor, qRect.y() * m_factor, qRect.width() * m_factor, qRect.height() * m_factor); + } + + static QRect mapFromNative(const QRect &dp) + { + return isActive() ? + QRect(dp.x() / m_factor, dp.y() / m_factor, (dp.width() + 1) / m_factor, (dp.height() + 1) / m_factor) : + dp; + } + + static QRegion mapToNative(const QRegion ®ionQt) + { + if (!QWindowsScaling::isActive() || regionQt.isEmpty()) + return regionQt; + + QRegion result; + foreach (const QRect &rectQt, regionQt.rects()) + result += QWindowsScaling::mapToNative(rectQt); + return result; + } + + static QRegion mapFromNative(const QRegion ®ionDp) + { + if (!QWindowsScaling::isActive() || regionDp.isEmpty()) + return regionDp; + + QRegion result; + foreach (const QRect &rectDp, regionDp.rects()) + result += QWindowsScaling::mapFromNative(rectDp); + return result; + } + +private: + static int m_factor; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSSCALING_H diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index bcdb8a2352..a5a291a8d8 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -101,21 +101,19 @@ static inline QDpi deviceDPI(const QSize &pixels, const QSizeF &physicalSizeMM) typedef QList WindowsScreenDataList; -// from QDesktopWidget, taking WindowsScreenDataList as LPARAM -BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p) +static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data) { MONITORINFOEX info; memset(&info, 0, sizeof(MONITORINFOEX)); info.cbSize = sizeof(MONITORINFOEX); if (GetMonitorInfo(hMonitor, &info) == FALSE) - return TRUE; + return false; - WindowsScreenDataList *result = reinterpret_cast(p); - QWindowsScreenData data; - data.geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1)); - data.name = QString::fromWCharArray(info.szDevice); - if (data.name == QLatin1String("WinDisc")) { - data.flags |= QWindowsScreenData::LockScreen; + data->geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1)); + data->availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1)); + data->name = QString::fromWCharArray(info.szDevice); + if (data->name == QLatin1String("WinDisc")) { + data->flags |= QWindowsScreenData::LockScreen; } else { #ifdef Q_OS_WINCE //Windows CE, just supports one Display and expects to get only DISPLAY, @@ -127,40 +125,48 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM if (hdc) { #ifndef Q_OS_WINCE const QDpi dpi = monitorDPI(hMonitor); - data.dpi = dpi.first ? dpi : deviceDPI(hdc); + data->dpi = dpi.first ? dpi : deviceDPI(hdc); #else - data.dpi = deviceDPI(hdc); + data->dpi = deviceDPI(hdc); #endif - data.depth = GetDeviceCaps(hdc, BITSPIXEL); - data.format = data.depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; - data.physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE)); + data->depth = GetDeviceCaps(hdc, BITSPIXEL); + data->format = data->depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; + data->physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE)); const int refreshRate = GetDeviceCaps(hdc, VREFRESH); if (refreshRate > 1) // 0,1 means hardware default. - data.refreshRateHz = refreshRate; + data->refreshRateHz = refreshRate; DeleteDC(hdc); } else { qWarning("%s: Unable to obtain handle for monitor '%s', defaulting to %g DPI.", __FUNCTION__, qPrintable(QString::fromWCharArray(info.szDevice)), - data.dpi.first); + data->dpi.first); } // CreateDC() failed } // not lock screen - data.geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1)); - data.availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1)); - data.orientation = data.geometry.height() > data.geometry.width() ? + data->orientation = data->geometry.height() > data->geometry.width() ? Qt::PortraitOrientation : Qt::LandscapeOrientation; // EnumDisplayMonitors (as opposed to EnumDisplayDevices) enumerates only // virtual desktop screens. - data.flags |= QWindowsScreenData::VirtualDesktop; - if (info.dwFlags & MONITORINFOF_PRIMARY) { - data.flags |= QWindowsScreenData::PrimaryScreen; + data->flags |= QWindowsScreenData::VirtualDesktop; + if (info.dwFlags & MONITORINFOF_PRIMARY) + data->flags |= QWindowsScreenData::PrimaryScreen; + return true; +} + +// from QDesktopWidget, taking WindowsScreenDataList as LPARAM +BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p) +{ + QWindowsScreenData data; + if (monitorData(hMonitor, &data)) { + WindowsScreenDataList *result = reinterpret_cast(p); // QPlatformIntegration::screenAdded() documentation specifies that first // added screen will be the primary screen, so order accordingly. // Note that the side effect of this policy is that there is no way to change primary // screen reported by Qt, unless we want to delete all existing screens and add them // again whenever primary screen changes. - result->prepend(data); - } else { - result->append(data); + if (data.flags & QWindowsScreenData::PrimaryScreen) + result->prepend(data); + else + result->append(data); } return TRUE; } @@ -217,14 +223,36 @@ QWindowsScreen::QWindowsScreen(const QWindowsScreenData &data) : { } +BOOL QT_WIN_CALLBACK monitorResolutionEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p) +{ + QWindowsScreenData data; + if (monitorData(hMonitor, &data)) { + int *maxHorizResolution = reinterpret_cast(p); + const int horizResolution = qRound(data.dpi.first); + if (horizResolution > *maxHorizResolution) + *maxHorizResolution = horizResolution; + } + return TRUE; +} + +int QWindowsScreen::maxMonitorHorizResolution() +{ + int result = 0; + EnumDisplayMonitors(0, 0, monitorResolutionEnumCallback, (LPARAM)&result); + return result; +} + Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0); -QPixmap QWindowsScreen::grabWindow(WId window, int x, int y, int width, int height) const +QPixmap QWindowsScreen::grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const { RECT r; HWND hwnd = window ? (HWND)window : GetDesktopWindow(); GetClientRect(hwnd, &r); - + const int x = qX * QWindowsScaling::factor(); + const int y = qY * QWindowsScaling::factor(); + int width = qWidth * QWindowsScaling::factor(); + int height = qHeight * QWindowsScaling::factor(); if (width < 0) width = r.right - r.left; if (height < 0) height = r.bottom - r.top; @@ -248,6 +276,10 @@ QPixmap QWindowsScreen::grabWindow(WId window, int x, int y, int width, int heig DeleteObject(bitmap); ReleaseDC(0, display_dc); + if (QWindowsScaling::isActive()) { + const qreal factor = 1.0 / qreal(QWindowsScaling::factor()); + return pixmap.transformed(QTransform::fromScale(factor, factor)); + } return pixmap; } diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index c9d8a5662c..49581db41a 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -43,11 +43,13 @@ #define QWINDOWSSCREEN_H #include "qwindowscursor.h" +#include "qwindowsscaling.h" #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" #endif #include +#include #include #include #include @@ -88,24 +90,28 @@ public: static QWindowsScreen *screenOf(const QWindow *w = 0); - QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; } - QRect availableGeometry() const Q_DECL_OVERRIDE { return m_data.availableGeometry; } + QRect geometryDp() const { return m_data.geometry; } + QRect geometry() const Q_DECL_OVERRIDE { return QWindowsScaling::mapFromNative(geometryDp()); } + QRect availableGeometryDp() const { return m_data.availableGeometry; } + QRect availableGeometry() const Q_DECL_OVERRIDE { return QWindowsScaling::mapFromNative(availableGeometryDp()); } int depth() const Q_DECL_OVERRIDE { return m_data.depth; } 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; } + QDpi logicalDpi() const Q_DECL_OVERRIDE + { return QDpi(m_data.dpi.first / QWindowsScaling::factor(), m_data.dpi.second / QWindowsScaling::factor()); } + qreal devicePixelRatio() const Q_DECL_OVERRIDE { return QWindowsScaling::factor(); } qreal refreshRate() const Q_DECL_OVERRIDE { return m_data.refreshRateHz; } QString name() const Q_DECL_OVERRIDE { return m_data.name; } Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE { return m_data.orientation; } QList virtualSiblings() const Q_DECL_OVERRIDE; QWindow *topLevelAt(const QPoint &point) const Q_DECL_OVERRIDE - { return QWindowsScreen::findTopLevelAt(point, CWP_SKIPINVISIBLE); } + { return QWindowsScreen::findTopLevelAt(point * QWindowsScaling::factor() , CWP_SKIPINVISIBLE); } static QWindow *findTopLevelAt(const QPoint &point, unsigned flags); static QWindow *windowAt(const QPoint &point, unsigned flags = CWP_SKIPINVISIBLE); static QWindow *windowUnderMouse(unsigned flags = CWP_SKIPINVISIBLE); - QPixmap grabWindow(WId window, int x, int y, int width, int height) const Q_DECL_OVERRIDE; + QPixmap grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const Q_DECL_OVERRIDE; inline void handleChanges(const QWindowsScreenData &newData); @@ -117,6 +123,7 @@ public: #endif // !QT_NO_CURSOR const QWindowsScreenData &data() const { return m_data; } + static int maxMonitorHorizResolution(); private: QWindowsScreenData m_data; diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp index d1737de907..802fc3605a 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qwindowstabletsupport.h" +#include "qwindowsscaling.h" #ifndef QT_NO_TABLETEVENT @@ -403,7 +404,8 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() // in which case we snap the position to the mouse position. // It seems there is no way to find out the mode programmatically, the LOGCONTEXT orgX/Y/Ext // area is always the virtual desktop. - const QRect virtualDesktopArea = QGuiApplication::primaryScreen()->virtualGeometry(); + const QRect virtualDesktopArea + = QWindowsScaling::mapToNative(QGuiApplication::primaryScreen()->virtualGeometry()); qCDebug(lcQpaTablet) << __FUNCTION__ << "processing " << packetCount << "target:" << QGuiApplicationPrivate::tabletPressTarget; @@ -423,7 +425,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() QPoint globalPos = globalPosF.toPoint(); // Get Mouse Position and compare to tablet info - const QPoint mouseLocation = QWindowsCursor::mousePosition(); + QPoint mouseLocation = QWindowsCursor::mousePosition(); // Positions should be almost the same if we are in absolute // mode. If they are not, use the mouse location. @@ -479,7 +481,9 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation; } - QWindowSystemInterface::handleTabletEvent(target, QPointF(localPos), globalPosF, + const QPointF localPosDip = QPointF(localPos / QWindowsScaling::factor()); + const QPointF globalPosDip = globalPosF / qreal(QWindowsScaling::factor()); + QWindowSystemInterface::handleTabletEvent(target, localPosDip, globalPosDip, currentDevice, currentPointer, static_cast(packet.pkButtons), pressureNew, tiltX, tiltY, diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 3b54feabbf..e6b996c685 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -44,6 +44,7 @@ #include "qwindowscontext.h" #include "qwindowsdrag.h" #include "qwindowsscreen.h" +#include "qwindowsscaling.h" #ifdef QT_NO_CURSOR # include "qwindowscursor.h" #endif @@ -576,7 +577,9 @@ QWindowsWindowData const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w, isGL); - QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, defaultWindowWidth, defaultWindowHeight); + const QRect geometryDip = QWindowsScaling::mapFromNative(data.geometry); + QRect fixedGeometryDip = QPlatformWindow::initialGeometry(w, geometryDip, defaultWindowWidth, defaultWindowHeight); + const QRect rect = fixedGeometryDip != geometryDip ? QWindowsScaling::mapToNative(fixedGeometryDip) : data.geometry; if (title.isEmpty() && (result.flags & Qt::WindowTitleHint)) title = topLevel ? qAppName() : w->objectName(); @@ -683,11 +686,9 @@ void WindowCreationData::initialize(HWND hwnd, bool frameChange, qreal opacityLe \ingroup qt-lighthouse-win */ -#define QWINDOWSIZE_MAX ((1<<24)-1) - QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w, const QMargins &cm) : - minimumSize(w->minimumSize()), - maximumSize(w->maximumSize()), + minimumSize(QWindowsScaling::mapToNativeConstrained(w->minimumSize())), + maximumSize(QWindowsScaling::mapToNativeConstrained(w->maximumSize())), customMargins(cm) { } @@ -930,7 +931,8 @@ void QWindowsWindow::fireExpose(const QRegion ®ion, bool force) clearFlag(Exposed); else setFlag(Exposed); - QWindowSystemInterface::handleExposeEvent(window(), region); + QWindowSystemInterface::handleExposeEvent(window(), + QWindowsScaling::mapFromNative(region)); } static inline QWindow *findTransientChild(const QWindow *parent) @@ -1106,7 +1108,7 @@ bool QWindowsWindow::isEmbedded(const QPlatformWindow *parentWindow) const return m_data.embedded; } -QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const +QPoint QWindowsWindow::mapToGlobalDp(const QPoint &pos) const { if (m_data.hwnd) return QWindowsGeometryHint::mapToGlobal(m_data.hwnd, pos); @@ -1114,7 +1116,7 @@ QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const return pos; } -QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const +QPoint QWindowsWindow::mapFromGlobalDp(const QPoint &pos) const { if (m_data.hwnd) return QWindowsGeometryHint::mapFromGlobal(m_data.hwnd, pos); @@ -1286,22 +1288,22 @@ static QRect normalFrameGeometry(HWND hwnd) return QRect(); } -QRect QWindowsWindow::normalGeometry() const +QRect QWindowsWindow::normalGeometryDp() const { // Check for fake 'fullscreen' mode. const bool fakeFullScreen = m_savedFrameGeometry.isValid() && window()->windowState() == Qt::WindowFullScreen; const QRect frame = fakeFullScreen ? m_savedFrameGeometry : normalFrameGeometry(m_data.hwnd); - const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMargins(); + const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMarginsDp(); return frame.isValid() ? frame.marginsRemoved(margins) : frame; } -void QWindowsWindow::setGeometry(const QRect &rectIn) +void QWindowsWindow::setGeometryDp(const QRect &rectIn) { QRect rect = rectIn; // This means it is a call from QWindow::setFramePosition() and // the coordinates include the frame (size is still the contents rectangle). if (QWindowsGeometryHint::positionIncludesFrame(window())) { - const QMargins margins = frameMargins(); + const QMargins margins = frameMarginsDp(); rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top())); } const QSize oldSize = m_data.geometry.size(); @@ -1383,8 +1385,9 @@ void QWindowsWindow::handleGeometryChange() return; const QRect previousGeometry = m_data.geometry; m_data.geometry = geometry_sys(); - QPlatformWindow::setGeometry(m_data.geometry); - QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry); + const QRect geometryDip = QWindowsScaling::mapFromNative(m_data.geometry); + QPlatformWindow::setGeometry(geometryDip); + QWindowSystemInterface::handleGeometryChange(window(), geometryDip); // QTBUG-32121: OpenGL/normal windows (with exception of ANGLE) do not receive // expose events when shrinking, synthesize. if (!testFlag(OpenGL_ES2) && isExposed() @@ -1404,7 +1407,7 @@ void QWindowsWindow::handleGeometryChange() void QWindowsWindow::setGeometry_sys(const QRect &rect) const { - const QMargins margins = frameMargins(); + const QMargins margins = frameMarginsDp(); const QRect frameGeometry = rect + margins; qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() @@ -1441,7 +1444,7 @@ QRect QWindowsWindow::frameGeometry_sys() const QRect QWindowsWindow::geometry_sys() const { - return frameGeometry_sys().marginsRemoved(frameMargins()); + return frameGeometry_sys().marginsRemoved(frameMarginsDp()); } /*! @@ -1514,7 +1517,7 @@ void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags) qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() << "\n from: " << QWindowsWindow::debugWindowFlags(m_data.flags) << "\n to: " << QWindowsWindow::debugWindowFlags(flags); - const QRect oldGeometry = geometry(); + const QRect oldGeometry = geometryDp(); if (m_data.flags != flags) { m_data.flags = flags; if (m_data.hwnd) { @@ -1602,7 +1605,8 @@ void QWindowsWindow::setWindowState(Qt::WindowState state) bool QWindowsWindow::isFullScreen_sys() const { - return window()->isTopLevel() && geometry_sys() == window()->screen()->geometry(); + return window()->isTopLevel() + && geometry_sys() == QWindowsScaling::mapToNative(window()->screen()->geometry()); } /*! @@ -1683,14 +1687,15 @@ 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 rDip = screen->geometry(); + const QRect r = QWindowsScaling::mapToNative(rDip); const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; const bool wasSync = testFlag(SynchronousGeometryChangeEvent); setFlag(SynchronousGeometryChangeEvent); SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf); if (!wasSync) clearFlag(SynchronousGeometryChangeEvent); - QWindowSystemInterface::handleGeometryChange(window(), r); + QWindowSystemInterface::handleGeometryChange(window(), rDip); QWindowSystemInterface::flushWindowSystemEvents(); } else if (newState != Qt::WindowMinimized) { // Restore saved state. @@ -1778,7 +1783,7 @@ void QWindowsWindow::propagateSizeHints() qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); } -QMargins QWindowsWindow::frameMargins() const +QMargins QWindowsWindow::frameMarginsDp() const { // Frames are invalidated by style changes (window state, flags). // As they are also required for geometry calculations in resize @@ -1820,17 +1825,17 @@ static inline void addRectToWinRegion(const QRect &rect, HRGN *winRegion) } } -static HRGN qRegionToWinRegion(const QRegion ®ion) +static HRGN qRegionToWinRegion(const QRegion ®ionDip) { - const QVector rects = region.rects(); + const QVector rects = regionDip.rects(); if (rects.isEmpty()) return NULL; const int rectCount = rects.size(); if (rectCount == 1) - return createRectRegion(region.boundingRect()); + return createRectRegion(QWindowsScaling::mapToNative(regionDip.boundingRect())); HRGN hRegion = createRectRegion(rects.front()); for (int i = 1; i < rectCount; ++i) - addRectToWinRegion(rects.at(i), &hRegion); + addRectToWinRegion(QWindowsScaling::mapToNative(rects.at(i)), &hRegion); return hRegion; } @@ -1844,7 +1849,7 @@ void QWindowsWindow::setMask(const QRegion ®ion) // Mask is in client area coordinates, so offset it in case we have a frame if (window()->isTopLevel()) { - const QMargins margins = frameMargins(); + const QMargins margins = frameMarginsDp(); OffsetRgn(winRegion, margins.left(), margins.top()); } @@ -1981,23 +1986,23 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re || (m_data.flags & Qt::FramelessWindowHint)) { return false; } - const QSize minimumSize = w->minimumSize(); + const QSize minimumSize = QWindowsScaling::mapToNativeConstrained(w->minimumSize()); if (minimumSize.isEmpty()) return false; - const QSize maximumSize = w->maximumSize(); + const QSize maximumSize = QWindowsScaling::mapToNativeConstrained(w->maximumSize()); const bool fixedWidth = minimumSize.width() == maximumSize.width(); const bool fixedHeight = minimumSize.height() == maximumSize.height(); if (!fixedWidth && !fixedHeight) return false; - const QPoint localPos = w->mapFromGlobal(globalPos); - const QSize size = w->size(); + const QPoint localPos = mapFromGlobalDp(globalPos); + const QSize size = w->size() * QWindowsScaling::factor(); if (fixedHeight) { if (localPos.y() >= size.height()) { *result = HTBORDER; // Unspecified border, no resize cursor. return true; } if (localPos.y() < 0) { - const QMargins margins = frameMargins(); + const QMargins margins = frameMarginsDp(); const int topResizeBarPos = margins.left() - margins.top(); if (localPos.y() < topResizeBarPos) { *result = HTCAPTION; // Extend caption over top resize bar, let's user move the window. @@ -2249,6 +2254,10 @@ void QWindowsWindow::setWindowIcon(const QIcon &icon) The property can be set using QPlatformNativeInterface::setWindowProperty() or, before platform window creation, by setting a dynamic property on the QWindow (see QWindowsIntegration::createPlatformWindow()). + + Note: The function uses (unscaled) device pixels since the QWizard also + uses AdjustWindowRect() and using device independent pixels would introduce + rounding errors. */ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 19d2236688..cb9da6fe27 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -46,6 +46,7 @@ #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" #endif +#include "qwindowsscaling.h" #include "qwindowscursor.h" #include "qwindowsopenglcontext.h" @@ -152,18 +153,28 @@ public: ~QWindowsWindow(); QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } - void setGeometry(const QRect &rect) Q_DECL_OVERRIDE; - QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; } - QRect normalGeometry() const Q_DECL_OVERRIDE; - + void setGeometryDp(const QRect &rectIn); + void setGeometry(const QRect &rect) Q_DECL_OVERRIDE + { setGeometryDp(QWindowsScaling::mapToNative(rect)); } + QRect geometryDp() const { return m_data.geometry; } + QRect geometry() const Q_DECL_OVERRIDE + { return QWindowsScaling::mapFromNative(geometryDp()); } + QRect normalGeometryDp() const; + QRect normalGeometry() const Q_DECL_OVERRIDE + { return QWindowsScaling::mapFromNative(normalGeometryDp()); } + qreal devicePixelRatio() const Q_DECL_OVERRIDE + { return qreal(QWindowsScaling::factor()); } void setVisible(bool visible) Q_DECL_OVERRIDE; bool isVisible() const; bool isExposed() const Q_DECL_OVERRIDE { return testFlag(Exposed); } bool isActive() const Q_DECL_OVERRIDE; bool isEmbedded(const QPlatformWindow *parentWindow) const Q_DECL_OVERRIDE; - QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; - QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; - + QPoint mapToGlobalDp(const QPoint &pos) const; + QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE + { return mapToGlobalDp(pos * QWindowsScaling::factor()) / QWindowsScaling::factor(); } + QPoint mapFromGlobalDp(const QPoint &pos) const; + QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE + { return mapFromGlobalDp(pos * QWindowsScaling::factor()) / QWindowsScaling::factor(); } void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE; void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; @@ -179,7 +190,8 @@ public: void windowEvent(QEvent *event); void propagateSizeHints() Q_DECL_OVERRIDE; - QMargins frameMargins() const Q_DECL_OVERRIDE; + QMargins frameMarginsDp() const; + QMargins frameMargins() const Q_DECL_OVERRIDE { return frameMarginsDp() / QWindowsScaling::factor(); } void setOpacity(qreal level) Q_DECL_OVERRIDE; void setMask(const QRegion ®ion) Q_DECL_OVERRIDE; @@ -190,7 +202,7 @@ public: bool setMouseGrabEnabled(bool grab) Q_DECL_OVERRIDE; inline bool hasMouseCapture() const { return GetCapture() == m_data.hwnd; } - bool startSystemResize(const QPoint &pos, Qt::Corner corner) Q_DECL_OVERRIDE; + bool startSystemResize(const QPoint &, Qt::Corner corner) Q_DECL_OVERRIDE; void setFrameStrutEventsEnabled(bool enabled); bool frameStrutEventsEnabled() const { return testFlag(FrameStrutEventsEnabled); } diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri index 104d882fba..8e5f35d293 100644 --- a/src/plugins/platforms/windows/windows.pri +++ b/src/plugins/platforms/windows/windows.pri @@ -39,7 +39,8 @@ SOURCES += \ $$PWD/qwindowsdialoghelpers.cpp \ $$PWD/qwindowsservices.cpp \ $$PWD/qwindowsnativeimage.cpp \ - $$PWD/qwindowsnativeinterface.cpp + $$PWD/qwindowsnativeinterface.cpp \ + $$PWD/qwindowsscaling.cpp HEADERS += \ $$PWD/qwindowswindow.h \ @@ -64,7 +65,8 @@ HEADERS += \ $$PWD/qwindowsservices.h \ $$PWD/qplatformfunctions_wince.h \ $$PWD/qwindowsnativeimage.h \ - $$PWD/qwindowsnativeinterface.h + $$PWD/qwindowsnativeinterface.h \ + $$PWD/qwindowsscaling.h !wince: HEADERS += $$PWD/qwindowsopengltester.h -- cgit v1.2.3