From 06276f3532750e1ecc51eac97b732cdd7258057e Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 7 Jan 2016 10:16:12 +0100 Subject: Adapt to High DPI scaling. [ChangeLog] Adapt to High DPI scaling. Task-number: QTBUG-46615 Change-Id: Ic56a2ff4f3115ae7d2b9a63fd3a8f15dc9d71ebe Reviewed-by: Joerg Bornemann --- src/activeqt/container/qaxwidget.cpp | 39 +++++----- src/activeqt/control/qaxserverbase.cpp | 41 ++++++----- src/activeqt/shared/qaxutils.cpp | 128 ++++++++++++++++++++++++++++++++- src/activeqt/shared/qaxutils_p.h | 48 ++++++++++++- 4 files changed, 211 insertions(+), 45 deletions(-) diff --git a/src/activeqt/container/qaxwidget.cpp b/src/activeqt/container/qaxwidget.cpp index 987c649..ae3e3e1 100644 --- a/src/activeqt/container/qaxwidget.cpp +++ b/src/activeqt/container/qaxwidget.cpp @@ -192,7 +192,7 @@ public: if (!host) return OLE_E_NOT_INPLACEACTIVE; - RECT rcPos = { host->x(), host->y(), host->x()+host->width(), host->y()+host->height() }; + RECT rcPos = qaxNativeWidgetRect(host); return m_spOleObject->DoVerb(index, 0, this, 0, (HWND)host->winId(), &rcPos); @@ -471,6 +471,8 @@ bool QAxNativeEventFilter::nativeEventFilter(const QByteArray &, void *m, long * { MSG *msg = (MSG*)m; const uint message = msg->message; + if (message == WM_DISPLAYCHANGE) + qaxClearCachedSystemLogicalDpi(); if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) || (message >= WM_KEYFIRST && message <= WM_KEYLAST)) { HWND hwnd = msg->hwnd; QAxWidget *ax = 0; @@ -508,7 +510,8 @@ bool QAxNativeEventFilter::nativeEventFilter(const QByteArray &, void *m, long * button = 0; DWORD ol_pos = GetMessagePos(); - QPoint gpos(GET_X_LPARAM(ol_pos), GET_Y_LPARAM(ol_pos)); + const QPoint nativeGlobalPos(GET_X_LPARAM(ol_pos), GET_Y_LPARAM(ol_pos)); + const QPoint gpos = qaxFromNativePosition(ax, nativeGlobalPos); QPoint pos = ax->mapFromGlobal(gpos); QMouseEvent e(type, pos, gpos, (Qt::MouseButton)button, @@ -662,15 +665,12 @@ bool QAxClientSite::activateObject(bool initialized, const QByteArray &data) m_spOleObject->SetHostNames(OLESTR("AXWIN"), 0); if (!(dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME)) { - SIZEL hmSize; - hmSize.cx = MAP_PIX_TO_LOGHIM(250, widget->logicalDpiX()); - hmSize.cy = MAP_PIX_TO_LOGHIM(250, widget->logicalDpiY()); + SIZEL hmSize = qaxMapPixToLogHiMetrics(QSize(250, 250), widget); m_spOleObject->SetExtent(DVASPECT_CONTENT, &hmSize); m_spOleObject->GetExtent(DVASPECT_CONTENT, &hmSize); - sizehint.setWidth(MAP_LOGHIM_TO_PIX(hmSize.cx, widget->logicalDpiX())); - sizehint.setHeight(MAP_LOGHIM_TO_PIX(hmSize.cy, widget->logicalDpiY())); + sizehint = qaxMapLogHiMetricsToPix(hmSize, widget); showHost = true; } else { sizehint = QSize(0, 0); @@ -682,7 +682,7 @@ bool QAxClientSite::activateObject(bool initialized, const QByteArray &data) host->setFocusPolicy(Qt::NoFocus); } - RECT rcPos = { host->x(), host->y(), host->x()+sizehint.width(), host->y()+sizehint.height() }; + RECT rcPos = qaxQRect2Rect(QRect(qaxNativeWidgetPosition(host), qaxToNativeSize(host, sizehint))); m_spOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, 0, (IOleClientSite*)this, 0, (HWND)host->winId(), @@ -1564,12 +1564,8 @@ QSize QAxClientSite::minimumSizeHint() const SIZE sz = { 0, 0 }; m_spOleObject->SetExtent(DVASPECT_CONTENT, &sz); - HRESULT res = m_spOleObject->GetExtent(DVASPECT_CONTENT, &sz); - if (SUCCEEDED(res)) { - return QSize(MAP_LOGHIM_TO_PIX(sz.cx, widget->logicalDpiX()), - MAP_LOGHIM_TO_PIX(sz.cy, widget->logicalDpiY())); - } - return QSize(); + return SUCCEEDED(m_spOleObject->GetExtent(DVASPECT_CONTENT, &sz)) + ? qaxMapLogHiMetricsToPix(sz, widget) : QSize(); } void QAxClientSite::windowActivationChange() @@ -1662,14 +1658,11 @@ void QAxHostWidget::resizeObject() return; } - SIZEL hmSize; - hmSize.cx = MAP_PIX_TO_LOGHIM(width(), logicalDpiX()); - hmSize.cy = MAP_PIX_TO_LOGHIM(height(), logicalDpiY()); - + SIZEL hmSize = qaxMapPixToLogHiMetrics(size(), this); if (axhost->m_spOleObject) axhost->m_spOleObject->SetExtent(DVASPECT_CONTENT, &hmSize); if (axhost->m_spInPlaceObject) { - RECT rcPos = { x(), y(), x()+width(), y()+height() }; + RECT rcPos = qaxNativeWidgetRect(this); axhost->m_spInPlaceObject->SetObjectRects(&rcPos, &rcPos); } } @@ -1709,7 +1702,7 @@ bool QAxHostWidget::event(QEvent *e) if (axhost && ((QTimerEvent*)e)->timerId() == setFocusTimer) { killTimer(setFocusTimer); setFocusTimer = 0; - RECT rcPos = { x(), y(), x()+size().width(), y()+size().height() }; + RECT rcPos = qaxNativeWidgetRect(this); axhost->m_spOleObject->DoVerb(OLEIVERB_UIACTIVATE, 0, (IOleClientSite*)axhost, 0, (HWND)winId(), &rcPos); @@ -1801,7 +1794,7 @@ void QAxHostWidget::paintEvent(QPaintEvent*) if (!view) return; - QPixmap pm(size()); + QPixmap pm(qaxNativeWidgetSize(this)); pm.fill(); HBITMAP hBmp = qaxPixmapToWinHBITMAP(pm); @@ -1818,7 +1811,9 @@ void QAxHostWidget::paintEvent(QPaintEvent*) view->Release(); QPainter painter(this); - painter.drawPixmap(0, 0, qaxPixmapFromWinHBITMAP(hBmp)); + QPixmap pixmap = qaxPixmapFromWinHBITMAP(hBmp); + pixmap.setDevicePixelRatio(devicePixelRatioF()); + painter.drawPixmap(0, 0, pixmap); SelectObject(hBmp_hdc, old_hBmp); DeleteObject(hBmp); diff --git a/src/activeqt/control/qaxserverbase.cpp b/src/activeqt/control/qaxserverbase.cpp index 5efdae9..b1eac89 100644 --- a/src/activeqt/control/qaxserverbase.cpp +++ b/src/activeqt/control/qaxserverbase.cpp @@ -346,10 +346,8 @@ public: RECT rcPosRect() const { RECT result = {0, 0, 1, 1}; - if (qt.widget) { - result.right = qt.widget->width() + 1; - result.bottom = qt.widget->height() + 1; - } + if (qt.widget) + result = qaxContentRect(QSize(1, 1) + qaxNativeWidgetSize(qt.widget)); return result; } @@ -419,7 +417,7 @@ private: IOleInPlaceFrame *m_spInPlaceFrame; ITypeInfo *m_spTypeInfo; IStorage *m_spStorage; - QSize m_currentExtent; + QSize m_currentExtent; // device independent pixels. }; static inline QAxServerBase *axServerBaseFromWindow(HWND hWnd) @@ -1447,7 +1445,7 @@ LRESULT QT_WIN_CALLBACK QAxServerBase::ActiveXProc(HWND hWnd, UINT uMsg, WPARAM case WM_SIZE: if (QAxServerBase *that = axServerBaseFromWindow(hWnd)) - that->resize(QSize(LOWORD(lParam), HIWORD(lParam))); + that->resize(qaxFromNativeSize(that->qt.widget, QSize(LOWORD(lParam), HIWORD(lParam)))); break; case WM_SETFOCUS: @@ -1563,6 +1561,9 @@ LRESULT QT_WIN_CALLBACK QAxServerBase::ActiveXProc(HWND hWnd, UINT uMsg, WPARAM } break; + case WM_DISPLAYCHANGE: + qaxClearCachedSystemLogicalDpi(); + default: break; } @@ -1868,7 +1869,7 @@ void QAxServerBase::updateMask() return; QRegion rgn = qt.widget->mask(); - HRGN hrgn = qaxHrgnFromQRegion(rgn); + HRGN hrgn = qaxHrgnFromQRegion(rgn, qt.widget); // Since SetWindowRegion takes ownership HRGN wr = CreateRectRgn(0,0,0,0); @@ -2636,11 +2637,10 @@ HRESULT WINAPI QAxServerBase::Invoke(DISPID dispidMember, REFIID riid, exception = 0; return DISP_E_EXCEPTION; } else if (isWidget) { - QSize sizeHint = qt.widget->sizeHint(); - if (oldSizeHint != sizeHint) { + if (oldSizeHint != qt.widget->sizeHint()) { updateGeometry(); if (m_spInPlaceSite) { - RECT rect = {0, 0, sizeHint.width(), sizeHint.height()}; + RECT rect = qaxContentRect(qaxToNativeSize(qt.widget, qt.widget->sizeHint())); m_spInPlaceSite->OnPosRectChange(&rect); } } @@ -3474,8 +3474,9 @@ HRESULT WINAPI QAxServerBase::SetObjectRects(LPCRECT prcPos, LPCRECT prcClip) } //Save the new extent. - m_currentExtent.rwidth() = qBound(qt.widget->minimumWidth(), int(prcPos->right - prcPos->left), qt.widget->maximumWidth()); - m_currentExtent.rheight() = qBound(qt.widget->minimumHeight(), int(prcPos->bottom - prcPos->top), qt.widget->maximumHeight()); + const QRect qr = qaxFromNativeRect(*prcPos, qt.widget); + m_currentExtent.rwidth() = qBound(qt.widget->minimumWidth(), qr.width(), qt.widget->maximumWidth()); + m_currentExtent.rheight() = qBound(qt.widget->minimumHeight(), qr.height(), qt.widget->maximumHeight()); return S_OK; } @@ -3944,8 +3945,7 @@ HRESULT WINAPI QAxServerBase::GetExtent(DWORD dwDrawAspect, SIZEL* psizel) if (!psizel) return E_POINTER; - psizel->cx = MAP_PIX_TO_LOGHIM(m_currentExtent.width(), qt.widget->logicalDpiX()); - psizel->cy = MAP_PIX_TO_LOGHIM(m_currentExtent.height(), qt.widget->logicalDpiY()); + *psizel = qaxMapPixToLogHiMetrics(m_currentExtent, qt.widget); return S_OK; } @@ -4034,8 +4034,7 @@ HRESULT WINAPI QAxServerBase::SetExtent(DWORD dwDrawAspect, SIZEL* psizel) if (!isWidget || !qt.widget) // nothing to do return S_OK; - QSize proposedSize(MAP_LOGHIM_TO_PIX(psizel->cx, qt.widget->logicalDpiX()), - MAP_LOGHIM_TO_PIX(psizel->cy, qt.widget->logicalDpiY())); + QSize proposedSize(qaxMapLogHiMetricsToPix(*psizel, qt.widget)); // can the widget be resized at all? if (qt.widget->minimumSize() == qt.widget->maximumSize() && qt.widget->minimumSize() != proposedSize) @@ -4112,8 +4111,7 @@ HRESULT WINAPI QAxServerBase::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmediu HRESULT hres = m_spInPlaceSite->GetWindowContext(&m_spInPlaceFrame, &spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo); if (hres == S_OK) { - QSize size(rcPos.right - rcPos.left, rcPos.bottom - rcPos.top); - resize(size); + resize(qaxFromNativeSize(qt.widget, qaxSizeOfRect(rcPos))); } else { qt.widget->adjustSize(); } @@ -4145,8 +4143,9 @@ HRESULT WINAPI QAxServerBase::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmediu LPMETAFILEPICT pMF = (LPMETAFILEPICT)GlobalLock(hMem); pMF->hMF = hMF; pMF->mm = MM_ANISOTROPIC; - pMF->xExt = MAP_PIX_TO_LOGHIM(width, qt.widget->logicalDpiX()); - pMF->yExt = MAP_PIX_TO_LOGHIM(height, qt.widget->logicalDpiY()); + const SIZEL sizeL = qaxMapPixToLogHiMetrics(QSize(width, height), qt.widget); + pMF->xExt = sizeL.cx; + pMF->yExt = sizeL.cy; GlobalUnlock(hMem); memset(pmedium, 0, sizeof(STGMEDIUM)); @@ -4267,7 +4266,7 @@ bool QAxServerBase::eventFilter(QObject *o, QEvent *e) } updateGeometry(); if (m_spInPlaceSite && qt.widget->sizeHint().isValid()) { - RECT rect = {0, 0, qt.widget->sizeHint().width(), qt.widget->sizeHint().height()}; + RECT rect = qaxContentRect(qaxToNativeSize(qt.widget, qt.widget->sizeHint())); m_spInPlaceSite->OnPosRectChange(&rect); } } diff --git a/src/activeqt/shared/qaxutils.cpp b/src/activeqt/shared/qaxutils.cpp index 7e5a9be..9f94835 100644 --- a/src/activeqt/shared/qaxutils.cpp +++ b/src/activeqt/shared/qaxutils.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -208,8 +209,9 @@ static void addRectToHrgn(HRGN &winRegion, const QRect &r) } } -HRGN qaxHrgnFromQRegion(const QRegion ®ion) +HRGN qaxHrgnFromQRegion(QRegion region, const QWindow *window) { + region = QHighDpi::toNativeLocalRegion(region, window); HRGN hRegion = CreateRectRgn(0, 0, 0, 0); if (region.rectCount() == 1) { addRectToHrgn(hRegion, region.boundingRect()); @@ -220,4 +222,128 @@ HRGN qaxHrgnFromQRegion(const QRegion ®ion) return hRegion; } +// HIMETRICS scaling +static const qreal himetricsPerInch = 2540; + +static inline long qaxMapPixToLogHiMetrics(int x, qreal logicalDpi, qreal factor) +{ + return qRound((qreal(x) * himetricsPerInch * factor) / logicalDpi); +} + +static inline int qaxMapLogHiMetricsToPix(long x, qreal logicalDpi, qreal factor) +{ + return qRound(logicalDpi * qreal(x) / (himetricsPerInch * factor)); +} + +SIZEL qaxMapPixToLogHiMetrics(const QSize &s, const QDpi &d, const QWindow *w) +{ + const qreal factor = QHighDpiScaling::factor(w); + const SIZEL result = { + qaxMapPixToLogHiMetrics(s.width(), d.first, factor), + qaxMapPixToLogHiMetrics(s.height(), d.second, factor) + }; + return result; +} + +QSize qaxMapLogHiMetricsToPix(const SIZEL &s, const QDpi &d, const QWindow *w) +{ + const qreal factor = QHighDpiScaling::factor(w); + const QSize result(qaxMapLogHiMetricsToPix(s.cx, d.first, factor), + qaxMapLogHiMetricsToPix(s.cy, d.second, factor)); + return result; +} + +// Cache logical DPI in case High DPI scaling is active (which case +// the fake logical DPI it calculates is not suitable). + +static QDpi cachedSystemLogicalDpi(-1, -1); + +void qaxClearCachedSystemLogicalDpi() // Call from WM_DISPLAYCHANGE +{ + cachedSystemLogicalDpi = QDpi(-1, -1); +} + +static inline QDpi systemLogicalDpi() +{ + if (cachedSystemLogicalDpi.first < 0) { + const HDC displayDC = GetDC(0); + cachedSystemLogicalDpi = QDpi(GetDeviceCaps(displayDC, LOGPIXELSX), GetDeviceCaps(displayDC, LOGPIXELSY)); + ReleaseDC(0, displayDC); + } + return cachedSystemLogicalDpi; +} + +static inline QDpi paintDeviceLogicalDpi(const QPaintDevice *d) +{ + return QDpi(d->logicalDpiX(), d->logicalDpiY()); +} + +#ifdef QT_WIDGETS_LIB + +SIZEL qaxMapPixToLogHiMetrics(const QSize &s, const QWidget *widget) +{ + return qaxMapPixToLogHiMetrics(s, + QHighDpiScaling::isActive() ? systemLogicalDpi() : paintDeviceLogicalDpi(widget), + widget->windowHandle()); +} + +QSize qaxMapLogHiMetricsToPix(const SIZEL &s, const QWidget *widget) +{ + return qaxMapLogHiMetricsToPix(s, + QHighDpiScaling::isActive() ? systemLogicalDpi() : paintDeviceLogicalDpi(widget), + widget->windowHandle()); +} + +QPoint qaxFromNativePosition(const QWidget *w, const QPoint &nativePos) +{ + const qreal factor = QHighDpiScaling::factor(w->windowHandle()); + return qFuzzyCompare(factor, 1) + ? nativePos : (QPointF(nativePos) / factor).toPoint(); +} + +QPoint qaxNativeWidgetPosition(const QWidget *w) +{ + return qaxFromNativePosition(w, w->geometry().topLeft()); +} + +QSize qaxToNativeSize(const QWidget *w, const QSize &size) +{ + const qreal factor = QHighDpiScaling::factor(w->windowHandle()); + return qFuzzyCompare(factor, 1) ? size : (QSizeF(size) * factor).toSize(); +} + +QSize qaxNativeWidgetSize(const QWidget *w) +{ + return qaxToNativeSize(w, w->size()); +} + +QSize qaxFromNativeSize(const QWidget *w, const QSize &size) +{ + const qreal factor = QHighDpiScaling::factor(w->windowHandle()); + return qFuzzyCompare(factor, 1) ? size : (QSizeF(size) / factor).toSize(); +} + +RECT qaxNativeWidgetRect(const QWidget *w) +{ + return QHighDpiScaling::isActive() + ? qaxQRect2Rect(QRect(qaxNativeWidgetPosition(w), qaxNativeWidgetSize(w))) + : qaxQRect2Rect(w->geometry()); +} + +QRect qaxFromNativeRect(const RECT &r, const QWidget *w) +{ + const QRect qr = qaxRect2QRect(r); + const qreal factor = QHighDpiScaling::factor(w->windowHandle()); + return qFuzzyCompare(factor, 1) + ? qr + : QRect((QPointF(qr.topLeft()) / factor).toPoint(), (QSizeF(qr.size()) / factor).toSize()); +} + +HRGN qaxHrgnFromQRegion(const QRegion ®ion, const QWidget *widget) +{ + return qaxHrgnFromQRegion(region, widget->windowHandle()); +} + +#endif // QT_WIDGETS_LIB + QT_END_NAMESPACE diff --git a/src/activeqt/shared/qaxutils_p.h b/src/activeqt/shared/qaxutils_p.h index 75a4c89..acd0eb8 100644 --- a/src/activeqt/shared/qaxutils_p.h +++ b/src/activeqt/shared/qaxutils_p.h @@ -54,6 +54,8 @@ #include #include +#include +#include QT_BEGIN_NAMESPACE @@ -61,6 +63,7 @@ class QWidget; class QPixmap; class QRect; class QRegion; +class QWindow; enum HBitmapFormat { @@ -72,7 +75,50 @@ enum HBitmapFormat HWND hwndForWidget(QWidget *widget); HBITMAP qaxPixmapToWinHBITMAP(const QPixmap &p, HBitmapFormat format = HBitmapNoAlpha); QPixmap qaxPixmapFromWinHBITMAP(HBITMAP bitmap, HBitmapFormat format = HBitmapNoAlpha); -HRGN qaxHrgnFromQRegion(const QRegion ®ion); +HRGN qaxHrgnFromQRegion(QRegion region, const QWindow *window); + +typedef QPair QDpi; + +extern SIZEL qaxMapPixToLogHiMetrics(const QSize &s, const QDpi &d, const QWindow *w); +extern QSize qaxMapLogHiMetricsToPix(const SIZEL &s, const QDpi &d, const QWindow *w); + +void qaxClearCachedSystemLogicalDpi(); // Call from WM_DISPLAYCHANGE + +static inline RECT qaxQRect2Rect(const QRect &r) +{ + RECT result = { r.x(), r.y(), r.x() + r.width(), r.y() + r.height() }; + return result; +} + +static inline QSize qaxSizeOfRect(const RECT &rect) +{ + return QSize(rect.right -rect.left, rect.bottom - rect.top); +} + +static inline QRect qaxRect2QRect(const RECT &rect) +{ + return QRect(QPoint(rect.left, rect.top), qaxSizeOfRect(rect)); +} + +static inline RECT qaxContentRect(const QSize &size) // Size with topleft = 0,0 +{ + RECT result = { 0, 0, size.width(), size.height() }; + return result; +} + +#ifdef QT_WIDGETS_LIB +SIZEL qaxMapPixToLogHiMetrics(const QSize &s, const QWidget *widget); +QSize qaxMapLogHiMetricsToPix(const SIZEL &s, const QWidget *widget); + +QPoint qaxFromNativePosition(const QWidget *w, const QPoint &nativePos); +QPoint qaxNativeWidgetPosition(const QWidget *w); +QSize qaxToNativeSize(const QWidget *w, const QSize &size); +QSize qaxFromNativeSize(const QWidget *w, const QSize &size); +QSize qaxNativeWidgetSize(const QWidget *w); +RECT qaxNativeWidgetRect(const QWidget *w); +QRect qaxFromNativeRect(const RECT &r, const QWidget *w); +HRGN qaxHrgnFromQRegion(const QRegion ®ion, const QWidget *widget); +#endif // QT_WIDGETS_LIB QT_END_NAMESPACE -- cgit v1.2.3