win32: fix restore geometry bug

The upstream fix has not been merged yet, however, it will be in 6.5.1 for sure.

Fixes: #20

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2023-04-20 16:06:19 +08:00 committed by Yuhang Zhao
parent 8930ea128f
commit a203e2c3ca
5 changed files with 109 additions and 6 deletions

View File

@ -161,10 +161,10 @@ if(NOT FRAMELESSHELPER_NO_SUMMARY)
message("Toolchain file: ${CMAKE_TOOLCHAIN_FILE}")
message("------------------------------ Qt -------------------------------")
query_qt_paths(SDK_DIR __qt_inst_dir)
query_qt_library_info(VERSION __qt_version STATIC __qt_static_lib)
message("Qt SDK installation directory: ${__qt_inst_dir}")
message("Qt SDK version: ${QT_VERSION}")
query_qt_library_info(STATIC __qt_lib_type)
if(__qt_lib_type)
message("Qt SDK version: ${__qt_version}")
if(__qt_static_lib)
message("Qt SDK library type: static")
else()
message("Qt SDK library type: shared")

2
cmake

@ -1 +1 @@
Subproject commit 60329b55dcfaf41da63f134a90ddce82dc9b6c4a
Subproject commit be821fca7e90858343540a487d663dca52bf0cd5

View File

@ -135,6 +135,8 @@ FRAMELESSHELPER_CORE_API void fixupChildWindowsDpiMessage(const WId windowId);
FRAMELESSHELPER_CORE_API void fixupDialogsDpiScaling();
FRAMELESSHELPER_CORE_API void setDarkModeAllowedForApp(const bool allow = true);
FRAMELESSHELPER_CORE_API void bringWindowToFront(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint getWindowPlacementOffset(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API QRect getWindowRestoreFrameGeometry(const WId windowId);
#endif // Q_OS_WINDOWS
#ifdef Q_OS_LINUX

View File

@ -84,6 +84,8 @@ FRAMELESSHELPER_STRING_CONSTANT(TrackMouseEvent)
FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
FRAMELESSHELPER_STRING_CONSTANT(UnregisterClassW)
FRAMELESSHELPER_STRING_CONSTANT(DestroyWindow)
FRAMELESSHELPER_STRING_CONSTANT(GetWindowPlacement)
FRAMELESSHELPER_STRING_CONSTANT(SetWindowPlacement)
[[maybe_unused]] static constexpr const char kFallbackTitleBarErrorMessage[] =
"FramelessHelper is unable to create the fallback title bar window, and thus the snap layout feature will be disabled"
" unconditionally. You can ignore this error and continue running your application, nothing else will be affected, "
@ -98,6 +100,7 @@ struct Win32HelperData
bool trackingMouse = false;
WId fallbackTitleBarWindowId = 0;
Dpi dpi = {};
QRect restoreGeometry = {};
};
struct Win32Helper
@ -1184,10 +1187,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
#if (QT_VERSION <= QT_VERSION_CHECK(6, 4, 2))
// We need to wait until Qt has handled this message, otherwise everything
// we have done here will always be overwritten.
QTimer::singleShot(0, qApp, [data](){ // Copy the variables intentionally, otherwise they'll go out of scope when Qt finally use them.
QWindow *window = data.params.getWindowHandle();
QTimer::singleShot(0, qApp, [window](){
// Sync the internal window frame margins with the latest DPI, otherwise
// we will get wrong window sizes after the DPI change.
Utils::updateInternalWindowFrameMargins(data.params.getWindowHandle(), true);
Utils::updateInternalWindowFrameMargins(window, true);
});
#endif // (QT_VERSION <= QT_VERSION_CHECK(6, 4, 2))
} break;
@ -1195,6 +1199,50 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// Re-apply the custom window frame if recovered from the basic theme.
Utils::updateWindowFrameMargins(windowId, false);
} break;
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
case WM_ENTERSIZEMOVE:
case WM_EXITSIZEMOVE: {
if (!Utils::isWindowNoState(windowId)) {
break;
}
const QRect rect = Utils::getWindowRestoreFrameGeometry(windowId);
if (rect.isNull() || !rect.isValid()) {
WARNING << "The calculated restore geometry is invalid.";
break;
}
const QMutexLocker locker(&g_win32Helper()->mutex);
g_win32Helper()->data[windowId].restoreGeometry = rect;
} break;
case WM_SIZE: {
if (wParam != SIZE_MAXIMIZED) {
break;
}
if (data.restoreGeometry.isNull() || !data.restoreGeometry.isValid()) {
const QRect rect = Utils::getWindowRestoreFrameGeometry(windowId);
if (rect.isValid() && !rect.isNull()) {
const QMutexLocker locker(&g_win32Helper()->mutex);
g_win32Helper()->data[windowId].restoreGeometry = rect;
} else {
WARNING << "The calculated restore geometry is invalid.";
}
break;
}
WINDOWPLACEMENT wp;
SecureZeroMemory(&wp, sizeof(wp));
wp.length = sizeof(wp);
if (GetWindowPlacement(hWnd, &wp) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kGetWindowPlacement);
break;
}
wp.rcNormalPosition = {
data.restoreGeometry.left(), data.restoreGeometry.top(),
data.restoreGeometry.right(), data.restoreGeometry.bottom()
};
if (SetWindowPlacement(hWnd, &wp) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kSetWindowPlacement);
}
} break;
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
default:
break;
}

View File

@ -2390,4 +2390,57 @@ void Utils::bringWindowToFront(const WId windowId)
moveWindowToMonitor(hwnd, activeMonitor.value());
}
QPoint Utils::getWindowPlacementOffset(const WId windowId)
{
Q_ASSERT(windowId);
if (!windowId) {
return {};
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
SetLastError(ERROR_SUCCESS);
const auto exStyle = static_cast<DWORD>(GetWindowLongPtrW(hwnd, GWL_EXSTYLE));
if (exStyle == 0) {
WARNING << getSystemErrorMessage(kGetWindowLongPtrW);
return {};
}
// Tool windows are special and they don't need any offset.
if (exStyle & WS_EX_TOOLWINDOW) {
return {};
}
const HMONITOR mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
if (!mon) {
WARNING << getSystemErrorMessage(kMonitorFromWindow);
return {};
}
MONITORINFOEXW mi;
SecureZeroMemory(&mi, sizeof(mi));
mi.cbSize = sizeof(mi);
if (GetMonitorInfoW(mon, &mi) == FALSE) {
WARNING << getSystemErrorMessage(kGetMonitorInfoW);
return {};
}
return {mi.rcWork.left - mi.rcMonitor.left, mi.rcWork.top - mi.rcMonitor.top};
}
QRect Utils::getWindowRestoreFrameGeometry(const WId windowId)
{
Q_ASSERT(windowId);
if (!windowId) {
return {};
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
WINDOWPLACEMENT wp;
SecureZeroMemory(&wp, sizeof(wp));
wp.length = sizeof(wp);
if (GetWindowPlacement(hwnd, &wp) == FALSE) {
WARNING << getSystemErrorMessage(kGetWindowPlacement);
return {};
}
const RECT rawRect = wp.rcNormalPosition;
const QPoint topLeft = {rawRect.left, rawRect.top};
const QSize size = {rawRect.right - rawRect.left, rawRect.bottom - rawRect.top};
const QPoint offset = getWindowPlacementOffset(windowId);
return QRect{topLeft, size}.translated(offset);
}
FRAMELESSHELPER_END_NAMESPACE