diff --git a/examples/dialog/main.cpp b/examples/dialog/main.cpp index a157e2d..3324c31 100644 --- a/examples/dialog/main.cpp +++ b/examples/dialog/main.cpp @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) // Must be called after QGuiApplication has been constructed, we are using // some private functions from QPA which won't be available until there's // a QGuiApplication instance. - FramelessHelper::Core::setApplicationOSThemeAware(true, false); + FramelessHelper::Core::setApplicationOSThemeAware(false); FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners); FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow); diff --git a/examples/mainwindow/main.cpp b/examples/mainwindow/main.cpp index 3bbb107..6d12087 100644 --- a/examples/mainwindow/main.cpp +++ b/examples/mainwindow/main.cpp @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) // Must be called after QGuiApplication has been constructed, we are using // some private functions from QPA which won't be available until there's // a QGuiApplication instance. - FramelessHelper::Core::setApplicationOSThemeAware(true, false); + FramelessHelper::Core::setApplicationOSThemeAware(false); FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners); FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow); diff --git a/examples/openglwidget/main.cpp b/examples/openglwidget/main.cpp index 2eead11..276a439 100644 --- a/examples/openglwidget/main.cpp +++ b/examples/openglwidget/main.cpp @@ -79,7 +79,7 @@ int main(int argc, char *argv[]) // Must be called after QGuiApplication has been constructed, we are using // some private functions from QPA which won't be available until there's // a QGuiApplication instance. - FramelessHelper::Core::setApplicationOSThemeAware(true, false); + FramelessHelper::Core::setApplicationOSThemeAware(false); FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners); FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow); diff --git a/examples/quick/main.cpp b/examples/quick/main.cpp index b7a20be..1eedddb 100644 --- a/examples/quick/main.cpp +++ b/examples/quick/main.cpp @@ -54,7 +54,7 @@ int main(int argc, char *argv[]) // Must be called after QGuiApplication has been constructed, we are using // some private functions from QPA which won't be available until there's // a QGuiApplication instance. - FramelessHelper::Core::setApplicationOSThemeAware(true, true); + FramelessHelper::Core::setApplicationOSThemeAware(true); FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners); FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow); diff --git a/examples/widget/main.cpp b/examples/widget/main.cpp index 4958985..95f9aaf 100644 --- a/examples/widget/main.cpp +++ b/examples/widget/main.cpp @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) // Must be called after QGuiApplication has been constructed, we are using // some private functions from QPA which won't be available until there's // a QGuiApplication instance. - FramelessHelper::Core::setApplicationOSThemeAware(true, false); + FramelessHelper::Core::setApplicationOSThemeAware(false); FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners); FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow); diff --git a/include/FramelessHelper/Core/framelesshelpercore_global.h b/include/FramelessHelper/Core/framelesshelpercore_global.h index dcb8363..4d33f1a 100644 --- a/include/FramelessHelper/Core/framelesshelpercore_global.h +++ b/include/FramelessHelper/Core/framelesshelpercore_global.h @@ -579,7 +579,7 @@ FRAMELESSHELPER_CORE_API void uninitialize(); [[nodiscard]] FRAMELESSHELPER_CORE_API Global::VersionInfo version(); FRAMELESSHELPER_CORE_API void registerInitializeHook(const Global::InitializeHookCallback &cb); FRAMELESSHELPER_CORE_API void registerUninitializeHook(const Global::UninitializeHookCallback &cb); -FRAMELESSHELPER_CORE_API void setApplicationOSThemeAware(const bool enable, const bool pureQuick); +FRAMELESSHELPER_CORE_API void setApplicationOSThemeAware(const bool pureQuick); } // namespace FramelessHelper::Core FRAMELESSHELPER_END_NAMESPACE diff --git a/src/core/framelesshelper_qt.cpp b/src/core/framelesshelper_qt.cpp index 9bd1d8a..eaf260d 100644 --- a/src/core/framelesshelper_qt.cpp +++ b/src/core/framelesshelper_qt.cpp @@ -101,7 +101,7 @@ void FramelessHelperQt::addWindow(const SystemParameters ¶ms) Utils::setSystemTitleBarVisible(windowId, false); #endif static const bool isQtQuickApplication = (params.getCurrentApplicationType() == ApplicationType::Quick); - FramelessHelper::Core::setApplicationOSThemeAware(true, isQtQuickApplication); + FramelessHelper::Core::setApplicationOSThemeAware(isQtQuickApplication); } bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) diff --git a/src/core/framelesshelper_win.cpp b/src/core/framelesshelper_win.cpp index 23c7032..bd1290c 100644 --- a/src/core/framelesshelper_win.cpp +++ b/src/core/framelesshelper_win.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "framelessmanager.h" #include "framelessmanager_p.h" @@ -74,6 +73,7 @@ FRAMELESSHELPER_STRING_CONSTANT(TrackMouseEvent) FRAMELESSHELPER_STRING_CONSTANT(FindWindowW) FRAMELESSHELPER_STRING_CONSTANT(UnregisterClassW) FRAMELESSHELPER_BYTEARRAY_CONSTANT2(DontOverrideCursor, "FRAMELESSHELPER_DONT_OVERRIDE_CURSOR") +FRAMELESSHELPER_STRING_CONSTANT(DestroyWindow) struct Win32HelperData { @@ -92,21 +92,6 @@ struct Win32Helper Q_GLOBAL_STATIC(Win32Helper, g_win32Helper) -[[nodiscard]] static inline bool unregisterFallbackTitleBarWindowClass() -{ - const HINSTANCE instance = GetModuleHandleW(nullptr); - if (instance) { - if (UnregisterClassW(kFallbackTitleBarWindowClassName, instance) == FALSE) { - WARNING << Utils::getSystemErrorMessage(kUnregisterClassW); - return false; - } - } else { - WARNING << Utils::getSystemErrorMessage(kGetModuleHandleW); - return false; - } - return true; -} - [[nodiscard]] static inline LRESULT CALLBACK FallbackTitleBarWindowProc (const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) { @@ -347,25 +332,6 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper) case WM_NCRBUTTONDBLCLK: case WM_NCRBUTTONUP: return SendMessageW(parentWindowHandle, uMsg, wParam, lParam); - case WM_DESTROY: { - const QMutexLocker locker(&g_win32Helper()->mutex); - g_win32Helper()->fallbackTitleBarToParentWindowMapping.remove(windowId); - if (g_win32Helper()->fallbackTitleBarToParentWindowMapping.count() < 1) { - // According to Microsoft Docs, window classes registered by DLLs will - // not be unregistered automatically on application termination, so we - // have to unregister them manually. - // And also from the docs, we are told that when the window received - // the "WM_DESTROY" message, the window may still exist, and we can't - // unregister the window class if it's corresponding windows are not - // all destroyed. So we have to wait a little bit to make sure the - // last window has been destroyed. - QTimer::singleShot(0, qApp, [](){ - if (!unregisterFallbackTitleBarWindowClass()) { - WARNING << "Failed to unregister the window class of the fallback title bar window."; - } - }); - } - } break; default: break; } @@ -448,6 +414,30 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper) wcex.lpfnWndProc = FallbackTitleBarWindowProc; wcex.hInstance = instance; if (RegisterClassExW(&wcex) != INVALID_ATOM) { + FramelessHelper::Core::registerUninitializeHook([](){ + g_win32Helper()->mutex.lock(); + if (!g_win32Helper()->fallbackTitleBarToParentWindowMapping.isEmpty()) { + auto it = g_win32Helper()->fallbackTitleBarToParentWindowMapping.constBegin(); + while (it != g_win32Helper()->fallbackTitleBarToParentWindowMapping.constEnd()) { + const auto hwnd = reinterpret_cast(it.key()); + Q_ASSERT(hwnd); + if (hwnd && (DestroyWindow(hwnd) == FALSE)) { + WARNING << Utils::getSystemErrorMessage(kDestroyWindow); + } + ++it; + } + g_win32Helper()->fallbackTitleBarToParentWindowMapping.clear(); + } + g_win32Helper()->mutex.unlock(); + const HINSTANCE instance = GetModuleHandleW(nullptr); + if (!instance) { + WARNING << Utils::getSystemErrorMessage(kGetModuleHandleW); + return; + } + if (UnregisterClassW(kFallbackTitleBarWindowClassName, instance) == FALSE) { + WARNING << Utils::getSystemErrorMessage(kUnregisterClassW); + } + }); return true; } WARNING << Utils::getSystemErrorMessage(kRegisterClassExW); @@ -523,7 +513,7 @@ void FramelessHelperWin::addWindow(const SystemParameters ¶ms) const bool dark = Utils::shouldAppsUseDarkMode(); static const bool isQtQuickApplication = (params.getCurrentApplicationType() == ApplicationType::Quick); // Tell DWM we may need dark theme non-client area (title bar & frame border). - FramelessHelper::Core::setApplicationOSThemeAware(true, isQtQuickApplication); + FramelessHelper::Core::setApplicationOSThemeAware(isQtQuickApplication); Utils::updateWindowFrameBorderColor(windowId, dark); static const bool isWin10RS5OrGreater = Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1809); if (isWin10RS5OrGreater) { diff --git a/src/core/framelesshelpercore_global.cpp b/src/core/framelesshelpercore_global.cpp index 6f6f063..e23a24b 100644 --- a/src/core/framelesshelpercore_global.cpp +++ b/src/core/framelesshelpercore_global.cpp @@ -271,7 +271,7 @@ void registerUninitializeHook(const UninitializeHookCallback &cb) coreData()->uninitHooks.append(cb); } -void setApplicationOSThemeAware(const bool enable, const bool pureQuick) +void setApplicationOSThemeAware(const bool pureQuick) { static bool set = false; if (set) { @@ -280,9 +280,8 @@ void setApplicationOSThemeAware(const bool enable, const bool pureQuick) set = true; #if (defined(Q_OS_WINDOWS) && (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))) - Utils::setQtDarkModeAwareEnabled(enable, pureQuick); + Utils::setQtDarkModeAwareEnabled(true, pureQuick); #else - Q_UNUSED(enable); Q_UNUSED(pureQuick); #endif diff --git a/src/core/utils_mac.mm b/src/core/utils_mac.mm index 86fa60c..6eb213b 100644 --- a/src/core/utils_mac.mm +++ b/src/core/utils_mac.mm @@ -567,6 +567,24 @@ Q_GLOBAL_STATIC(MacUtilsData, g_macUtilsData); const auto proxy = new NSWindowProxy(qwindow, nswindow); g_macUtilsData()->hash.insert(windowId, proxy); } + static const int hook = []() -> int { + FramelessHelper::Core::registerUninitializeHook([](){ + const QMutexLocker locker(&g_macUtilsData()->mutex); + if (g_macUtilsData()->hash.isEmpty()) { + return; + } + for (auto &&proxy : qAsConst(g_macUtilsData()->hash)) { + Q_ASSERT(proxy); + if (!proxy) { + continue; + } + delete proxy; + } + g_macUtilsData()->hash.clear(); + }); + return 0; + }(); + Q_UNUSED(hook); return g_macUtilsData()->hash.value(windowId); } diff --git a/src/core/utils_win.cpp b/src/core/utils_win.cpp index f18d3bc..b2d28e8 100644 --- a/src/core/utils_win.cpp +++ b/src/core/utils_win.cpp @@ -240,41 +240,6 @@ private: T *p = nullptr; }; -struct WindowClassCleaner -{ - explicit WindowClassCleaner(const HWND hWnd, const std::wstring &Class) : _hWnd(hWnd), _Class(Class) - { - Q_ASSERT(_hWnd); - Q_ASSERT(!_Class.empty()); - } - - ~WindowClassCleaner() - { - if (!_hWnd || _Class.empty()) { - return; - } - if (DestroyWindow(_hWnd) == FALSE) { - WARNING << Utils::getSystemErrorMessage(kDestroyWindow); - return; - } - const HINSTANCE instance = GetModuleHandleW(nullptr); - if (!instance) { - WARNING << Utils::getSystemErrorMessage(kGetModuleHandleW); - return; - } - if (UnregisterClassW(_Class.c_str(), instance) == FALSE) { - WARNING << Utils::getSystemErrorMessage(kUnregisterClassW); - } - } - -private: - Q_DISABLE_COPY_MOVE(WindowClassCleaner) - -private: - const HWND _hWnd = nullptr; - const std::wstring _Class = {}; -}; - [[nodiscard]] static inline QString dwmRegistryKey() { static const QString key = QString::fromWCharArray(kDwmRegistryKey); @@ -319,7 +284,20 @@ private: WARNING << Utils::getSystemErrorMessage(kCreateWindowExW); return nullptr; } - static const auto cleaner = WindowClassCleaner(window, kDummyWindowClassName); + FramelessHelper::Core::registerUninitializeHook([window](){ + if (window && (DestroyWindow(window) == FALSE)) { + WARNING << Utils::getSystemErrorMessage(kDestroyWindow); + return; + } + const HINSTANCE instance = GetModuleHandleW(nullptr); + if (!instance) { + WARNING << Utils::getSystemErrorMessage(kGetModuleHandleW); + return; + } + if (UnregisterClassW(kDummyWindowClassName, instance) == FALSE) { + WARNING << Utils::getSystemErrorMessage(kUnregisterClassW); + } + }); return window; }(); return hwnd;