summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp66
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h4
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp30
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h2
4 files changed, 74 insertions, 28 deletions
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 40d4cb1497..c8c09bebff 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -380,6 +380,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;
@@ -808,7 +813,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;
@@ -839,6 +846,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)) {
@@ -1020,9 +1028,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;
@@ -1195,6 +1200,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.
@@ -1208,7 +1244,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
@@ -1218,6 +1256,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 9dfde67797..41405f8efc 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -181,12 +181,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 2d9a683da6..2f7abc6de8 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -1681,7 +1681,6 @@ QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt,
QWindowsWindowData result = m_data;
result.flags = creationData.flags;
result.embedded = creationData.embedded;
- setFlag(FrameDirty);
return result;
}
@@ -1689,7 +1688,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) {
@@ -1766,8 +1764,6 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
const bool visible = isVisible();
- setFlag(FrameDirty);
-
if ((oldState == Qt::WindowFullScreen) != (newState == Qt::WindowFullScreen)) {
if (newState == Qt::WindowFullScreen) {
#ifndef Q_FLATTEN_EXPOSE
@@ -1861,7 +1857,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);
}
@@ -1870,7 +1865,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);
}
@@ -1926,22 +1920,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)
@@ -2357,7 +2346,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 90b0940813..dd433a3ca8 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -189,7 +189,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,
@@ -244,6 +243,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 &region) Q_DECL_OVERRIDE;