diff --git a/src/core/framelesshelper_win.cpp b/src/core/framelesshelper_win.cpp index 2e254d2..ebc7bd8 100644 --- a/src/core/framelesshelper_win.cpp +++ b/src/core/framelesshelper_win.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "framelessmanager.h" #include "framelessmanager_p.h" @@ -46,7 +47,7 @@ Q_LOGGING_CATEGORY(lcFramelessHelperWin, "wangwenx190.framelesshelper.core.impl. using namespace Global; -static constexpr const wchar_t kFallbackTitleBarWindowClass[] = L"FALLBACK_TITLEBAR_WINDOW_CLASS\0"; +static constexpr const wchar_t kFallbackTitleBarWindowClassName[] = L"org.wangwenx190.FramelessHelper.FallbackTitleBarWindow\0"; FRAMELESSHELPER_BYTEARRAY_CONSTANT2(Win32MessageTypeName, "windows_generic_MSG") FRAMELESSHELPER_STRING_CONSTANT(MonitorFromWindow) FRAMELESSHELPER_STRING_CONSTANT(GetMonitorInfoW) @@ -71,6 +72,7 @@ FRAMELESSHELPER_STRING_CONSTANT(SetLayeredWindowAttributes) FRAMELESSHELPER_STRING_CONSTANT(SetWindowPos) FRAMELESSHELPER_STRING_CONSTANT(TrackMouseEvent) FRAMELESSHELPER_STRING_CONSTANT(FindWindowW) +FRAMELESSHELPER_STRING_CONSTANT(UnregisterClassW) struct Win32HelperData { @@ -89,6 +91,21 @@ 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) { @@ -328,6 +345,25 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper) case WM_NCRBUTTONDBLCLK: case WM_NCRBUTTONUP: return SendMessageW(parentWindowHandle, uMsg, wParam, lParam); + case WM_DESTROY: { + 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; } @@ -387,31 +423,41 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper) return false; } const auto parentWindowHandle = reinterpret_cast(parentWindowId); - const auto instance = static_cast(GetModuleHandleW(nullptr)); + const HINSTANCE instance = GetModuleHandleW(nullptr); Q_ASSERT(instance); if (!instance) { WARNING << Utils::getSystemErrorMessage(kGetModuleHandleW); return false; } - static const ATOM fallbackTitleBarWindowClass = [instance]() -> ATOM { - WNDCLASSEXW wcex; + static const bool fallbackTitleBarWindowClass = [instance]() -> ATOM { + WNDCLASSEXW wcex = {}; + // First try to find out if we have registered the window class already. + if (GetClassInfoExW(instance, kFallbackTitleBarWindowClassName, &wcex) != FALSE) { + // Register the same window class for multiple times will fail. + return true; + } SecureZeroMemory(&wcex, sizeof(wcex)); wcex.cbSize = sizeof(wcex); + // The "CS_DBLCLKS" style is necessary, don't remove it! wcex.style = (CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS); - wcex.lpszClassName = kFallbackTitleBarWindowClass; + wcex.lpszClassName = kFallbackTitleBarWindowClassName; wcex.hbrBackground = static_cast(GetStockObject(BLACK_BRUSH)); wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW); wcex.lpfnWndProc = FallbackTitleBarWindowProc; wcex.hInstance = instance; - return RegisterClassExW(&wcex); + if (RegisterClassExW(&wcex) != INVALID_ATOM) { + return true; + } + WARNING << Utils::getSystemErrorMessage(kRegisterClassExW); + return false; }(); Q_ASSERT(fallbackTitleBarWindowClass); if (!fallbackTitleBarWindowClass) { - WARNING << Utils::getSystemErrorMessage(kRegisterClassExW); + WARNING << "Failed to register the window class for the fallback title bar window."; return false; } const HWND fallbackTitleBarWindowHandle = CreateWindowExW((WS_EX_LAYERED | WS_EX_NOREDIRECTIONBITMAP), - kFallbackTitleBarWindowClass, nullptr, WS_CHILD, 0, 0, 0, 0, + kFallbackTitleBarWindowClassName, nullptr, WS_CHILD, 0, 0, 0, 0, parentWindowHandle, nullptr, instance, nullptr); Q_ASSERT(fallbackTitleBarWindowHandle); if (!fallbackTitleBarWindowHandle) { diff --git a/src/core/micamaterial.cpp b/src/core/micamaterial.cpp index e7afb8a..0738312 100644 --- a/src/core/micamaterial.cpp +++ b/src/core/micamaterial.cpp @@ -383,15 +383,18 @@ static inline void expblur(QImage &img, qreal radius, const bool improvedQuality } if (p) { + p->save(); p->scale(scale, scale); - p->setRenderHints(QPainter::Antialiasing | - QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform); + p->setRenderHint(QPainter::Antialiasing, false); + p->setRenderHint(QPainter::TextAntialiasing, false); + p->setRenderHint(QPainter::SmoothPixmapTransform, false); #if (QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)) const QSize imageSize = blurImage.deviceIndependentSize().toSize(); #else const QSize imageSize = QSizeF(QSizeF(blurImage.size()) / blurImage.devicePixelRatio()).toSize(); #endif p->drawImage(QRect(QPoint(0, 0), imageSize), blurImage); + p->restore(); } } @@ -535,7 +538,7 @@ void MicaMaterialPrivate::maybeGenerateBlurredWallpaper(const bool force) g_micaMaterialData()->mutex.lock(); QPainter painter(&g_micaMaterialData()->blurredWallpaper); #if 1 - qt_blurImage(&painter, buffer, kDefaultBlurRadius, true, false); + qt_blurImage(&painter, buffer, kDefaultBlurRadius, false, false); #else painter.drawImage(desktopOriginPoint, buffer); #endif diff --git a/src/core/utils_win.cpp b/src/core/utils_win.cpp index 2725bc2..eda156a 100644 --- a/src/core/utils_win.cpp +++ b/src/core/utils_win.cpp @@ -52,7 +52,7 @@ Q_LOGGING_CATEGORY(lcUtilsWin, "wangwenx190.framelesshelper.core.utils.win") using namespace Global; -static constexpr const wchar_t kDummyWindowClassName[] = L"FRAMELESSHELPER_DUMMY_WINDOW_CLASS"; +static constexpr const wchar_t kDummyWindowClassName[] = L"org.wangwenx190.FramelessHelper.DummyWindow\0"; static const QString qDwmColorKeyName = QString::fromWCharArray(kDwmColorKeyName); FRAMELESSHELPER_STRING_CONSTANT2(SuccessMessageText, "The operation completed successfully.") FRAMELESSHELPER_STRING_CONSTANT2(EmptyMessageText, "FormatMessageW() returned empty string.") @@ -258,21 +258,22 @@ private: [[nodiscard]] static inline HWND ensureDummyWindow() { static const HWND hwnd = []() -> HWND { - const HMODULE instance = GetModuleHandleW(nullptr); + const HINSTANCE instance = GetModuleHandleW(nullptr); if (!instance) { WARNING << Utils::getSystemErrorMessage(kGetModuleHandleW); return nullptr; } - WNDCLASSEXW wcex; - SecureZeroMemory(&wcex, sizeof(wcex)); - wcex.cbSize = sizeof(wcex); - wcex.lpfnWndProc = DefWindowProcW; - wcex.hInstance = instance; - wcex.lpszClassName = kDummyWindowClassName; - const ATOM atom = RegisterClassExW(&wcex); - if (!atom) { - WARNING << Utils::getSystemErrorMessage(kRegisterClassExW); - return nullptr; + WNDCLASSEXW wcex = {}; + if (GetClassInfoExW(instance, kDummyWindowClassName, &wcex) == FALSE) { + SecureZeroMemory(&wcex, sizeof(wcex)); + wcex.cbSize = sizeof(wcex); + wcex.lpfnWndProc = DefWindowProcW; + wcex.hInstance = instance; + wcex.lpszClassName = kDummyWindowClassName; + if (RegisterClassExW(&wcex) == INVALID_ATOM) { + WARNING << Utils::getSystemErrorMessage(kRegisterClassExW); + return nullptr; + } } const HWND window = CreateWindowExW(0, kDummyWindowClassName, nullptr, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, nullptr, nullptr, instance, nullptr);