From 099da347e85068e2f4c4d4cf16095b6e7177a0e0 Mon Sep 17 00:00:00 2001 From: Zhao Yuhang <2546789017@qq.com> Date: Thu, 14 Sep 2023 22:29:40 +0800 Subject: [PATCH] wip --- .../Core/framelesshelper_windows.h | 76 ++++ .../Core/framelesshelpercore_global.h | 2 +- .../private/framelesshelpercore_global_p.h | 21 +- .../Core/private/framelessmanager_p.h | 1 + src/core/framelesshelper_win.cpp | 147 ++++--- src/core/framelesshelpercore_global.cpp | 17 + src/core/framelessmanager.cpp | 67 ++-- src/core/platformsupport_win.cpp | 86 ++-- src/core/utils_win.cpp | 366 +++++++++--------- 9 files changed, 446 insertions(+), 337 deletions(-) diff --git a/include/FramelessHelper/Core/framelesshelper_windows.h b/include/FramelessHelper/Core/framelesshelper_windows.h index 3fcee29..71b4fb0 100644 --- a/include/FramelessHelper/Core/framelesshelper_windows.h +++ b/include/FramelessHelper/Core/framelesshelper_windows.h @@ -86,6 +86,46 @@ #include +#ifndef SC_SIZE +# define SC_SIZE (0xF000) +#endif + +#ifndef SC_SIZELEFT +# define SC_SIZELEFT (0xF001) +#endif + +#ifndef SC_SIZERIGHT +# define SC_SIZERIGHT (0xF002) +#endif + +#ifndef SC_SIZETOP +# define SC_SIZETOP (0xF003) +#endif + +#ifndef SC_SIZETOPLEFT +# define SC_SIZETOPLEFT (0xF004) +#endif + +#ifndef SC_SIZETOPRIGHT +# define SC_SIZETOPRIGHT (0xF005) +#endif + +#ifndef SC_SIZEBOTTOM +# define SC_SIZEBOTTOM (0xF006) +#endif + +#ifndef SC_SIZEBOTTOMLEFT +# define SC_SIZEBOTTOMLEFT (0xF007) +#endif + +#ifndef SC_SIZEBOTTOMRIGHT +# define SC_SIZEBOTTOMRIGHT (0xF008) +#endif + +#ifndef SC_DRAGMOVE +# define SC_DRAGMOVE (0xF012) +#endif + #ifndef WM_SIZEWAIT # define WM_SIZEWAIT (0x0004) #endif @@ -1166,3 +1206,39 @@ EXTERN_C_END { return !operator==(lhs, rhs); } + +[[nodiscard]] inline constexpr QPoint point2qpoint(const POINT &point) +{ + return QPoint{ int(point.x), int(point.y) }; +} + +[[nodiscard]] inline constexpr POINT qpoint2point(const QPoint &point) +{ + return POINT{ LONG(point.x()), LONG(point.y()) }; +} + +[[nodiscard]] inline constexpr QSize size2qsize(const SIZE &size) +{ + return QSize{ int(size.cx), int(size.cy) }; +} + +[[nodiscard]] inline constexpr SIZE qsize2size(const QSize &size) +{ + return SIZE{ LONG(size.width()), LONG(size.height()) }; +} + +[[nodiscard]] inline constexpr QRect rect2qrect(const RECT &rect) +{ + return QRect{ QPoint{ int(rect.left), int(rect.top) }, QSize{ int(RECT_WIDTH(rect)), int(RECT_HEIGHT(rect)) } }; +} + +[[nodiscard]] inline constexpr RECT qrect2rect(const QRect &qrect) +{ + return RECT{ LONG(qrect.left()), LONG(qrect.top()), LONG(qrect.right()), LONG(qrect.bottom()) }; +} + +[[nodiscard]] inline /*constexpr*/ QString hwnd2str(const HWND hwnd) +{ + // NULL handle is allowed here. + return FRAMELESSHELPER_STRING_LITERAL("0x") + QString::number(reinterpret_cast(hwnd), 16).toUpper().rightJustified(8, u'0'); +} diff --git a/include/FramelessHelper/Core/framelesshelpercore_global.h b/include/FramelessHelper/Core/framelesshelpercore_global.h index 3bd009c..181a367 100644 --- a/include/FramelessHelper/Core/framelesshelpercore_global.h +++ b/include/FramelessHelper/Core/framelesshelpercore_global.h @@ -312,7 +312,7 @@ Q_NAMESPACE_EXPORT(FRAMELESSHELPER_CORE_API) enum class Option : quint8 { - UseCrossPlatformQtImplementation, + //UseCrossPlatformQtImplementation, ForceHideWindowFrameBorder, ForceShowWindowFrameBorder, DisableWindowsSnapLayout, diff --git a/include/FramelessHelper/Core/private/framelesshelpercore_global_p.h b/include/FramelessHelper/Core/private/framelesshelpercore_global_p.h index 2b1c656..330392e 100644 --- a/include/FramelessHelper/Core/private/framelesshelpercore_global_p.h +++ b/include/FramelessHelper/Core/private/framelesshelpercore_global_p.h @@ -96,26 +96,33 @@ struct FramelessCallbacks ForceChildrenRepaintCallback forceChildrenRepaint = nullptr; ResetQtGrabbedControlCallback resetQtGrabbedControl = nullptr; + using PtrType = std::shared_ptr; + [[nodiscard]] static PtrType create(); + private: Q_DISABLE_COPY_MOVE(FramelessCallbacks) }; -using FramelessCallbacksPtr = std::shared_ptr; -#define CreateFramelessCallbacks(...) std::make_shared(__VA_ARGS__) - -struct FramelessData; -using FramelessDataPtr = std::shared_ptr; -#define CreateFramelessData(...) std::make_shared(__VA_ARGS__) +using FramelessCallbacksPtr = FramelessCallbacks::PtrType; struct FramelessData { bool frameless = false; FramelessCallbacksPtr callbacks = nullptr; + struct { + void *ptr = nullptr; + using DeleterFunctionPrototype = void(*)(void*); + DeleterFunctionPrototype deleter = nullptr; + } extraData = {}; - [[nodiscard]] static FramelessDataPtr create(); + using PtrType = std::shared_ptr; + [[nodiscard]] static PtrType create(); + + ~FramelessData(); private: Q_DISABLE_COPY_MOVE(FramelessData) }; +using FramelessDataPtr = FramelessData::PtrType; using FramelessDataHash = QHash; diff --git a/include/FramelessHelper/Core/private/framelessmanager_p.h b/include/FramelessHelper/Core/private/framelessmanager_p.h index 7b4a762..adb1741 100644 --- a/include/FramelessHelper/Core/private/framelessmanager_p.h +++ b/include/FramelessHelper/Core/private/framelessmanager_p.h @@ -62,6 +62,7 @@ public: void doNotifyWallpaperHasChangedOrNot(); Q_NODISCARD static FramelessDataPtr getData(const QWindow *window); + static void removeData(const QWindow *window); FramelessManager *q_ptr = nullptr; Global::SystemTheme systemTheme = Global::SystemTheme::Unknown; diff --git a/src/core/framelesshelper_win.cpp b/src/core/framelesshelper_win.cpp index 9b9552a..2d3d043 100644 --- a/src/core/framelesshelper_win.cpp +++ b/src/core/framelesshelper_win.cpp @@ -114,28 +114,16 @@ struct FramelessDataWin : public FramelessData QRect restoreGeometry = {}; #endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) }; -#define CreateFramelessDataWin(...) std::make_shared(__VA_ARGS__) #define GetFramelessDataWin(Window) std::dynamic_pointer_cast(FramelessManagerPrivate::getData(Window)) [[nodiscard]] FramelessDataPtr FramelessData::create() { - return CreateFramelessDataWin(); + return std::make_shared(); } static std::unique_ptr g_framelessHelperWin = nullptr; -[[nodiscard]] extern QPoint point2qpoint(const POINT &point); -[[nodiscard]] extern POINT qpoint2point(const QPoint &point); - -[[nodiscard]] extern QSize size2qsize(const SIZE &size); -[[nodiscard]] extern SIZE qsize2size(const QSize &size); - -[[nodiscard]] extern QRect rect2qrect(const RECT &rect); -[[nodiscard]] extern RECT qrect2rect(const QRect &qrect); - -[[nodiscard]] extern QString hwnd2str(const HWND hwnd); - [[nodiscard]] extern std::optional getMonitorForWindow(const HWND hwnd); [[nodiscard]] static inline QByteArray qtNativeEventType() @@ -218,11 +206,7 @@ void FramelessHelperWin::addWindow(const QWindow *window) } data->frameless = true; data->dpi = Dpi{ Utils::getWindowDpi(window, true), Utils::getWindowDpi(window, false) }; - if (!g_framelessHelperWin) { - g_framelessHelperWin = std::make_unique(); - qApp->installNativeEventFilter(g_framelessHelperWin.get()); - } - DEBUG.noquote() << "The DPI of window" << hwnd2str(windowId) << "is" << data->dpi; + DEBUG.noquote() << "The DPI of window" << hwnd2str(qWindowId(window)) << "is" << data->dpi; // Remove the bad window styles added by Qt (it's not that "bad" though). std::ignore = Utils::maybeFixupQtInternals(window); #if 0 @@ -267,19 +251,15 @@ void FramelessHelperWin::addWindow(const QWindow *window) } } } + if (!g_framelessHelperWin) { + g_framelessHelperWin = std::make_unique(); + qApp->installNativeEventFilter(g_framelessHelperWin.get()); + } } void FramelessHelperWin::removeWindow(const QWindow *window) { - Q_ASSERT(window); - if (!window) { - return; - } - const auto data = GetFramelessDataWin(window); - if (!data || !data->frameless) { - return; - } - data->frameless = false; + Q_UNUSED(window); } bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result) @@ -301,16 +281,23 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // Anyway, we should skip the entire processing in this case. return false; } + const QWindow *window = Utils::findWindow(reinterpret_cast(hWnd)); + if (!window) { + return false; + } + + // Let's be extra safe. + if (!Utils::isValidWindow(window, false, true)) { + return false; + } + const auto data = GetFramelessDataWin(window); Q_ASSERT(data); if (!data || !data->frameless) { return false; } - // Let's be extra safe. - if (!Utils::isValidWindow(window, false, true)) { - return false; - } + const UINT uMsg = msg->message; // We should skip these messages otherwise we will get crashes. @@ -332,7 +319,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me const LPARAM lParam = msg->lParam; #if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) - const auto updateRestoreGeometry = [window](const bool ignoreWindowState) -> void { + const auto updateRestoreGeometry = [window, &data](const bool ignoreWindowState) -> void { if (!ignoreWindowState && !Utils::isWindowNoState(window)) { return; } @@ -341,10 +328,10 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me WARNING << "The calculated restore geometry is invalid."; return; } - if (Utils::isValidGeometry(data.restoreGeometry) && (data.restoreGeometry == rect)) { + if (Utils::isValidGeometry(data->restoreGeometry) && (data->restoreGeometry == rect)) { return; } - muData.restoreGeometry = rect; + data->restoreGeometry = rect; }; #endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) @@ -447,13 +434,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // So we filter out these superfluous mouse leave events here to avoid this issue. const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint{ msg->pt.x, msg->pt.y }); SystemButtonType dummy = SystemButtonType::Unknown; - if (data.params.isInsideSystemButtons(qtScenePos, &dummy)) { - muData.mouseLeaveBlocked = true; + if (data->callbacks->isInsideSystemButtons(qtScenePos, &dummy)) { + data->mouseLeaveBlocked = true; *result = FALSE; return true; } } - muData.mouseLeaveBlocked = false; + data->mouseLeaveBlocked = false; } switch (uMsg) { @@ -465,7 +452,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // If we are using the PMv2 DPI awareness mode, the non-client area // of the window will be scaled by the OS automatically, so there will // be no need to do this in that case. - Utils::enableNonClientAreaDpiScalingForWindow(windowId); + Utils::enableNonClientAreaDpiScalingForWindow(window); } break; #endif case WM_NCCALCSIZE: { @@ -581,7 +568,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me clientRect->top = originalTop; } const bool max = IsMaximized(hWnd); - const bool full = Utils::isFullScreen(windowId); + const bool full = Utils::isFullScreen(window); // We don't need this correction when we're fullscreen. We will // have the WS_POPUP size, so we don't have to worry about // borders, and the default frame will be fine. @@ -592,11 +579,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // then the window is clipped to the monitor so that the resize handle // do not appear because you don't need them (because you can't resize // a window when it's maximized unless you restore it). - const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true); + const int frameSizeY = Utils::getResizeBorderThickness(window, false, true); clientRect->top += frameSizeY; if (!frameBorderVisible) { clientRect->bottom -= frameSizeY; - const int frameSizeX = Utils::getResizeBorderThickness(windowId, true, true); + const int frameSizeX = Utils::getResizeBorderThickness(window, true, true); clientRect->left += frameSizeX; clientRect->right -= frameSizeX; } @@ -791,8 +778,8 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // color, our homemade top border can almost have exactly the same // appearance with the system's one. - const auto hitTestRecorder = qScopeGuard([&muData, &result](){ - muData.lastHitTestResult = getHittedWindowPart(*result); + const auto hitTestRecorder = qScopeGuard([&data, &result](){ + data->lastHitTestResult = getHittedWindowPart(*result); }); const auto nativeGlobalPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; @@ -812,7 +799,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint(nativeLocalPos.x, nativeLocalPos.y)); SystemButtonType sysButtonType = SystemButtonType::Unknown; - if (data.params.isInsideSystemButtons(qtScenePos, &sysButtonType)) { + if (data->callbacks->isInsideSystemButtons(qtScenePos, &sysButtonType)) { // Even if the mouse is inside the chrome button area now, we should still allow the user // to be able to resize the window with the top or right window border, this is also the // normal behavior of a native Win32 window. @@ -858,13 +845,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // are we hitting. const bool max = IsMaximized(hWnd); - const bool full = Utils::isFullScreen(windowId); - const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true); + const bool full = Utils::isFullScreen(window); + const int frameSizeY = Utils::getResizeBorderThickness(window, false, true); const bool isTop = (nativeLocalPos.y < frameSizeY); - const bool isTitleBar = data.params.isInsideTitleBarDraggableArea(qtScenePos); - const bool isFixedSize = data.params.isWindowFixedSize(); - const bool dontOverrideCursor = data.params.getProperty(kDontOverrideCursorVar, false).toBool(); - const bool dontToggleMaximize = data.params.getProperty(kDontToggleMaximizeVar, false).toBool(); + const bool isTitleBar = data->callbacks->isInsideTitleBarDraggableArea(qtScenePos); + const bool isFixedSize = data->callbacks->isWindowFixedSize(); + const bool dontOverrideCursor = data->callbacks->getProperty(kDontOverrideCursorVar, false).toBool(); + const bool dontToggleMaximize = data->callbacks->getProperty(kDontToggleMaximizeVar, false).toBool(); if (dontToggleMaximize) { static bool once = false; @@ -922,7 +909,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me const bool isBottom = (nativeLocalPos.y >= (clientHeight - frameSizeY)); // Make the border a little wider to let the user easy to resize on corners. const auto scaleFactor = ((isTop || isBottom) ? qreal(2) : qreal(1)); - const int frameSizeX = Utils::getResizeBorderThickness(windowId, true, true); + const int frameSizeX = Utils::getResizeBorderThickness(window, true, true); const int scaledFrameSizeX = std::round(qreal(frameSizeX) * scaleFactor); const bool isLeft = (nativeLocalPos.x < scaledFrameSizeX); const bool isRight = (nativeLocalPos.x >= (clientWidth - scaledFrameSizeX)); @@ -975,8 +962,8 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me return true; } case WM_MOUSEMOVE: - if ((data.lastHitTestResult != WindowPart::ChromeButton) && data.mouseLeaveBlocked) { - muData.mouseLeaveBlocked = false; + if ((data->lastHitTestResult != WindowPart::ChromeButton) && data->mouseLeaveBlocked) { + data->mouseLeaveBlocked = false; std::ignore = requestForMouseLeaveMessage(hWnd, false); } break; @@ -999,11 +986,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me case WM_NCPOINTERUP: #endif case WM_NCMOUSEHOVER: { - const WindowPart currentWindowPart = data.lastHitTestResult; + const WindowPart currentWindowPart = data->lastHitTestResult; if (uMsg == WM_NCMOUSEMOVE) { if (currentWindowPart != WindowPart::ChromeButton) { - std::ignore = data.params.resetQtGrabbedControl(); - if (muData.mouseLeaveBlocked) { + std::ignore = data->callbacks->resetQtGrabbedControl(); + if (data->mouseLeaveBlocked) { emulateClientAreaMessage(WM_NCMOUSELEAVE); } } @@ -1014,12 +1001,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // If the mouse is entering the client area, there must be a WM_NCHITTEST setting // it to `Client` before the WM_NCMOUSELEAVE comes; // If the mouse is leaving the window, current window part remains as `Outside`. - muData.lastHitTestResult = WindowPart::Outside; + data->lastHitTestResult = WindowPart::Outside; } if (currentWindowPart == WindowPart::ChromeButton) { emulateClientAreaMessage(); if (uMsg == WM_NCMOUSEMOVE) { + // ### FIXME: Calling DefWindowProc() here is really dangerous, investigate how + // to avoid doing this. *result = ::DefWindowProcW(hWnd, WM_NCMOUSEMOVE, wParam, lParam); } else { *result = (((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK)) ? TRUE : FALSE); @@ -1028,18 +1017,18 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me } } break; case WM_NCMOUSELEAVE: { - const WindowPart currentWindowPart = data.lastHitTestResult; + const WindowPart currentWindowPart = data->lastHitTestResult; if (currentWindowPart == WindowPart::ChromeButton) { // If we press on the chrome button and move mouse, Windows will take the pressing area // as HTCLIENT which maybe because of our former retransmission of WM_NCLBUTTONDOWN, as // a result, a WM_NCMOUSELEAVE will come immediately and a lot of WM_MOUSEMOVE will come // if we move the mouse, we should track the mouse in advance. - if (muData.mouseLeaveBlocked) { - muData.mouseLeaveBlocked = false; + if (data->mouseLeaveBlocked) { + data->mouseLeaveBlocked = false; std::ignore = requestForMouseLeaveMessage(hWnd, false); } } else { - if (data.mouseLeaveBlocked) { + if (data->mouseLeaveBlocked) { // The mouse is moving from the chrome button to other non-client area, we should // emulate a WM_MOUSELEAVE message to reset the button state. emulateClientAreaMessage(WM_NCMOUSELEAVE); @@ -1051,7 +1040,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // the mouse leaves window from client area and enters window from non-client area, // but it has no bad effect. - std::ignore = data.params.resetQtGrabbedControl(); + std::ignore = data->callbacks->resetQtGrabbedControl(); } } } break; @@ -1065,7 +1054,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // of the application a lot. const auto windowPos = reinterpret_cast(lParam); const QRect suggestedFrameGeometry{ windowPos->x, windowPos->y, windowPos->cx, windowPos->cy }; - const QMargins frameMargins = (Utils::getWindowSystemFrameMargins(windowId) + Utils::getWindowCustomFrameMargins(window)); + const QMargins frameMargins = (Utils::getWindowSystemFrameMargins(window) + Utils::getWindowCustomFrameMargins(window)); const QRect suggestedGeometry = (suggestedFrameGeometry - frameMargins); if (Utils::toNativePixels(window, window->size()) != suggestedGeometry.size()) { windowPos->flags |= SWP_NOCOPYBITS; @@ -1107,7 +1096,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me } #endif // (QT_VERSION <= QT_VERSION_CHECK(6, 4, 2)) case WM_DPICHANGED: { - const Dpi oldDpi = data.dpi; + const Dpi oldDpi = data->dpi; const Dpi newDpi = {UINT(LOWORD(wParam)), UINT(HIWORD(wParam))}; if (Q_UNLIKELY(newDpi == oldDpi)) { WARNING << "Wrong WM_DPICHANGED received: same DPI."; @@ -1115,18 +1104,18 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me } DEBUG.noquote() << "New DPI for window" << hwnd2str(hWnd) << "is" << newDpi << "(was" << oldDpi << ")."; - muData.dpi = newDpi; + data->dpi = newDpi; #if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) - if (Utils::isValidGeometry(data.restoreGeometry)) { + if (Utils::isValidGeometry(data->restoreGeometry)) { // Update the window size only. The position should not be changed. - muData.restoreGeometry.setSize(Utils::rescaleSize(data.restoreGeometry.size(), oldDpi.x, newDpi.x)); + muData.restoreGeometry.setSize(Utils::rescaleSize(data->restoreGeometry.size(), oldDpi.x, newDpi.x)); } #endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) - data.params.forceChildrenRepaint(500); + data->callbacks->forceChildrenRepaint(500); } break; case WM_DWMCOMPOSITIONCHANGED: // Re-apply the custom window frame if recovered from the basic theme. - std::ignore = Utils::updateWindowFrameMargins(windowId, false); + std::ignore = Utils::updateWindowFrameMargins(window, false); break; #if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) case WM_ENTERSIZEMOVE: // Sent to a window when the user drags the title bar or the resize border. @@ -1137,7 +1126,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me if (wParam != SIZE_MAXIMIZED) { break; } - if (!Utils::isValidGeometry(data.restoreGeometry)) { + if (!Utils::isValidGeometry(data->restoreGeometry)) { updateRestoreGeometry(true); break; } @@ -1149,11 +1138,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me break; } // The restore geometry is correct, no need to bother. - if (rect2qrect(wp.rcNormalPosition) == data.restoreGeometry) { + if (rect2qrect(wp.rcNormalPosition) == data->restoreGeometry) { break; } // OK, the restore geometry is wrong, let's correct it then :) - wp.rcNormalPosition = qrect2rect(data.restoreGeometry); + wp.rcNormalPosition = qrect2rect(data->restoreGeometry); if (::SetWindowPlacement(hWnd, &wp) == FALSE) { WARNING << Utils::getSystemErrorMessage(kSetWindowPlacement); } @@ -1165,7 +1154,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // down the monitor (only a suggestion to the OS, the OS can still ignore // our request). if ((filteredWParam == SC_SCREENSAVE) || (filteredWParam == SC_MONITORPOWER)) { - if (Utils::isFullScreen(windowId)) { + if (Utils::isFullScreen(window)) { *result = FALSE; return true; } @@ -1233,14 +1222,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me WARNING << Utils::getSystemErrorMessage(kSetWindowLongPtrW); break; } - std::ignore = Utils::triggerFrameChange(windowId); + std::ignore = Utils::triggerFrameChange(window); const LRESULT originalResult = ::DefWindowProcW(hWnd, uMsg, wParam, lParam); ::SetLastError(ERROR_SUCCESS); if (::SetWindowLongPtrW(hWnd, GWL_STYLE, static_cast(oldStyle)) == 0) { WARNING << Utils::getSystemErrorMessage(kSetWindowLongPtrW); break; } - std::ignore = Utils::triggerFrameChange(windowId); + std::ignore = Utils::triggerFrameChange(window); *result = originalResult; return true; } @@ -1251,7 +1240,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me if ((uMsg == WM_DWMCOMPOSITIONCHANGED) || (uMsg == WM_DWMCOLORIZATIONCOLORCHANGED)) { if (Utils::isWindowAccelerated(window) && Utils::isWindowTransparent(window)) { - std::ignore = Utils::updateFramebufferTransparency(windowId); + std::ignore = Utils::updateFramebufferTransparency(window); } } @@ -1266,14 +1255,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me if (WindowsVersionHelper::isWin10RS5OrGreater()) { const bool dark = (FramelessManager::instance()->systemTheme() == SystemTheme::Dark); const auto isWidget = [&data]() -> bool { - const auto widget = data.params.getWidgetHandle(); + const auto widget = data->callbacks->getWidgetHandle(); return (widget && widget->isWidgetType()); }(); if (!isWidget) { // Causes some QtWidgets paint incorrectly, so only apply to Qt Quick applications. - std::ignore = Utils::updateGlobalWin32ControlsTheme(windowId, dark); + std::ignore = Utils::updateGlobalWin32ControlsTheme(window, dark); } - std::ignore = Utils::refreshWin32ThemeResources(windowId, dark); + std::ignore = Utils::refreshWin32ThemeResources(window, dark); } } } diff --git a/src/core/framelesshelpercore_global.cpp b/src/core/framelesshelpercore_global.cpp index 5aa52c2..82a2134 100644 --- a/src/core/framelesshelpercore_global.cpp +++ b/src/core/framelesshelpercore_global.cpp @@ -114,6 +114,23 @@ using namespace Global; static_assert(std::size(WindowsVersions) == (static_cast(WindowsVersion::Latest) + 1)); #endif +FramelessCallbacksPtr FramelessCallbacks::create() +{ + return std::make_shared(); +} + +FramelessData::~FramelessData() +{ + if (extraData.ptr) { + Q_ASSERT(extraData.deleter); + if (extraData.deleter) { + extraData.deleter(extraData.ptr); + extraData.deleter = nullptr; + } + extraData.ptr = nullptr; + } +} + void FramelessHelperCoreInitialize() { static bool inited = false; diff --git a/src/core/framelessmanager.cpp b/src/core/framelessmanager.cpp index 3114da9..21cb902 100644 --- a/src/core/framelessmanager.cpp +++ b/src/core/framelessmanager.cpp @@ -81,18 +81,6 @@ static constexpr const int kEventDelayInterval = 1000; } #endif -[[nodiscard]] static inline bool usePureQtImplementation() -{ - static const auto result = []() -> bool { -#ifdef Q_OS_WINDOWS - return FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation); -#else - return true; -#endif - }(); - return result; -} - FramelessManagerPrivate::FramelessManagerPrivate(FramelessManager *q) : QObject(q) { Q_ASSERT(q); @@ -240,6 +228,19 @@ FramelessDataPtr FramelessManagerPrivate::getData(const QWindow *window) return it.value(); } +void FramelessManagerPrivate::removeData(const QWindow *window) +{ + Q_ASSERT(window); + if (!window) { + return; + } + const auto it = g_internalData()->constFind(window); + if (it == g_internalData()->constEnd()) { + return; + } + g_internalData()->erase(it); +} + bool FramelessManagerPrivate::isThemeOverrided() const { return (overrideTheme.value_or(SystemTheme::Unknown) != SystemTheme::Unknown); @@ -316,7 +317,7 @@ bool FramelessManager::isFramelessWindow(const QWindow *window) const if (!window) { return false; } - return FramelessManagerPrivate::getData(window)->isFrameless; + return FramelessManagerPrivate::getData(window)->frameless; } SystemTheme FramelessManager::systemTheme() const @@ -369,19 +370,20 @@ bool FramelessManager::addWindow(const QWindow *window) return false; } const FramelessDataPtr data = FramelessManagerPrivate::getData(window); - if (data->isFrameless) { + Q_ASSERT(data); + if (!data || data->frameless) { return false; } - data->isFrameless = true; - const bool pureQt = usePureQtImplementation(); - if (pureQt) { - FramelessHelperQt::addWindow(window); - } -#ifdef Q_OS_WINDOWS - if (!pureQt) { - FramelessHelperWin::addWindow(window); - } +#if FRAMELESSHELPER_CONFIG(native_impl) +# ifdef Q_OS_WINDOWS std::ignore = Utils::installWindowProcHook(window); + FramelessHelperWin::addWindow(window); +# elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) +# elif defined(Q_OS_MACOS) +# else +# endif +#else + FramelessHelperQt::addWindow(window); #endif connect(window, &QWindow::destroyed, FramelessManager::instance(), [this, window](){ std::ignore = removeWindow(window); }); return true; @@ -394,19 +396,20 @@ bool FramelessManager::removeWindow(const QWindow *window) return false; } const auto it = g_internalData()->constFind(window); - if ((it == g_internalData()->constEnd()) || !it.value()->isFrameless) { + if (it == g_internalData()->constEnd()) { return false; } - const bool pureQt = usePureQtImplementation(); - if (pureQt) { - FramelessHelperQt::removeWindow(window); - } -#ifdef Q_OS_WINDOWS - if (!pureQt) { - FramelessHelperWin::removeWindow(window); - } +#if FRAMELESSHELPER_CONFIG(native_impl) +# ifdef Q_OS_WINDOWS + FramelessHelperWin::removeWindow(window); std::ignore = Utils::uninstallWindowProcHook(window); std::ignore = Utils::removeMicaWindow(window); +# elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) +# elif defined(Q_OS_MACOS) +# else +# endif +#else + FramelessHelperQt::removeWindow(window); #endif g_internalData()->erase(it); return true; diff --git a/src/core/platformsupport_win.cpp b/src/core/platformsupport_win.cpp index 479f822..a710dd1 100644 --- a/src/core/platformsupport_win.cpp +++ b/src/core/platformsupport_win.cpp @@ -50,11 +50,11 @@ _GetWindowCompositionAttribute(const HWND hWnd, PWINDOWCOMPOSITIONATTRIBDATA pvD Q_ASSERT(hWnd); Q_ASSERT(pvData); if (!hWnd || !pvData) { - SetLastError(ERROR_INVALID_PARAMETER); + ::SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (!API_USER_AVAILABLE(GetWindowCompositionAttribute)) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } return API_CALL_FUNCTION4(user32, GetWindowCompositionAttribute, hWnd, pvData); @@ -66,11 +66,11 @@ _SetWindowCompositionAttribute(const HWND hWnd, PWINDOWCOMPOSITIONATTRIBDATA pvD Q_ASSERT(hWnd); Q_ASSERT(pvData); if (!hWnd || !pvData) { - SetLastError(ERROR_INVALID_PARAMETER); + ::SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (!API_USER_AVAILABLE(SetWindowCompositionAttribute)) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } return API_CALL_FUNCTION4(user32, SetWindowCompositionAttribute, hWnd, pvData); @@ -111,14 +111,14 @@ _ShouldAppsUseDarkMode(VOID) { FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } static const auto pShouldAppsUseDarkMode = reinterpret_cast( SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(132))); if (!pShouldAppsUseDarkMode) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } return pShouldAppsUseDarkMode(); @@ -129,19 +129,19 @@ _AllowDarkModeForWindow(const HWND hWnd, const BOOL bAllow) { Q_ASSERT(hWnd); if (!hWnd) { - SetLastError(ERROR_INVALID_PARAMETER); + ::SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } static const auto pAllowDarkModeForWindow = reinterpret_cast( SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(133))); if (!pAllowDarkModeForWindow) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } return pAllowDarkModeForWindow(hWnd, bAllow); @@ -152,14 +152,14 @@ _AllowDarkModeForApp(const BOOL bAllow) { FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } static const auto pAllowDarkModeForApp = reinterpret_cast( SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(135))); if (!pAllowDarkModeForApp) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } return pAllowDarkModeForApp(bAllow); @@ -170,14 +170,14 @@ _FlushMenuThemes(VOID) { FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return; } static const auto pFlushMenuThemes = reinterpret_cast( SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(136))); if (!pFlushMenuThemes) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return; } pFlushMenuThemes(); @@ -188,14 +188,14 @@ _RefreshImmersiveColorPolicyState(VOID) { FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return; } static const auto pRefreshImmersiveColorPolicyState = reinterpret_cast( SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(104))); if (!pRefreshImmersiveColorPolicyState) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return; } pRefreshImmersiveColorPolicyState(); @@ -206,19 +206,19 @@ _IsDarkModeAllowedForWindow(const HWND hWnd) { Q_ASSERT(hWnd); if (!hWnd) { - SetLastError(ERROR_INVALID_PARAMETER); + ::SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } static const auto pIsDarkModeAllowedForWindow = reinterpret_cast( SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(137))); if (!pIsDarkModeAllowedForWindow) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } return pIsDarkModeAllowedForWindow(hWnd); @@ -229,14 +229,14 @@ _GetIsImmersiveColorUsingHighContrast(const IMMERSIVE_HC_CACHE_MODE mode) { FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } static const auto pGetIsImmersiveColorUsingHighContrast = reinterpret_cast( SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(106))); if (!pGetIsImmersiveColorUsingHighContrast) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } return pGetIsImmersiveColorUsingHighContrast(mode); @@ -248,19 +248,19 @@ _OpenNcThemeData(const HWND hWnd, LPCWSTR pszClassList) Q_ASSERT(hWnd); Q_ASSERT(pszClassList); if (!hWnd || !pszClassList) { - SetLastError(ERROR_INVALID_PARAMETER); + ::SetLastError(ERROR_INVALID_PARAMETER); return nullptr; } FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return nullptr; } static const auto pOpenNcThemeData = reinterpret_cast( SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(49))); if (!pOpenNcThemeData) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return nullptr; } return pOpenNcThemeData(hWnd, pszClassList); @@ -271,14 +271,14 @@ _ShouldSystemUseDarkMode(VOID) { FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } static const auto pShouldSystemUseDarkMode = reinterpret_cast( SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(138))); if (!pShouldSystemUseDarkMode) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } return pShouldSystemUseDarkMode(); @@ -289,14 +289,14 @@ _SetPreferredAppMode(const PREFERRED_APP_MODE mode) { FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return PAM_MAX; } static const auto pSetPreferredAppMode = reinterpret_cast( SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(135))); if (!pSetPreferredAppMode) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return PAM_MAX; } return pSetPreferredAppMode(mode); @@ -307,14 +307,14 @@ _IsDarkModeAllowedForApp(VOID) { FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } static const auto pIsDarkModeAllowedForApp = reinterpret_cast( SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(139))); if (!pIsDarkModeAllowedForApp) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } return pIsDarkModeAllowedForApp(); @@ -325,12 +325,12 @@ _EnableChildWindowDpiMessage2(const HWND hWnd, const BOOL fEnable) { Q_ASSERT(hWnd); if (!hWnd) { - SetLastError(ERROR_INVALID_PARAMETER); + ::SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } using EnableChildWindowDpiMessagePtr = decltype(&::_EnableChildWindowDpiMessage); @@ -355,7 +355,7 @@ _EnableChildWindowDpiMessage2(const HWND hWnd, const BOOL fEnable) return nullptr; }(); if (!pEnableChildWindowDpiMessage) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } return pEnableChildWindowDpiMessage(hWnd, fEnable); @@ -366,7 +366,7 @@ _EnablePerMonitorDialogScaling2(VOID) { FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } using EnablePerMonitorDialogScalingPtr = decltype(&::_EnablePerMonitorDialogScaling); @@ -385,7 +385,7 @@ _EnablePerMonitorDialogScaling2(VOID) return nullptr; }(); if (!pEnablePerMonitorDialogScaling) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } return pEnablePerMonitorDialogScaling(); @@ -396,12 +396,12 @@ _GetDpiForWindow2(const HWND hWnd) { Q_ASSERT(hWnd); if (!hWnd) { - SetLastError(ERROR_INVALID_PARAMETER); + ::SetLastError(ERROR_INVALID_PARAMETER); return 0; } FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } using GetDpiForWindowPtr = decltype(&::_GetDpiForWindow); @@ -424,7 +424,7 @@ _GetDpiForWindow2(const HWND hWnd) return nullptr; }(); if (!pGetDpiForWindow) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } return pGetDpiForWindow(hWnd); @@ -436,12 +436,12 @@ _GetSystemMetricsForDpi2(const int nIndex, const UINT dpi) Q_ASSERT(nIndex >= 0); Q_ASSERT(dpi != 0); if ((nIndex < 0) || (dpi == 0)) { - SetLastError(ERROR_INVALID_PARAMETER); + ::SetLastError(ERROR_INVALID_PARAMETER); return 0; } FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } using GetSystemMetricsForDpiPtr = decltype(&::_GetSystemMetricsForDpi); @@ -460,7 +460,7 @@ _GetSystemMetricsForDpi2(const int nIndex, const UINT dpi) return nullptr; }(); if (!pGetSystemMetricsForDpi) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } return pGetSystemMetricsForDpi(nIndex, dpi); @@ -473,12 +473,12 @@ _AdjustWindowRectExForDpi2(LPRECT lpRect, const DWORD dwStyle, Q_ASSERT(lpRect); Q_ASSERT(dpi != 0); if (!lpRect || (dpi == 0)) { - SetLastError(ERROR_INVALID_PARAMETER); + ::SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } FRAMELESSHELPER_USE_NAMESPACE if (!WindowsVersionHelper::isWin10OrGreater()) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } using AdjustWindowRectExForDpiPtr = decltype(&::_AdjustWindowRectExForDpi); @@ -496,7 +496,7 @@ _AdjustWindowRectExForDpi2(LPRECT lpRect, const DWORD dwStyle, return nullptr; }(); if (!pAdjustWindowRectExForDpi) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } return pAdjustWindowRectExForDpi(lpRect, dwStyle, bMenu, dwExStyle, dpi); diff --git a/src/core/utils_win.cpp b/src/core/utils_win.cpp index 68ccc75..53fe40c 100644 --- a/src/core/utils_win.cpp +++ b/src/core/utils_win.cpp @@ -28,6 +28,7 @@ #include "framelesshelper_windows.h" #include "framelessmanager.h" +#include "framelessmanager_p.h" #include "framelessconfig_p.h" #include "sysapiloader_p.h" #include "registrykey_p.h" @@ -193,12 +194,20 @@ FRAMELESSHELPER_STRING_CONSTANT(ScreenToClient) FRAMELESSHELPER_STRING_CONSTANT(DwmFlush) FRAMELESSHELPER_STRING_CONSTANT(GetCursorPos) -struct Win32UtilsInternal +struct FramelessDataExtra { WNDPROC qtWindowProc = nullptr; + bool windowProcHooked = false; + bool mica = false; }; -Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData) +static inline void FramelessDataExtraDeleter(void *data) +{ + Q_ASSERT(data); + if (data) { + delete static_cast(data); + } +} struct Win32Message { @@ -576,42 +585,6 @@ static constexpr const std::array g_win32MessageMap = }; #undef DEFINE_WIN32_MESSAGE -[[nodiscard]] QPoint point2qpoint(const POINT &point) -{ - return QPoint{ int(point.x), int(point.y) }; -} - -[[nodiscard]] POINT qpoint2point(const QPoint &point) -{ - return POINT{ LONG(point.x()), LONG(point.y()) }; -} - -[[nodiscard]] QSize size2qsize(const SIZE &size) -{ - return QSize{ int(size.cx), int(size.cy) }; -} - -[[nodiscard]] SIZE qsize2size(const QSize &size) -{ - return SIZE{ LONG(size.width()), LONG(size.height()) }; -} - -[[nodiscard]] QRect rect2qrect(const RECT &rect) -{ - return QRect{ QPoint{ int(rect.left), int(rect.top) }, QSize{ int(RECT_WIDTH(rect)), int(RECT_HEIGHT(rect)) } }; -} - -[[nodiscard]] RECT qrect2rect(const QRect &qrect) -{ - return RECT{ LONG(qrect.left()), LONG(qrect.top()), LONG(qrect.right()), LONG(qrect.bottom()) }; -} - -[[nodiscard]] QString hwnd2str(const HWND hwnd) -{ - // NULL handle is allowed here. - return FRAMELESSHELPER_STRING_LITERAL("0x") + QString::number(reinterpret_cast(hwnd), 16).toUpper().rightJustified(8, u'0'); -} - [[nodiscard]] std::optional getMonitorForWindow(const HWND hwnd) { Q_ASSERT(hwnd); @@ -814,29 +787,29 @@ static constexpr const std::array g_win32MessageMap = return std::round(qreal(::GetSystemMetrics(index)) / dpr); } -[[maybe_unused]] [[nodiscard]] static inline +[[maybe_unused]] [[nodiscard]] static inline constexpr DWORD qtEdgesToWin32Orientation(const Qt::Edges edges) { if (edges == Qt::Edges{}) { return 0; } else if (edges == (Qt::LeftEdge)) { - return 0xF001; // SC_SIZELEFT + return SC_SIZELEFT; } else if (edges == (Qt::RightEdge)) { - return 0xF002; // SC_SIZERIGHT + return SC_SIZERIGHT; } else if (edges == (Qt::TopEdge)) { - return 0xF003; // SC_SIZETOP + return SC_SIZETOP; } else if (edges == (Qt::TopEdge | Qt::LeftEdge)) { - return 0xF004; // SC_SIZETOPLEFT + return SC_SIZETOPLEFT; } else if (edges == (Qt::TopEdge | Qt::RightEdge)) { - return 0xF005; // SC_SIZETOPRIGHT + return SC_SIZETOPRIGHT; } else if (edges == (Qt::BottomEdge)) { - return 0xF006; // SC_SIZEBOTTOM + return SC_SIZEBOTTOM; } else if (edges == (Qt::BottomEdge | Qt::LeftEdge)) { - return 0xF007; // SC_SIZEBOTTOMLEFT + return SC_SIZEBOTTOMLEFT; } else if (edges == (Qt::BottomEdge | Qt::RightEdge)) { - return 0xF008; // SC_SIZEBOTTOMRIGHT + return SC_SIZEBOTTOMRIGHT; } else { - return 0xF000; // SC_SIZE + return SC_SIZE; } } @@ -854,7 +827,7 @@ static constexpr const std::array g_win32MessageMap = return result; } -[[nodiscard]] static inline bool isNonClientMessage(const UINT message) +[[nodiscard]] static inline constexpr bool isNonClientMessage(const UINT message) { if (((message >= WM_NCCREATE) && (message <= WM_NCACTIVATE)) || ((message >= WM_NCMOUSEMOVE) && (message <= WM_NCMBUTTONDBLCLK)) @@ -867,7 +840,7 @@ static constexpr const std::array g_win32MessageMap = } } -[[nodiscard]] static inline bool isMouseMessage(const UINT message, bool *isNonClient = nullptr) +[[nodiscard]] static inline constexpr bool isMouseMessage(const UINT message, bool *isNonClient = nullptr) { if (((message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST)) || ((message == WM_MOUSEHOVER) || (message == WM_MOUSELEAVE))) { @@ -887,18 +860,12 @@ static constexpr const std::array g_win32MessageMap = } } -[[nodiscard]] static inline bool usePureQtImplementation() -{ - static const bool result = FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation); - return result; -} - [[nodiscard]] static inline LRESULT CALLBACK FramelessHelperHookWindowProc (const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) { Q_ASSERT(hWnd); if (!hWnd) { - return 0; + return FALSE; } #if FRAMELESSHELPER_CONFIG(debug_output) if (isWin32MessageDebuggingEnabled()) { @@ -913,14 +880,20 @@ static constexpr const std::array g_win32MessageMap = } #endif const QWindow *window = Utils::findWindow(reinterpret_cast(hWnd)); + Q_ASSERT(window); if (!window || !FramelessManager::instance()->isFramelessWindow(window)) { return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); } - const FramelessDataPtr data = FramelessHelperExtractData(window); + const FramelessDataPtr data = FramelessManagerPrivate::getData(window); Q_ASSERT(data); if (!data) { return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); } + const auto extraData = static_cast(data->extraData.ptr); + Q_ASSERT(extraData); + if (!extraData) { + return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); + } // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowscontext.cpp#L1025 // We can see from the source code that Qt will filter out some messages first and then send the unfiltered // messages to the event dispatcher. To activate the Snap Layout feature on Windows 11, we must process @@ -939,7 +912,7 @@ static constexpr const std::array g_win32MessageMap = // (and correct client area size, especially when the window is maximized/fullscreen). So we still go through // the normal code path of the original qWindowsWndProc() function, but only for this specific message. It should // be OK because Qt won't prevent us from handling WM_NCCALCSIZE. - if (!usePureQtImplementation() && (uMsg != WM_NCCALCSIZE)) { + if ((uMsg != WM_NCCALCSIZE)) { MSG message; SecureZeroMemory(&message, sizeof(message)); message.hwnd = hWnd; @@ -1008,7 +981,7 @@ static constexpr const std::array g_win32MessageMap = case WM_RBUTTONUP: { const QPoint nativeLocalPos = getNativePosFromMouse(); const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, nativeLocalPos); - if (data->callbacks.isInsideTitleBarDraggableArea(qtScenePos)) { + if (data->callbacks->isInsideTitleBarDraggableArea(qtScenePos)) { POINT pos = {nativeLocalPos.x(), nativeLocalPos.y()}; if (::ClientToScreen(hWnd, &pos) == FALSE) { WARNING << Utils::getSystemErrorMessage(kClientToScreen); @@ -1051,13 +1024,13 @@ static constexpr const std::array g_win32MessageMap = // behavior is not what we would want to see because it doesn't know our // window doesn't have any window frame now, so return early here to avoid // entering Qt's own handling logic. - return 0; // Return 0 means we have handled this event. + return FALSE; // Return 0 means we have handled this event. } - Q_ASSERT(g_win32UtilsData()->qtWindowProc); - if (g_win32UtilsData()->qtWindowProc) { + Q_ASSERT(extraData->qtWindowProc); + if (extraData->qtWindowProc) { // Hand over to Qt's original window proc function for events we are not // interested in. - return ::CallWindowProcW(g_win32UtilsData()->qtWindowProc, hWnd, uMsg, wParam, lParam); + return ::CallWindowProcW(extraData->qtWindowProc, hWnd, uMsg, wParam, lParam); } else { return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); } @@ -1123,20 +1096,28 @@ bool Utils::updateWindowFrameMargins(const QWindow *window, const bool reset) if (!API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea)) { return false; } - // We can't extend the window frame when DWM composition is disabled. + // We can't extend the window frame when DWM composition is disabled anyway. // No need to try further in this case. if (!isDwmCompositionEnabled()) { return false; } - const FramelessDataPtr data = FramelessHelperExtractData(window); - const bool micaEnabled = (data && data->micaEnabled); - const auto margins = [micaEnabled, reset]() -> MARGINS { + const FramelessDataPtr data = FramelessManagerPrivate::getData(window); + Q_ASSERT(data); + if (!data) { + return false; + } + const auto extraData = static_cast(data->extraData.ptr); + Q_ASSERT(extraData); + if (!extraData) { + return false; + } + const auto margins = [extraData, reset]() -> MARGINS { // To make Mica/Mica Alt work for normal Win32 windows, we have to // let the window frame extend to the whole window (or disable the // redirection surface, but this will break GDI's rendering, so we // can't do this, unfortunately), so we can't change the window frame // margins in this case, otherwise Mica/Mica Alt will be broken. - if (micaEnabled) { + if (extraData->mica) { return {-1, -1, -1, -1}; } if (reset || isWindowFrameBorderVisible()) { @@ -1282,7 +1263,7 @@ bool Utils::showSystemMenu(const QWindow *window, const QPoint &pos, const bool if (!FramelessManager::instance()->isFramelessWindow(window)) { return false; } - const FramelessDataPtr data = FramelessHelperExtractData(window); + const FramelessDataPtr data = FramelessManagerPrivate::getData(window); Q_ASSERT(data); if (!data) { return false; @@ -1298,11 +1279,11 @@ bool Utils::showSystemMenu(const QWindow *window, const QPoint &pos, const bool } // Tweak the menu items according to the current window status and user settings. - const bool disableRestore = data->callbacks.getProperty(kSysMenuDisableRestoreVar, false).toBool(); - const bool disableMinimize = data->callbacks.getProperty(kSysMenuDisableMinimizeVar, false).toBool(); - const bool disableMaximize = data->callbacks.getProperty(kSysMenuDisableMaximizeVar, false).toBool(); + const bool disableRestore = data->callbacks->getProperty(kSysMenuDisableRestoreVar, false).toBool(); + const bool disableMinimize = data->callbacks->getProperty(kSysMenuDisableMinimizeVar, false).toBool(); + const bool disableMaximize = data->callbacks->getProperty(kSysMenuDisableMaximizeVar, false).toBool(); const bool maxOrFull = (IsMaximized(hWnd) || isFullScreen(window)); - const bool fixedSize = data->callbacks.isWindowFixedSize(); + const bool fixedSize = data->callbacks->isWindowFixedSize(); ::EnableMenuItem(hMenu, SC_RESTORE, (MF_BYCOMMAND | ((maxOrFull && !fixedSize && !disableRestore) ? MFS_ENABLED : MFS_DISABLED))); // The first menu item should be selected by default if the menu is brought // up by keyboard. I don't know how to pre-select a menu item but it seems @@ -1342,7 +1323,7 @@ bool Utils::showSystemMenu(const QWindow *window, const QPoint &pos, const bool // highlighting until we unhighlight it manually. ::HiliteMenuItem(hWnd, hMenu, SC_RESTORE, (MF_BYCOMMAND | MFS_UNHILITE)); - if (result == 0) { + if (result == FALSE) { // The user canceled the menu, no need to continue. return true; } @@ -1877,7 +1858,7 @@ bool Utils::startSystemMove(QWindow *window, const QPoint &globalPos) return false; } const auto hwnd = qWindowId(window); - if (::PostMessageW(hwnd, WM_SYSCOMMAND, 0xF012 /*SC_DRAGMOVE*/, 0) == FALSE) { + if (::PostMessageW(hwnd, WM_SYSCOMMAND, SC_DRAGMOVE, 0) == FALSE) { WARNING << getSystemErrorMessage(kPostMessageW); return false; } @@ -1914,10 +1895,8 @@ bool Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi bool Utils::isWindowFrameBorderVisible() { static const auto result = []() -> bool { +#if FRAMELESSHELPER_CONFIG(native_impl) const FramelessConfig * const config = FramelessConfig::instance(); - if (config->isSet(Option::UseCrossPlatformQtImplementation)) { - return false; - } if (config->isSet(Option::ForceShowWindowFrameBorder)) { return true; } @@ -1925,6 +1904,9 @@ bool Utils::isWindowFrameBorderVisible() return false; } return WindowsVersionHelper::isWin10OrGreater(); +#else + return false; +#endif }(); return result; } @@ -1950,8 +1932,20 @@ bool Utils::installWindowProcHook(const QWindow *window) if (!window) { return false; } + const FramelessDataPtr data = FramelessManagerPrivate::getData(window); + Q_ASSERT(data); + if (!data) { + return false; + } + if (!data->extraData.ptr) { + data->extraData.ptr = new FramelessDataExtra(); + } + if (!data->extraData.deleter) { + data->extraData.deleter = FramelessDataExtraDeleter; + } + const auto extraData = static_cast(data->extraData.ptr); const auto hwnd = qWindowId(window); - if (!g_win32UtilsData()->qtWindowProc) { + if (!extraData->qtWindowProc) { ::SetLastError(ERROR_SUCCESS); const auto qtWindowProc = reinterpret_cast(::GetWindowLongPtrW(hwnd, GWLP_WNDPROC)); Q_ASSERT(qtWindowProc); @@ -1959,53 +1953,56 @@ bool Utils::installWindowProcHook(const QWindow *window) WARNING << getSystemErrorMessage(kGetWindowLongPtrW); return false; } - g_win32UtilsData()->qtWindowProc = qtWindowProc; + extraData->qtWindowProc = qtWindowProc; } - FramelessDataPtr data = FramelessHelperExtractData(window); - if (!data) { - data.reset(new FramelessData); - FramelessHelperSetData(const_cast(window), data); - } - if (!data->windowProcHooked) { + if (!extraData->windowProcHooked) { ::SetLastError(ERROR_SUCCESS); if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast(FramelessHelperHookWindowProc)) == 0) { WARNING << getSystemErrorMessage(kSetWindowLongPtrW); return false; } - data->windowProcHooked = true; + extraData->windowProcHooked = true; } return true; } -bool Utils::uninstallWindowProcHook(const WId windowId) +bool Utils::uninstallWindowProcHook(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } - const auto it = g_win32UtilsData()->data.constFind(windowId); - if (it != g_win32UtilsData()->data.constEnd()) { - g_win32UtilsData()->data.erase(it); + const FramelessDataPtr data = FramelessManagerPrivate::getData(window); + Q_ASSERT(data); + if (!data) { + return false; } - if (g_win32UtilsData()->data.isEmpty() && g_win32UtilsData()->qtWindowProc) { - const auto hwnd = reinterpret_cast(windowId); - ::SetLastError(ERROR_SUCCESS); - if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast(g_win32UtilsData()->qtWindowProc)) == 0) { - WARNING << getSystemErrorMessage(kSetWindowLongPtrW); - return false; - } - g_win32UtilsData()->qtWindowProc = nullptr; + const auto extraData = static_cast(data->extraData.ptr); + if (!extraData || !extraData->windowProcHooked) { + return false; } + Q_ASSERT(extraData->qtWindowProc); + if (!extraData->qtWindowProc) { + return false; + } + const auto hwnd = qWindowId(window); + ::SetLastError(ERROR_SUCCESS); + if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast(extraData->qtWindowProc)) == 0) { + WARNING << getSystemErrorMessage(kSetWindowLongPtrW); + return false; + } + extraData->qtWindowProc = nullptr; + extraData->windowProcHooked = false; return true; } -bool Utils::setAeroSnappingEnabled(const WId windowId, const bool enable) +bool Utils::setAeroSnappingEnabled(const QWindow *window, const bool enable) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); ::SetLastError(ERROR_SUCCESS); const auto oldWindowStyle = static_cast(::GetWindowLongPtrW(hwnd, GWL_STYLE)); if (oldWindowStyle == 0) { @@ -2027,7 +2024,7 @@ bool Utils::setAeroSnappingEnabled(const WId windowId, const bool enable) WARNING << getSystemErrorMessage(kSetWindowLongPtrW); return false; } - return triggerFrameChange(windowId); + return triggerFrameChange(window); } bool Utils::tryToEnableHighestDpiAwarenessLevel() @@ -2138,10 +2135,10 @@ bool Utils::tryToEnableHighestDpiAwarenessLevel() return false; } -bool Utils::updateGlobalWin32ControlsTheme(const WId windowId, const bool dark) +bool Utils::updateGlobalWin32ControlsTheme(const QWindow *window, const bool dark) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } // There's no global dark theme for common Win32 controls before Win10 1809. @@ -2151,7 +2148,7 @@ bool Utils::updateGlobalWin32ControlsTheme(const WId windowId, const bool dark) if (!API_THEME_AVAILABLE(SetWindowTheme)) { return false; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); const HRESULT hr = API_CALL_FUNCTION(uxtheme, SetWindowTheme, hwnd, (dark ? kSystemDarkThemeResourceName : kSystemLightThemeResourceName), nullptr); if (FAILED(hr)) { @@ -2209,10 +2206,10 @@ bool Utils::shouldAppsUseDarkMode_windows() return resultFromRegistry(); } -bool Utils::setCornerStyleForWindow(const WId windowId, const WindowCornerStyle style) +bool Utils::setCornerStyleForWindow(const QWindow *window, const WindowCornerStyle style) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } // We cannot change the window corner style until Windows 11. @@ -2222,7 +2219,7 @@ bool Utils::setCornerStyleForWindow(const WId windowId, const WindowCornerStyle if (!API_DWM_AVAILABLE(DwmSetWindowAttribute)) { return false; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); const auto wcp = [style]() -> _DWM_WINDOW_CORNER_PREFERENCE { switch (style) { case WindowCornerStyle::Default: @@ -2246,22 +2243,32 @@ bool Utils::setCornerStyleForWindow(const WId windowId, const WindowCornerStyle return true; } -bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode, const QColor &color) +bool Utils::setBlurBehindWindowEnabled(const QWindow *window, const BlurMode mode, const QColor &color) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } - const auto hwnd = reinterpret_cast(windowId); + const FramelessDataPtr data = FramelessManagerPrivate::getData(window); + Q_ASSERT(data); + if (!data) { + return false; + } + const auto extraData = static_cast(data->extraData.ptr); + Q_ASSERT(extraData); + if (!extraData) { + return false; + } + const auto hwnd = qWindowId(window); if (WindowsVersionHelper::isWin8OrGreater()) { if (!(API_DWM_AVAILABLE(DwmSetWindowAttribute) && API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea))) { WARNING << "Blur behind window is not available on current platform."; return false; } - const auto restoreWindowFrameMargins = [windowId]() -> void { - g_win32UtilsData()->micaWindowIds.removeAll(windowId); - std::ignore = updateWindowFrameMargins(windowId, false); + const auto restoreWindowFrameMargins = [window, extraData]() -> void { + extraData->mica = false; + std::ignore = updateWindowFrameMargins(window, false); }; static const bool preferMicaAlt = (qEnvironmentVariableIntValue("FRAMELESSHELPER_PREFER_MICA_ALT") != 0); const auto blurMode = [mode]() -> BlurMode { @@ -2334,7 +2341,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode, return result; } else { if ((blurMode == BlurMode::Windows_Mica) || (blurMode == BlurMode::Windows_MicaAlt)) { - g_win32UtilsData()->micaWindowIds.append(windowId); + extraData->mica = true; // By giving a negative value, DWM will extend the window frame into the whole // client area. We need this step because the Mica material can only be applied // to the non-client area of a window. Without this step, you'll get a window @@ -2531,13 +2538,13 @@ bool Utils::isBlurBehindWindowSupported() return result; } -bool Utils::hideOriginalTitleBarElements(const WId windowId, const bool disable) +bool Utils::hideOriginalTitleBarElements(const QWindow *window, const bool disable) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); static constexpr const DWORD validBits = (WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON | WTNCA_NOSYSMENU); const DWORD mask = (disable ? validBits : 0); const HRESULT hr = _SetWindowThemeNonClientAttributes(hwnd, mask, mask); @@ -2575,9 +2582,9 @@ bool Utils::setQtDarkModeAwareEnabled(const bool enable) // flag has no effect for pure Qt Quick applications. return {App::DarkModeWindowFrames | App::DarkModeStyle}; # else // (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) \ - // Don't try to use the broken dark theme for Qt Widgets applications. \ - // For Qt Quick applications this is also enough. There's no global dark \ - // theme for them anyway. + // Don't try to use the broken dark theme for Qt Widgets applications. \ + // For Qt Quick applications this is also enough. There's no global dark \ + // theme for them anyway. return {App::DarkModeWindowFrames}; # endif // (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) }()); @@ -2604,13 +2611,13 @@ bool Utils::registerThemeChangeNotification() return true; } -bool Utils::refreshWin32ThemeResources(const WId windowId, const bool dark) +bool Utils::refreshWin32ThemeResources(const QWindow *window, const bool dark) { // Code learned from the following repositories. Thank very much for their great effort! // https://github.com/ysc3839/win32-darkmode/blob/master/win32-darkmode/DarkMode.h // https://github.com/TortoiseGit/TortoiseGit/blob/master/src/TortoiseGitBlame/MainFrm.cpp - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } // We have no way to adjust such things until Win10 1809. @@ -2620,7 +2627,7 @@ bool Utils::refreshWin32ThemeResources(const WId windowId, const bool dark) if (!API_DWM_AVAILABLE(DwmSetWindowAttribute)) { return false; } - const auto hWnd = reinterpret_cast(windowId); + const auto hWnd = qWindowId(window); const DWORD borderFlag = (WindowsVersionHelper::isWin1020H1OrGreater() ? _DWMWA_USE_IMMERSIVE_DARK_MODE : _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1); const BOOL darkFlag = (dark ? TRUE : FALSE); @@ -2689,10 +2696,10 @@ bool Utils::refreshWin32ThemeResources(const WId windowId, const bool dark) return true; } -bool Utils::enableNonClientAreaDpiScalingForWindow(const WId windowId) +bool Utils::enableNonClientAreaDpiScalingForWindow(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } if (!API_USER_AVAILABLE(EnableNonClientDpiScaling)) { @@ -2702,7 +2709,7 @@ bool Utils::enableNonClientAreaDpiScalingForWindow(const WId windowId) if (getDpiAwarenessForCurrentProcess() == DpiAwareness::PerMonitorVersion2) { return true; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); if (API_CALL_FUNCTION4(user32, EnableNonClientDpiScaling, hwnd) == FALSE) { WARNING << getSystemErrorMessage(kEnableNonClientDpiScaling); return false; @@ -2816,10 +2823,10 @@ DpiAwareness Utils::getDpiAwarenessForCurrentProcess(bool *highest) return DpiAwareness::Unknown; } -bool Utils::fixupChildWindowsDpiMessage(const WId windowId) +bool Utils::fixupChildWindowsDpiMessage(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } // This hack is only available on Windows 10 and newer, and starting from @@ -2830,7 +2837,7 @@ bool Utils::fixupChildWindowsDpiMessage(const WId windowId) && (getDpiAwarenessForCurrentProcess() == DpiAwareness::PerMonitorVersion2))) { return true; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); if (_EnableChildWindowDpiMessage2(hwnd, TRUE) != FALSE) { return true; } @@ -2884,13 +2891,13 @@ bool Utils::setDarkModeAllowedForApp(const bool allow) return true; } -bool Utils::bringWindowToFront(const WId windowId) +bool Utils::bringWindowToFront(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); const HWND oldForegroundWindow = ::GetForegroundWindow(); if (!oldForegroundWindow) { // The foreground window can be NULL, it's not an API error. @@ -2956,13 +2963,13 @@ bool Utils::bringWindowToFront(const WId windowId) return moveWindowToMonitor(hwnd, activeMonitor.value()); } -QPoint Utils::getWindowPlacementOffset(const WId windowId) +QPoint Utils::getWindowPlacementOffset(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return {}; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); ::SetLastError(ERROR_SUCCESS); const auto exStyle = static_cast(::GetWindowLongPtrW(hwnd, GWL_EXSTYLE)); if (exStyle == 0) { @@ -2983,13 +2990,13 @@ QPoint Utils::getWindowPlacementOffset(const WId windowId) return {work.left - total.left, work.top - total.top}; } -QRect Utils::getWindowRestoreGeometry(const WId windowId) +QRect Utils::getWindowRestoreGeometry(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return {}; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); WINDOWPLACEMENT wp; SecureZeroMemory(&wp, sizeof(wp)); wp.length = sizeof(wp); @@ -2997,16 +3004,25 @@ QRect Utils::getWindowRestoreGeometry(const WId windowId) WARNING << getSystemErrorMessage(kGetWindowPlacement); return {}; } - return rect2qrect(wp.rcNormalPosition).translated(getWindowPlacementOffset(windowId)); + return rect2qrect(wp.rcNormalPosition).translated(getWindowPlacementOffset(window)); } -bool Utils::removeMicaWindow(const WId windowId) +bool Utils::removeMicaWindow(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } - g_win32UtilsData()->micaWindowIds.removeAll(windowId); + const FramelessDataPtr data = FramelessManagerPrivate::getData(window); + Q_ASSERT(data); + if (!data) { + return false; + } + const auto extraData = static_cast(data->extraData.ptr); + if (!extraData || !extraData->mica) { + return false; + } + extraData->mica = false; return true; } @@ -3041,13 +3057,13 @@ quint64 Utils::getKeyState() return result; } -bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const bool checkTopLevel) +bool Utils::isValidWindow(const QWindow *window, const bool checkVisible, const bool checkTopLevel) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); if (::IsWindow(hwnd) == FALSE) { return false; } @@ -3056,7 +3072,7 @@ bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const boo return false; } const LONG_PTR exStyles = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE); - if ((exStyles != 0) && (exStyles & WS_EX_TOOLWINDOW)) { + if ((exStyles == 0) || (exStyles & WS_EX_TOOLWINDOW)) { return false; } RECT rect = { 0, 0, 0, 0 }; @@ -3079,10 +3095,10 @@ bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const boo return true; } -bool Utils::updateFramebufferTransparency(const WId windowId) +bool Utils::updateFramebufferTransparency(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } if (!API_DWM_AVAILABLE(DwmEnableBlurBehindWindow)) { @@ -3093,7 +3109,7 @@ bool Utils::updateFramebufferTransparency(const WId windowId) if (!isDwmCompositionEnabled()) { return false; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); bool opaque = false; bool ok = false; std::ignore = getDwmColorizationColor(&opaque, &ok); @@ -3102,11 +3118,11 @@ bool Utils::updateFramebufferTransparency(const WId windowId) DWM_BLURBEHIND bb; SecureZeroMemory(&bb, sizeof(bb)); bb.dwFlags = (DWM_BB_ENABLE | DWM_BB_BLURREGION); - bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1); + bb.hRgnBlur = ::CreateRectRgn(0, 0, -1, -1); bb.fEnable = TRUE; const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmEnableBlurBehindWindow, hwnd, &bb); if (bb.hRgnBlur) { - if (DeleteObject(bb.hRgnBlur) == FALSE) { + if (::DeleteObject(bb.hRgnBlur) == FALSE) { WARNING << getSystemErrorMessage(kDeleteObject); } } @@ -3133,14 +3149,14 @@ bool Utils::updateFramebufferTransparency(const WId windowId) return true; } -QMargins Utils::getWindowSystemFrameMargins(const WId windowId) +QMargins Utils::getWindowSystemFrameMargins(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return {}; } - const auto horizontalMargin = int(getResizeBorderThickness(windowId, true, true)); - const auto verticalMargin = int(getResizeBorderThickness(windowId, false, true)); + const auto horizontalMargin = int(getResizeBorderThickness(window, true, true)); + const auto verticalMargin = int(getResizeBorderThickness(window, false, true)); return QMargins{ horizontalMargin, verticalMargin, horizontalMargin, verticalMargin }; }