Skip to content
This repository has been archived by the owner on Dec 19, 2023. It is now read-only.

Commit

Permalink
win32: fix restore geometry bug
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
wangwenx190 committed Apr 22, 2023
1 parent 8930ea1 commit a203e2c
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 6 deletions.
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion cmake
Submodule cmake updated 1 files
+17 −3 utils.cmake
2 changes: 2 additions & 0 deletions include/FramelessHelper/Core/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
52 changes: 50 additions & 2 deletions src/core/framelesshelper_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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, "
Expand All @@ -98,6 +100,7 @@ struct Win32HelperData
bool trackingMouse = false;
WId fallbackTitleBarWindowId = 0;
Dpi dpi = {};
QRect restoreGeometry = {};
};

struct Win32Helper
Expand Down Expand Up @@ -1184,17 +1187,62 @@ 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;
case WM_DWMCOMPOSITIONCHANGED: {
// 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;
}
Expand Down
53 changes: 53 additions & 0 deletions src/core/utils_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit a203e2c

Please sign in to comment.