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 <lars.knoll@theqtcompany.com>
bb10
Friedemann Kleint 2015-06-29 10:25:24 +02:00 committed by Paul Olav Tvete
parent a705b4ec1f
commit fd6821740f
8 changed files with 65 additions and 17 deletions

View File

@ -38,6 +38,7 @@
#include <QtGui/QWindow>
#include <QtGui/QPainter>
#include <private/qhighdpiscaling_p.h>
#include <QtCore/QDebug>
@ -82,8 +83,8 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion &region,
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()};

View File

@ -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 <QtGui/QGuiApplication>
#include <qpa/qwindowsysteminterface_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtCore/QDebug>
#include <QtCore/QBuffer>
@ -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()));

View File

@ -63,6 +63,7 @@
# include "qwindowssessionmanager.h"
#endif
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/qpa/qplatforminputcontextfactory_p.h>
#include <QtCore/private/qeventdispatcher_win_p.h>
@ -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())

View File

@ -40,6 +40,7 @@
#include <QtGui/QWindow>
#include <qpa/qwindowsysteminterface.h>
#include <private/qguiapplication_p.h>
#include <private/qhighdpiscaling_p.h>
#include <QtGui/QKeyEvent>
#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)

View File

@ -43,6 +43,7 @@
#include <QtGui/QPixmap>
#include <QtGui/QGuiApplication>
#include <qpa/qwindowsysteminterface.h>
#include <private/qhighdpiscaling_p.h>
#include <QtGui/QScreen>
#include <QtCore/QDebug>
@ -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.

View File

@ -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; }

View File

@ -67,6 +67,7 @@
#include <QtGui/QPainter>
#include <QtGui/QPixmapCache>
#include <qpa/qwindowsysteminterface.h>
#include <private/qhighdpiscaling_p.h>
#include <private/qsystemlibrary_p.h>
#include <algorithm>
@ -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;

View File

@ -50,6 +50,7 @@
#include <private/qsystemlibrary_p.h>
#include <private/qwindow_p.h> // QWINDOWSIZE_MAX
#include <private/qguiapplication_p.h>
#include <private/qhighdpiscaling_p.h>
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/QDebug>
@ -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 *>(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()) {