vlc | branch: master | Hugo Beauzée-Luyssen <[email protected]> | Tue Mar 7 15:11:04 2017 +0100| [a828bc2d99a208ec19b6410ae9b27d38f8cdc45f] | committer: Hugo Beauzée-Luyssen
contribs: qt: Fix win32 window decorations on HiDPI screens https://bugreports.qt.io/browse/QTBUG-53255 As a side note, Qt have been asked to include those patches included in Qt 5.6.x branch, but it won't happen until 5.9 gets released, if ever. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=a828bc2d99a208ec19b6410ae9b27d38f8cdc45f --- ...implement-calculation-of-window-frames_56.patch | 271 +++++++++++++++++++++ ...e-new-EnableNonClientDpiScaling-for-Wi_56.patch | 135 ++++++++++ contrib/src/qt/rules.mak | 2 + 3 files changed, 408 insertions(+) diff --git a/contrib/src/qt/0001-Windows-QPA-Reimplement-calculation-of-window-frames_56.patch b/contrib/src/qt/0001-Windows-QPA-Reimplement-calculation-of-window-frames_56.patch new file mode 100644 index 0000000..f958f2b --- /dev/null +++ b/contrib/src/qt/0001-Windows-QPA-Reimplement-calculation-of-window-frames_56.patch @@ -0,0 +1,271 @@ +From 81ead1ff68711fed609cb47b33b3906c14ed95d5 Mon Sep 17 00:00:00 2001 +From: Friedemann Kleint <[email protected]> +Date: Mon, 14 Nov 2016 16:08:51 +0100 +Subject: [PATCH 1/2] Windows QPA: Reimplement calculation of window frames + +Instead of relying on AdjustWindowRectEx() and dirty-handling, +capture the rectangles before and after the processing of +WM_NCCALCSIZE and calculate the frame from that. This allows +for changing window frames by handling WM_NCCALCSIZE and +monitor-dependent window frames when using High DPI scaling. + +Task-number: QTBUG-53255 +Task-number: QTBUG-40578 +Task-number: QTBUG-56591 +Change-Id: If8364a5440a6324ea5d470bf5b74e68942285abe +Reviewed-by: Tim Jenssen <[email protected]> +Reviewed-by: Oliver Wolff <[email protected]> +--- + src/plugins/platforms/windows/qwindowscontext.cpp | 66 +++++++++++++++++++++-- + src/plugins/platforms/windows/qwindowscontext.h | 4 +- + src/plugins/platforms/windows/qwindowswindow.cpp | 30 ++++------- + src/plugins/platforms/windows/qwindowswindow.h | 2 +- + 4 files changed, 74 insertions(+), 28 deletions(-) + +diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp +index b611843..9058993 100644 +--- a/src/plugins/platforms/windows/qwindowscontext.cpp ++++ b/src/plugins/platforms/windows/qwindowscontext.cpp +@@ -453,6 +453,11 @@ void QWindowsContext::setWindowCreationContext(const QSharedPointer<QWindowCreat + d->m_creationContext = ctx; + } + ++QSharedPointer<QWindowCreationContext> QWindowsContext::windowCreationContext() const ++{ ++ return d->m_creationContext; ++} ++ + int QWindowsContext::defaultDPI() const + { + return d->m_defaultDPI; +@@ -916,7 +921,9 @@ static inline QWindowsInputContext *windowsInputContext() + + bool QWindowsContext::windowsProc(HWND hwnd, UINT message, + QtWindows::WindowsEventType et, +- WPARAM wParam, LPARAM lParam, LRESULT *result) ++ WPARAM wParam, LPARAM lParam, ++ LRESULT *result, ++ QWindowsWindow **platformWindowPtr) + { + *result = 0; + +@@ -949,6 +956,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, + } + + QWindowsWindow *platformWindow = findPlatformWindow(hwnd); ++ *platformWindowPtr = platformWindow; + if (platformWindow) { + filterResult = 0; + if (QWindowSystemInterface::handleNativeEvent(platformWindow->window(), d->m_eventType, &msg, &filterResult)) { +@@ -1144,9 +1152,6 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, + return true; + case QtWindows::ThemeChanged: { + // Switch from Aero to Classic changes margins. +- const Qt::WindowFlags flags = platformWindow->window()->flags(); +- if ((flags & Qt::WindowType_Mask) != Qt::Desktop && !(flags & Qt::FramelessWindowHint)) +- platformWindow->setFlag(QWindowsWindow::FrameDirty); + if (QWindowsTheme *theme = QWindowsTheme::instance()) + theme->windowsThemeChanged(platformWindow->window()); + return true; +@@ -1318,6 +1323,37 @@ QTouchDevice *QWindowsContext::touchDevice() const + return d->m_mouseHandler.touchDevice(); + } + ++static inline bool isEmptyRect(const RECT &rect) ++{ ++ return rect.right - rect.left == 0 && rect.bottom - rect.top == 0; ++} ++ ++static inline QMargins marginsFromRects(const RECT &frame, const RECT &client) ++{ ++ return QMargins(client.left - frame.left, client.top - frame.top, ++ frame.right - client.right, frame.bottom - client.bottom); ++} ++ ++static RECT rectFromNcCalcSize(UINT message, WPARAM wParam, LPARAM lParam, int n) ++{ ++ RECT result = {0, 0, 0, 0}; ++ if (message == WM_NCCALCSIZE && wParam) ++ result = reinterpret_cast<const NCCALCSIZE_PARAMS *>(lParam)->rgrc[n]; ++ return result; ++} ++ ++static inline bool isMinimized(HWND hwnd) ++{ ++ WINDOWPLACEMENT windowPlacement; ++ windowPlacement.length = sizeof(WINDOWPLACEMENT); ++ return GetWindowPlacement(hwnd, &windowPlacement) && windowPlacement.showCmd == SW_SHOWMINIMIZED; ++} ++ ++static inline bool isTopLevel(HWND hwnd) ++{ ++ return (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILD) == 0; ++} ++ + /*! + \brief Windows functions for actual windows. + +@@ -1331,7 +1367,9 @@ extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPAR + { + LRESULT result; + const QtWindows::WindowsEventType et = windowsEventType(message, wParam, lParam); +- const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result); ++ QWindowsWindow *platformWindow = nullptr; ++ const RECT ncCalcSizeFrame = rectFromNcCalcSize(message, wParam, lParam, 0); ++ const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result, &platformWindow); + if (QWindowsContext::verbose > 1 && lcQpaEvents().isDebugEnabled()) { + if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message)) { + qCDebug(lcQpaEvents) << "EVENT: hwd=" << hwnd << eventName << hex << "msg=0x" << message +@@ -1341,6 +1379,24 @@ extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPAR + } + if (!handled) + result = DefWindowProc(hwnd, message, wParam, lParam); ++ ++ // Capture WM_NCCALCSIZE on top level windows and obtain the window margins by ++ // subtracting the rectangles before and after processing. This will correctly ++ // capture client code overriding the message and allow for per-monitor margins ++ // for High DPI (QTBUG-53255, QTBUG-40578). ++ if (message == WM_NCCALCSIZE && !isEmptyRect(ncCalcSizeFrame) && isTopLevel(hwnd) && !isMinimized(hwnd)) { ++ const QMargins margins = ++ marginsFromRects(ncCalcSizeFrame, rectFromNcCalcSize(message, wParam, lParam, 0)); ++ if (margins.left() >= 0) { ++ if (platformWindow) { ++ platformWindow->setFrameMargins(margins); ++ } else { ++ const QSharedPointer<QWindowCreationContext> ctx = QWindowsContext::instance()->windowCreationContext(); ++ if (!ctx.isNull()) ++ ctx->margins = margins; ++ } ++ } ++ } + return result; + } + +diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h +index 14baec9..dcac77c 100644 +--- a/src/plugins/platforms/windows/qwindowscontext.h ++++ b/src/plugins/platforms/windows/qwindowscontext.h +@@ -210,12 +210,14 @@ public: + + inline bool windowsProc(HWND hwnd, UINT message, + QtWindows::WindowsEventType et, +- WPARAM wParam, LPARAM lParam, LRESULT *result); ++ WPARAM wParam, LPARAM lParam, LRESULT *result, ++ QWindowsWindow **platformWindowPtr); + + QWindow *keyGrabber() const; + void setKeyGrabber(QWindow *hwnd); + + void setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx); ++ QSharedPointer<QWindowCreationContext> windowCreationContext() const; + + void setTabletAbsoluteRange(int a); + void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness); +diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp +index b38d7c2..11ba9c1 100644 +--- a/src/plugins/platforms/windows/qwindowswindow.cpp ++++ b/src/plugins/platforms/windows/qwindowswindow.cpp +@@ -1630,7 +1630,6 @@ QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt, + QWindowsWindowData result = m_data; + result.flags = creationData.flags; + result.embedded = creationData.embedded; +- setFlag(FrameDirty); + return result; + } + +@@ -1638,7 +1637,6 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowState state) + { + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() + << "\n from " << m_windowState << " to " << state; +- setFlag(FrameDirty); + m_windowState = state; + QWindowSystemInterface::handleWindowStateChanged(window(), state); + switch (state) { +@@ -1715,8 +1713,6 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) + + const bool visible = isVisible(); + +- setFlag(FrameDirty); +- + if ((oldState == Qt::WindowFullScreen) != (newState == Qt::WindowFullScreen)) { + #ifdef Q_OS_WINCE + HWND handle = FindWindow(L"HHTaskBar", L""); +@@ -1826,7 +1822,6 @@ void QWindowsWindow::setStyle(unsigned s) const + { + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << debugWinStyle(s); + setFlag(WithinSetStyle); +- setFlag(FrameDirty); + SetWindowLongPtr(m_data.hwnd, GWL_STYLE, s); + clearFlag(WithinSetStyle); + } +@@ -1835,7 +1830,6 @@ void QWindowsWindow::setExStyle(unsigned s) const + { + qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << this << ' ' << window() + << " 0x" << QByteArray::number(s, 16); +- setFlag(FrameDirty); + SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s); + } + +@@ -1909,22 +1903,17 @@ bool QWindowsWindow::handleGeometryChanging(MSG *message) const + return QWindowsWindow::handleGeometryChangingMessage(message, window(), margins); + } + +-QMargins QWindowsWindow::frameMargins() const ++void QWindowsWindow::setFrameMargins(const QMargins &newMargins) + { +- // Frames are invalidated by style changes (window state, flags). +- // As they are also required for geometry calculations in resize +- // event sequences, introduce a dirty flag mechanism to be able +- // to cache results. +- if (testFlag(FrameDirty)) { +- // Always skip calculating style-dependent margins for windows claimed to be frameless. +- // This allows users to remove the margins by handling WM_NCCALCSIZE with WS_THICKFRAME set +- // to ensure Areo snap still works (QTBUG-40578). +- m_data.frame = m_data.flags & Qt::FramelessWindowHint +- ? QMargins(0, 0, 0, 0) +- : QWindowsGeometryHint::frame(style(), exStyle()); +- clearFlag(FrameDirty); ++ if (m_data.frame != newMargins) { ++ qCDebug(lcQpaWindows) << __FUNCTION__ << window() << m_data.frame << "->" << newMargins; ++ m_data.frame = newMargins; + } +- return m_data.frame + m_data.customMargins; ++} ++ ++QMargins QWindowsWindow::frameMargins() const ++{ ++ return m_data.frame; + } + + void QWindowsWindow::setOpacity(qreal level) +@@ -2322,7 +2311,6 @@ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) + const QPoint topLeft = currentFrameGeometry.topLeft(); + QRect newFrame = currentFrameGeometry.marginsRemoved(oldCustomMargins) + m_data.customMargins; + newFrame.moveTo(topLeft); +- setFlag(FrameDirty); + qCDebug(lcQpaWindows) << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins + << currentFrameGeometry << "->" << newFrame; + SetWindowPos(m_data.hwnd, 0, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED); +diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h +index 6fffa1e..0e150a8 100644 +--- a/src/plugins/platforms/windows/qwindowswindow.h ++++ b/src/plugins/platforms/windows/qwindowswindow.h +@@ -119,7 +119,6 @@ public: + { + AutoMouseCapture = 0x1, //! Automatic mouse capture on button press. + WithinSetParent = 0x2, +- FrameDirty = 0x4, //! Frame outdated by setStyle, recalculate in next query. + OpenGLSurface = 0x10, + OpenGL_ES2 = 0x20, + OpenGLDoubleBuffered = 0x40, +@@ -177,6 +176,7 @@ public: + static bool handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &marginsDp); + bool handleGeometryChanging(MSG *message) const; + QMargins frameMargins() const Q_DECL_OVERRIDE; ++ void setFrameMargins(const QMargins &newMargins); + + void setOpacity(qreal level) Q_DECL_OVERRIDE; + void setMask(const QRegion ®ion) Q_DECL_OVERRIDE; +-- +2.9.0.windows.1 + diff --git a/contrib/src/qt/0002-Windows-QPA-Use-new-EnableNonClientDpiScaling-for-Wi_56.patch b/contrib/src/qt/0002-Windows-QPA-Use-new-EnableNonClientDpiScaling-for-Wi_56.patch new file mode 100644 index 0000000..ff7986d --- /dev/null +++ b/contrib/src/qt/0002-Windows-QPA-Use-new-EnableNonClientDpiScaling-for-Wi_56.patch @@ -0,0 +1,135 @@ +From 8f39b5247c4f7766553131688f5d5b7193327336 Mon Sep 17 00:00:00 2001 +From: Friedemann Kleint <[email protected]> +Date: Mon, 7 Nov 2016 14:22:37 +0100 +Subject: [PATCH 2/2] Windows QPA: Use new EnableNonClientDpiScaling() for + Windows decoration + +Use newly introduced EnableNonClientDpiScaling() function to fix +the decoration having the wrong size in multimonitor setups with +per-monitor DPI awareness. + +Task-number: QTBUG-53255 +Change-Id: Ic6e2f2a92f790259107d2a0837b96177cf3adb5f +Reviewed-by: Tim Jenssen <[email protected]> +--- + src/plugins/platforms/windows/qtwindowsglobal.h | 3 ++ + src/plugins/platforms/windows/qwindowscontext.cpp | 35 ++++++++++++++++++++++- + src/plugins/platforms/windows/qwindowscontext.h | 7 +++++ + 3 files changed, 44 insertions(+), 1 deletion(-) + +diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h +index 63c083d..e7e010d 100644 +--- a/src/plugins/platforms/windows/qtwindowsglobal.h ++++ b/src/plugins/platforms/windows/qtwindowsglobal.h +@@ -87,6 +87,7 @@ enum WindowsEventType // Simplify event types + TouchEvent = TouchEventFlag + 1, + NonClientMouseEvent = NonClientEventFlag + MouseEventFlag + 1, + NonClientHitTest = NonClientEventFlag + 2, ++ NonClientCreate = NonClientEventFlag + 3, + KeyEvent = KeyEventFlag + 1, + KeyDownEvent = KeyEventFlag + KeyDownEventFlag + 1, + KeyboardLayoutChangeEvent = KeyEventFlag + 2, +@@ -164,6 +165,8 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI + return QtWindows::HideEvent; + case WM_SIZE: + return QtWindows::ResizeEvent; ++ case WM_NCCREATE: ++ return QtWindows::NonClientCreate; + case WM_NCCALCSIZE: + return QtWindows::CalculateSize; + #ifndef Q_OS_WINCE +diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp +index 9058993..ab0b3da 100644 +--- a/src/plugins/platforms/windows/qwindowscontext.cpp ++++ b/src/plugins/platforms/windows/qwindowscontext.cpp +@@ -140,6 +140,28 @@ static inline QWindowsSessionManager *platformSessionManager() { + } + #endif + ++static inline int windowDpiAwareness(HWND hwnd) ++{ ++ return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getWindowDpiAwarenessContext ++ ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext(QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd)) ++ : -1; ++} ++ ++// Note: This only works within WM_NCCREATE ++static bool enableNonClientDpiScaling(HWND hwnd) ++{ ++ bool result = false; ++ if (QWindowsContext::user32dll.enableNonClientDpiScaling && windowDpiAwareness(hwnd) == 2) { ++ result = QWindowsContext::user32dll.enableNonClientDpiScaling(hwnd) != FALSE; ++ if (!result) { ++ const DWORD errorCode = GetLastError(); ++ qErrnoWarning(int(errorCode), "EnableNonClientDpiScaling() failed for HWND %p (%lu)", ++ hwnd, errorCode); ++ } ++ } ++ return result; ++} ++ + /*! + \class QWindowsUser32DLL + \brief Struct that contains dynamically resolved symbols of User32.dll. +@@ -165,7 +187,8 @@ QWindowsUser32DLL::QWindowsUser32DLL() : + registerTouchWindow(0), unregisterTouchWindow(0), + getTouchInputInfo(0), closeTouchInputHandle(0), setProcessDPIAware(0), + addClipboardFormatListener(0), removeClipboardFormatListener(0), +- getDisplayAutoRotationPreferences(0), setDisplayAutoRotationPreferences(0) ++ getDisplayAutoRotationPreferences(0), setDisplayAutoRotationPreferences(0), ++ enableNonClientDpiScaling(0), getWindowDpiAwarenessContext(0), getAwarenessFromDpiAwarenessContext(0) + { + } + +@@ -188,6 +211,12 @@ void QWindowsUser32DLL::init() + } + getDisplayAutoRotationPreferences = (GetDisplayAutoRotationPreferences)library.resolve("GetDisplayAutoRotationPreferences"); + setDisplayAutoRotationPreferences = (SetDisplayAutoRotationPreferences)library.resolve("SetDisplayAutoRotationPreferences"); ++ ++ if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS10) { // Appears in 10.0.14393, October 2016 ++ enableNonClientDpiScaling = (EnableNonClientDpiScaling)library.resolve("EnableNonClientDpiScaling"); ++ getWindowDpiAwarenessContext = (GetWindowDpiAwarenessContext)library.resolve("GetWindowDpiAwarenessContext"); ++ getAwarenessFromDpiAwarenessContext = (GetAwarenessFromDpiAwarenessContext)library.resolve("GetAwarenessFromDpiAwarenessContext"); ++ } + } + + bool QWindowsUser32DLL::initTouch() +@@ -1040,6 +1069,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, + case QtWindows::MoveEvent: + d->m_creationContext->obtainedGeometry.moveTo(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + return true; ++ case QtWindows::NonClientCreate: ++ if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS10 && d->m_creationContext->window->isTopLevel()) ++ enableNonClientDpiScaling(msg.hwnd); ++ return false; + case QtWindows::CalculateSize: + return QWindowsGeometryHint::handleCalculateSize(d->m_creationContext->customMargins, msg, result); + case QtWindows::GeometryChangingEvent: +diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h +index dcac77c..156ede5 100644 +--- a/src/plugins/platforms/windows/qwindowscontext.h ++++ b/src/plugins/platforms/windows/qwindowscontext.h +@@ -96,6 +96,9 @@ struct QWindowsUser32DLL + typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND); + typedef BOOL (WINAPI *GetDisplayAutoRotationPreferences)(DWORD *); + typedef BOOL (WINAPI *SetDisplayAutoRotationPreferences)(DWORD); ++ typedef BOOL (WINAPI *EnableNonClientDpiScaling)(HWND); ++ typedef int (WINAPI *GetWindowDpiAwarenessContext)(HWND); ++ typedef int (WINAPI *GetAwarenessFromDpiAwarenessContext)(int); + + // Functions missing in Q_CC_GNU stub libraries. + SetLayeredWindowAttributes setLayeredWindowAttributes; +@@ -122,6 +125,10 @@ struct QWindowsUser32DLL + // Rotation API + GetDisplayAutoRotationPreferences getDisplayAutoRotationPreferences; + SetDisplayAutoRotationPreferences setDisplayAutoRotationPreferences; ++ ++ EnableNonClientDpiScaling enableNonClientDpiScaling; ++ GetWindowDpiAwarenessContext getWindowDpiAwarenessContext; ++ GetAwarenessFromDpiAwarenessContext getAwarenessFromDpiAwarenessContext; + }; + + struct QWindowsShell32DLL +-- +2.9.0.windows.1 + diff --git a/contrib/src/qt/rules.mak b/contrib/src/qt/rules.mak index 849d646..3c820f7 100644 --- a/contrib/src/qt/rules.mak +++ b/contrib/src/qt/rules.mak @@ -22,6 +22,8 @@ $(TARBALLS)/qt-$(QT_VERSION).tar.xz: qt: qt-$(QT_VERSION).tar.xz .sum-qt $(UNPACK) mv qtbase-opensource-src-$(QT_VERSION) qt-$(QT_VERSION) + $(APPLY) $(SRC)/qt/0001-Windows-QPA-Reimplement-calculation-of-window-frames_56.patch + $(APPLY) $(SRC)/qt/0002-Windows-QPA-Use-new-EnableNonClientDpiScaling-for-Wi_56.patch $(MOVE) ifdef HAVE_MACOSX _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
