free all resources during destruction

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-09-06 13:40:16 +08:00
parent fb13ff1c1b
commit 7dda58deaf
11 changed files with 67 additions and 82 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -101,7 +101,7 @@ void FramelessHelperQt::addWindow(const SystemParameters &params)
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)

View File

@ -28,7 +28,6 @@
#include <QtCore/qmutex.h>
#include <QtCore/qvariant.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qtimer.h>
#include <QtGui/qwindow.h>
#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<HWND>(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 &params)
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) {

View File

@ -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

View File

@ -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);
}

View File

@ -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;