Windows QPA: Fix broken frame geometry when moving windows with native menus

QWindowsWindow::updateFullFrameMargins() which is called
from the screen changed handling does not take native menus
into account.

Since the size of the menu is not known when using
EnableNonClientDpiScaling(), obtaining the correct frame
size requires triggering a WM_NCCALCSIZE message. Extract
the helper forceNcCalcSize() from QWindowsMenu and
use that from updateFullFrameMargins() in case menus are present.

Amends d2fd9b1b98.

Fixes: QTBUG-82580
Change-Id: I306f1faf84e26c88608cb22ffd42eccc848905c3
Reviewed-by: André de la Rocha <andre.rocha@qt.io>
This commit is contained in:
Friedemann Kleint 2020-03-09 11:07:42 +01:00
parent d8ab719c08
commit 1d403ef81a
5 changed files with 23 additions and 10 deletions

View File

@ -978,6 +978,13 @@ QByteArray QWindowsContext::comErrorString(HRESULT hr)
return result;
}
void QWindowsContext::forceNcCalcSize(HWND hwnd)
{
// Force WM_NCCALCSIZE to adjust margin
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
}
bool QWindowsContext::systemParametersInfo(unsigned action, unsigned param, void *out,
unsigned dpi)
{

View File

@ -246,6 +246,8 @@ public:
bool asyncExpose() const;
void setAsyncExpose(bool value);
static void forceNcCalcSize(HWND hwnd);
static bool systemParametersInfo(unsigned action, unsigned param, void *out, unsigned dpi = 0);
static bool systemParametersInfoForScreen(unsigned action, unsigned param, void *out,
const QPlatformScreen *screen = nullptr);

View File

@ -794,20 +794,13 @@ QWindowsMenuBar *QWindowsMenuBar::menuBarOf(const QWindow *notYetCreatedWindow)
? qobject_cast<QWindowsMenuBar *>(menuBarV.value<QObject *>()) : nullptr;
}
static inline void forceNcCalcSize(HWND hwnd)
{
// Force WM_NCCALCSIZE to adjust margin: Does not appear to work?
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
}
void QWindowsMenuBar::install(QWindowsWindow *window)
{
const HWND hwnd = window->handle();
const BOOL result = SetMenu(hwnd, m_hMenuBar);
if (result) {
window->setMenuBar(this);
forceNcCalcSize(hwnd);
QWindowsContext::forceNcCalcSize(hwnd);
}
}
@ -817,7 +810,7 @@ void QWindowsMenuBar::removeFromWindow()
const HWND hwnd = window->handle();
SetMenu(hwnd, nullptr);
window->setMenuBar(nullptr);
forceNcCalcSize(hwnd);
QWindowsContext::forceNcCalcSize(hwnd);
}
}

View File

@ -2431,7 +2431,17 @@ void QWindowsWindow::setFullFrameMargins(const QMargins &newMargins)
void QWindowsWindow::updateFullFrameMargins()
{
// Normally obtained from WM_NCCALCSIZE
// QTBUG-82580: If a native menu is present, force a WM_NCCALCSIZE.
if (GetMenu(m_data.hwnd))
QWindowsContext::forceNcCalcSize(m_data.hwnd);
else
calculateFullFrameMargins();
}
void QWindowsWindow::calculateFullFrameMargins()
{
// Normally obtained from WM_NCCALCSIZE. This calculation only works
// when no native menu is present.
const auto systemMargins = testFlag(DisableNonClientScaling)
? QWindowsGeometryHint::frameOnPrimaryScreen(m_data.hwnd)
: frameMargins_sys();

View File

@ -370,6 +370,7 @@ private:
void handleWindowStateChange(Qt::WindowStates state);
inline void destroyIcon();
void fireExpose(const QRegion &region, bool force=false);
void calculateFullFrameMargins();
mutable QWindowsWindowData m_data;
QPointer<QWindowsMenuBar> m_menuBar;