From 29c6e39086831f6811e94364273c1f4bff119bef Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 18 Jul 2016 10:53:41 +0200 Subject: Windows style: Scale native metrics per monitor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The native sizes returned by the metrics and theme functions refer to the primary monitor. They need adaption when showing on a secondary monitor with differing logical DPI. Introduce a helper function QWindowsStylePrivate::nativeMetricScaleFactor() to calculate the total factor. Task-number: QTBUG-49374 Change-Id: I34c843ff34108424e1ef0aafcf9f563d17ebbc89 Reviewed-by: Morten Johan Sørvig --- src/widgets/styles/qwindowsstyle.cpp | 47 ++++++++++++++++++++++++++++++- src/widgets/styles/qwindowsstyle_p_p.h | 2 ++ src/widgets/styles/qwindowsvistastyle.cpp | 22 +++++++-------- src/widgets/styles/qwindowsxpstyle.cpp | 15 +++++----- 4 files changed, 67 insertions(+), 19 deletions(-) diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index 536ef2d49a..a0830a1f92 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -59,8 +59,12 @@ #include "qlistview.h" #include #include +#include +#include #include +#include #include +#include #include #include @@ -395,6 +399,47 @@ int QWindowsStylePrivate::fixedPixelMetric(QStyle::PixelMetric pm) return QWindowsStylePrivate::InvalidMetric; } +static QWindow *windowOf(const QWidget *w) +{ + QWindow *result = Q_NULLPTR; + if (w) { + result = w->windowHandle(); + if (!result) { + if (const QWidget *np = w->nativeParentWidget()) + result = np->windowHandle(); + } + } + return result; +} + +static QScreen *screenOf(const QWidget *w) +{ + if (const QWindow *window = windowOf(w)) + return window->screen(); + return QGuiApplication::primaryScreen(); +} + +// Calculate the overall scale factor to obtain Qt Device Independent +// Pixels from a native Windows size. Divide by devicePixelRatio +// and account for secondary screens with differing logical DPI. +qreal QWindowsStylePrivate::nativeMetricScaleFactor(const QWidget *widget) +{ + if (!QHighDpiScaling::isActive()) + return 1; + qreal result = qreal(1) / QWindowsStylePrivate::devicePixelRatio(widget); + if (QGuiApplicationPrivate::screen_list.size() > 1) { + const QScreen *primaryScreen = QGuiApplication::primaryScreen(); + const QScreen *screen = screenOf(widget); + if (screen != primaryScreen) { + const qreal primaryLogicalDpi = primaryScreen->handle()->logicalDpi().first; + const qreal logicalDpi = screen->handle()->logicalDpi().first; + if (!qFuzzyCompare(primaryLogicalDpi, logicalDpi)) + result *= logicalDpi / primaryLogicalDpi; + } + } + return result; +} + /*! \reimp */ @@ -402,7 +447,7 @@ int QWindowsStyle::pixelMetric(PixelMetric pm, const QStyleOption *opt, const QW { int ret = QWindowsStylePrivate::pixelMetricFromSystemDp(pm, opt, widget); if (ret != QWindowsStylePrivate::InvalidMetric) - return qRound(qreal(ret) / QWindowsStylePrivate::devicePixelRatio(widget)); + return qRound(qreal(ret) * QWindowsStylePrivate::nativeMetricScaleFactor(widget)); ret = QWindowsStylePrivate::fixedPixelMetric(pm); if (ret != QWindowsStylePrivate::InvalidMetric) diff --git a/src/widgets/styles/qwindowsstyle_p_p.h b/src/widgets/styles/qwindowsstyle_p_p.h index 7971b84923..dc5a15db70 100644 --- a/src/widgets/styles/qwindowsstyle_p_p.h +++ b/src/widgets/styles/qwindowsstyle_p_p.h @@ -66,6 +66,7 @@ public: static int fixedPixelMetric(QStyle::PixelMetric pm); static qreal devicePixelRatio(const QWidget *widget = 0) { return widget ? widget->devicePixelRatioF() : QWindowsStylePrivate::appDevicePixelRatio(); } + static qreal nativeMetricScaleFactor(const QWidget *widget = Q_NULLPTR); bool hasSeenAlt(const QWidget *widget) const; bool altDown() const { return alt_down; } @@ -98,3 +99,4 @@ QT_END_NAMESPACE #endif // QT_NO_STYLE_WINDOWS #endif //QWINDOWSSTYLE_P_P_H +; diff --git a/src/widgets/styles/qwindowsvistastyle.cpp b/src/widgets/styles/qwindowsvistastyle.cpp index 2ce54fe207..fe9684a25f 100644 --- a/src/widgets/styles/qwindowsvistastyle.cpp +++ b/src/widgets/styles/qwindowsvistastyle.cpp @@ -426,7 +426,7 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt XPThemeData themeSize = theme; themeSize.partId = TVP_HOTGLYPH; themeSize.stateId = GLPS_OPENED; - const QSizeF size = themeSize.size() / QWindowsXPStylePrivate::devicePixelRatio(widget); + const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget); decoration_size = qRound(qMax(size.width(), size.height())); } int mid_h = option->rect.x() + option->rect.width() / 2; @@ -988,7 +988,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption XPThemeData theme(widget, 0, QWindowsXPStylePrivate::ToolBarTheme, TP_DROPDOWNBUTTON); if (theme.isValid()) { - const QSizeF size = theme.size() / QWindowsXPStylePrivate::devicePixelRatio(widget); + const QSizeF size = theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget); if (!size.isEmpty()) { mbiw = qRound(size.width()); mbih = qRound(size.height()); @@ -1184,8 +1184,8 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption XPThemeData themeSize = theme; themeSize.partId = MENU_POPUPCHECK; themeSize.stateId = 0; - const QSizeF size = themeSize.size() / QWindowsXPStylePrivate::devicePixelRatio(widget); - const QMarginsF margins = themeSize.margins() / QWindowsXPStylePrivate::devicePixelRatio(widget); + const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget); + const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget); checkcol = qMax(menuitem->maxIconWidth, qRound(gutterWidth + size.width() + margins.left() + margins.right())); } QRect rect = option->rect; @@ -1210,7 +1210,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) { int yoff = y-2 + h / 2; - const int separatorSize = 6 / QWindowsXPStylePrivate::devicePixelRatio(widget); + const int separatorSize = qRound(qreal(6) * QWindowsStylePrivate::nativeMetricScaleFactor(widget)); QPoint p1 = QPoint(x + checkcol, yoff); QPoint p2 = QPoint(x + w + separatorSize, yoff); stateId = MBI_HOT; @@ -1243,8 +1243,8 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption XPThemeData themeSize = theme; themeSize.partId = MENU_POPUPCHECK; themeSize.stateId = 0; - const QSizeF size = themeSize.size() / QWindowsXPStylePrivate::devicePixelRatio(widget); - const QMarginsF margins = themeSize.margins() / QWindowsXPStylePrivate::devicePixelRatio(widget); + const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget); + const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget); QRect checkRect(0, 0, qRound(size.width() + margins.left() + margins.right()), qRound(size.height() + margins.bottom() + margins.top())); checkRect.moveCenter(vCheckRect.center()); @@ -1856,8 +1856,8 @@ QSize QWindowsVistaStyle::sizeFromContents(ContentsType type, const QStyleOption XPThemeData themeSize = theme; themeSize.partId = MENU_POPUPCHECK; themeSize.stateId = 0; - const QSizeF size = themeSize.size() / QWindowsXPStylePrivate::devicePixelRatio(widget); - const QMarginsF margins = themeSize.margins() / QWindowsXPStylePrivate::devicePixelRatio(widget); + const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget); + const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget); minimumHeight = qMax(qRound(size.height() + margins.bottom() + margins.top()), sz.height()); sz.rwidth() += qRound(size.width() + margins.left() + margins.right()); } @@ -1967,7 +1967,7 @@ QRect QWindowsVistaStyle::subElementRect(SubElement element, const QStyleOption int arrowWidth = 13; int arrowHeight = 5; if (theme.isValid()) { - const QSizeF size = theme.size() / QWindowsXPStylePrivate::devicePixelRatio(widget); + const QSizeF size = theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget); if (!size.isEmpty()) { arrowWidth = qRound(size.width()); arrowHeight = qRound(size.height()); @@ -2450,7 +2450,7 @@ QIcon QWindowsVistaStyle::standardIcon(StandardPixmap standardIcon, QWindowsXPStylePrivate::ButtonTheme, BP_COMMANDLINKGLYPH, CMDLGS_NORMAL); if (theme.isValid()) { - const QSize size = (theme.size() / QWindowsXPStylePrivate::devicePixelRatio(widget)).toSize(); + const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize(); QIcon linkGlyph; QPixmap pm(size); pm.fill(Qt::transparent); diff --git a/src/widgets/styles/qwindowsxpstyle.cpp b/src/widgets/styles/qwindowsxpstyle.cpp index a850787af0..f2ee8e0b47 100644 --- a/src/widgets/styles/qwindowsxpstyle.cpp +++ b/src/widgets/styles/qwindowsxpstyle.cpp @@ -481,7 +481,7 @@ const QPixmap *QWindowsXPStylePrivate::tabBody(QWidget *widget) { if (!tabbody) { XPThemeData theme(0, 0, QWindowsXPStylePrivate::TabTheme, TABP_BODY); - const QSize size = (theme.size() / QWindowsXPStylePrivate::devicePixelRatio(widget)).toSize(); + const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize(); tabbody = new QPixmap(size.width(), QApplication::desktop()->screenGeometry().height()); QPainter painter(tabbody); @@ -3449,7 +3449,7 @@ int QWindowsXPStyle::pixelMetric(PixelMetric pm, const QStyleOption *option, con int res = QWindowsXPStylePrivate::pixelMetricFromSystemDp(pm, option, widget); if (res != QWindowsStylePrivate::InvalidMetric) - return qRound(qreal(res) / QWindowsStylePrivate::devicePixelRatio(widget)); + return qRound(qreal(res) * QWindowsStylePrivate::nativeMetricScaleFactor(widget)); res = 0; switch (pm) { @@ -3595,9 +3595,10 @@ QRect QWindowsXPStyle::subControlRect(ComplexControl cc, const QStyleOptionCompl const int height = tb->rect.height(); const int width = tb->rect.width(); const int buttonMargin = int(QStyleHelper::dpiScaled(4)); - int buttonHeight = qRound(qreal(GetSystemMetrics(SM_CYSIZE)) / QWindowsStylePrivate::devicePixelRatio(widget)) + const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget); + int buttonHeight = qRound(qreal(GetSystemMetrics(SM_CYSIZE)) * factor) - buttonMargin; - int buttonWidth = qRound(qreal(GetSystemMetrics(SM_CXSIZE)) / QWindowsStylePrivate::devicePixelRatio(widget)) + int buttonWidth = qRound(qreal(GetSystemMetrics(SM_CXSIZE)) * factor) - buttonMargin; const int delta = buttonWidth + 2; int controlTop = option->rect.bottom() - buttonHeight - 2; @@ -3967,7 +3968,7 @@ QPixmap QWindowsXPStyle::standardPixmap(StandardPixmap standardPixmap, const QSt if (widget && widget->isWindow()) { XPThemeData theme(widget, 0, QWindowsXPStylePrivate::WindowTheme, WP_SMALLCLOSEBUTTON, CBS_NORMAL); if (theme.isValid()) { - const QSize size = (theme.size() / QWindowsXPStylePrivate::devicePixelRatio(widget)).toSize(); + const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize(); return QIcon(QWindowsStyle::standardPixmap(standardPixmap, option, widget)).pixmap(size); } } @@ -4001,7 +4002,7 @@ QIcon QWindowsXPStyle::standardIcon(StandardPixmap standardIcon, XPThemeData theme(0, 0, QWindowsXPStylePrivate::WindowTheme, WP_MAXBUTTON, MAXBS_NORMAL); if (theme.isValid()) { - const QSize size = (themeSize.size() / QWindowsXPStylePrivate::devicePixelRatio(widget)).toSize(); + const QSize size = (themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize(); QPixmap pm(size); pm.fill(Qt::transparent); QPainter p(&pm); @@ -4035,7 +4036,7 @@ QIcon QWindowsXPStyle::standardIcon(StandardPixmap standardIcon, XPThemeData theme(0, 0, QWindowsXPStylePrivate::WindowTheme, WP_SMALLCLOSEBUTTON, CBS_NORMAL); if (theme.isValid()) { - const QSize size = (theme.size() / QWindowsXPStylePrivate::devicePixelRatio(widget)).toSize(); + const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize(); QPixmap pm(size); pm.fill(Qt::transparent); QPainter p(&pm); -- cgit v1.2.3