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

Commit

Permalink
win: minor improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
wangwenx190 committed Aug 14, 2023
1 parent 2035fed commit 013f2e8
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 8 deletions.
5 changes: 4 additions & 1 deletion include/FramelessHelper/Core/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ FRAMELESSHELPER_CORE_API void registerThemeChangeNotification();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isValidGeometry(const QRect &rect);
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor();
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 defaultScreenDpi();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowAccelerated(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowTransparent(const QWindow *window);

#ifdef Q_OS_WINDOWS
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowsVersionOrGreater(const Global::WindowsVersion version);
Expand All @@ -101,7 +103,7 @@ FRAMELESSHELPER_CORE_API void syncWmPaintWithDwm();
FRAMELESSHELPER_CORE_API void showSystemMenu(
const WId windowId, const QPoint &pos,
const bool selectFirstEntry, const SystemParameters *params);
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getDwmColorizationColor();
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getDwmColorizationColor(bool *opaque = nullptr, bool *ok = nullptr);
[[nodiscard]] FRAMELESSHELPER_CORE_API Global::DwmColorizationArea getDwmColorizationArea();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isHighContrastModeEnabled();
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getPrimaryScreenDpi(const bool horizontal);
Expand Down Expand Up @@ -147,6 +149,7 @@ FRAMELESSHELPER_CORE_API void removeMicaWindow(const WId windowId);
FRAMELESSHELPER_CORE_API void removeSysMenuHook(const WId windowId);
FRAMELESSHELPER_CORE_API quint64 queryMouseButtonState();
FRAMELESSHELPER_CORE_API bool isValidWindow(const WId windowId, const bool checkVisible, const bool checkTopLevel);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool updateFramebufferTransparency(const WId windowId);
#endif // Q_OS_WINDOWS

#ifdef Q_OS_LINUX
Expand Down
31 changes: 28 additions & 3 deletions src/core/framelesshelper_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ void FramelessHelperWin::addWindow(FramelessParamsConst params)
qApp->installNativeEventFilter(g_framelessWin32HelperData()->nativeEventFilter.get());
}
DEBUG.noquote() << "The DPI of window" << hwnd2str(windowId) << "is" << data.dpi;
const QWindow *window = params->getWindowHandle();
// Remove the bad window styles added by Qt (it's not that "bad" though).
Utils::maybeFixupQtInternals(windowId);
#if 0
Expand All @@ -571,7 +572,7 @@ void FramelessHelperWin::addWindow(FramelessParamsConst params)
// otherwise we'll get lots of warning messages when we change the window
// geometry, it will also affect the final window geometry because QPA will
// always take it into account when setting window size and position.
Utils::updateInternalWindowFrameMargins(params->getWindowHandle(), true);
Utils::updateInternalWindowFrameMargins(const_cast<QWindow *>(window), true);
#endif
// Tell DWM our preferred frame margin.
Utils::updateWindowFrameMargins(windowId, false);
Expand All @@ -581,6 +582,11 @@ void FramelessHelperWin::addWindow(FramelessParamsConst params)
// Windows, which means only the top level windows can be scaled to the correct
// size, we of course don't want such thing from happening.
Utils::fixupChildWindowsDpiMessage(windowId);
if (Utils::isWindowAccelerated(window) && Utils::isWindowTransparent(window)) {
if (!Utils::updateFramebufferTransparency(windowId)) {
WARNING << "Failed to update the frame buffer transparency.";
}
}
if (WindowsVersionHelper::isWin10RS1OrGreater()) {
// Tell DWM we may need dark theme non-client area (title bar & frame border).
FramelessHelper::Core::setApplicationOSThemeAware();
Expand Down Expand Up @@ -671,6 +677,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}
const FramelessWin32HelperData &data = it.value();
FramelessWin32HelperData &muData = it.value();
const QWindow *window = data.params.getWindowHandle();
const bool frameBorderVisible = Utils::isWindowFrameBorderVisible();
const WPARAM wParam = msg->wParam;
const LPARAM lParam = msg->lParam;
Expand Down Expand Up @@ -1032,8 +1039,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
WARNING << Utils::getSystemErrorMessage(kScreenToClient);
break;
}
const QPoint qtScenePos = Utils::fromNativeLocalPosition(
data.params.getWindowHandle(), QPoint(nativeLocalPos.x, nativeLocalPos.y));
const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint(nativeLocalPos.x, nativeLocalPos.y));
const bool max = IsMaximized(hWnd);
const bool full = Utils::isFullScreen(windowId);
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true);
Expand Down Expand Up @@ -1255,6 +1261,18 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}
} break;
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
case WM_SYSCOMMAND: {
const WPARAM filteredWParam = (wParam & 0xFFF0);
// When the window is fullscreened, don't enter screen saver or power
// 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)) {
*result = 0;
return true;
}
}
} break;
default:
break;
}
Expand Down Expand Up @@ -1331,6 +1349,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
break;
}
}
if ((uMsg == WM_DWMCOMPOSITIONCHANGED) || (uMsg == WM_DWMCOLORIZATIONCOLORCHANGED)) {
if (Utils::isWindowAccelerated(window) && Utils::isWindowTransparent(window)) {
if (!Utils::updateFramebufferTransparency(windowId)) {
WARNING << "Failed to update the frame buffer transparency.";
}
}
}
if (WindowsVersionHelper::isWin11OrGreater() && data.fallbackTitleBarWindowId) {
switch (uMsg) {
case WM_SIZE: // Sent to a window after its size has changed.
Expand Down
41 changes: 41 additions & 0 deletions src/core/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@
#include <QtGui/qguiapplication.h>
#include <QtGui/qfontmetrics.h>
#include <QtGui/qpalette.h>
#include <QtGui/qsurface.h>
#include <QtGui/qsurfaceformat.h>
#ifndef FRAMELESSHELPER_CORE_NO_PRIVATE
# include <QtGui/private/qhighdpiscaling_p.h>
# include <QtGui/private/qwindow_p.h>
#endif // FRAMELESSHELPER_CORE_NO_PRIVATE
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
# include <QtGui/qstylehints.h>
Expand Down Expand Up @@ -587,4 +590,42 @@ QColor Utils::getAccentColor()
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
}

bool Utils::isWindowAccelerated(const QWindow *window)
{
Q_ASSERT(window);
if (!window) {
return false;
}
switch (window->surfaceType()) {
case QSurface::RasterGLSurface:
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
return false;
#else
return qt_window_private(const_cast<QWindow *>(window))->compositing;
#endif
case QSurface::OpenGLSurface:
case QSurface::VulkanSurface:
case QSurface::MetalSurface:
case QSurface::Direct3DSurface:
return true;
default:
break;
}
return false;
}

bool Utils::isWindowTransparent(const QWindow *window)
{
Q_ASSERT(window);
if (!window) {
return false;
}
// On most platforms, QWindow::format() will just return the
// user set format if there is one, otherwise it will return
// an invalid surface format. That means, most of the time
// the following check will not be useful. But since this is
// what the QPA code does, we just mirror it here.
return window->format().hasAlpha();
}

FRAMELESSHELPER_END_NAMESPACE
91 changes: 87 additions & 4 deletions src/core/utils_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,7 @@ QString Utils::getSystemErrorMessage(const QString &function)
return getSystemErrorMessageImpl(function, code);
}

QColor Utils::getDwmColorizationColor()
QColor Utils::getDwmColorizationColor(bool *opaque, bool *ok)
{
const auto resultFromRegistry = []() -> QColor {
const RegistryKey registry(RegistryRootKey::CurrentUser, dwmRegistryKey());
Expand All @@ -790,15 +790,27 @@ QColor Utils::getDwmColorizationColor()
return QColor::fromRgba(qvariant_cast<DWORD>(value));
};
if (!API_DWM_AVAILABLE(DwmGetColorizationColor)) {
if (ok) {
*ok = false;
}
return resultFromRegistry();
}
DWORD color = 0;
BOOL opaque = FALSE;
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmGetColorizationColor, &color, &opaque);
BOOL bOpaque = FALSE;
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmGetColorizationColor, &color, &bOpaque);
if (FAILED(hr)) {
WARNING << getSystemErrorMessageImpl(kDwmGetColorizationColor, hr);
if (ok) {
*ok = false;
}
return resultFromRegistry();
}
if (opaque) {
*opaque = (bOpaque != FALSE);
}
if (ok) {
*ok = true;
}
return QColor::fromRgba(color);
}

Expand Down Expand Up @@ -1357,7 +1369,7 @@ void Utils::maybeFixupQtInternals(const WId windowId)
// and this will also break the normal functionalities for our windows, so we do the
// correction here unconditionally.
static constexpr const DWORD badWindowStyle = WS_POPUP;
static constexpr const DWORD goodWindowStyle = WS_OVERLAPPEDWINDOW;
static constexpr const DWORD goodWindowStyle = (WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
if ((windowStyle & badWindowStyle) || !(windowStyle & goodWindowStyle)) {
SetLastError(ERROR_SUCCESS);
if (SetWindowLongPtrW(hwnd, GWL_STYLE, ((windowStyle & ~badWindowStyle) | goodWindowStyle)) == 0) {
Expand All @@ -1367,6 +1379,22 @@ void Utils::maybeFixupQtInternals(const WId windowId)
}
}
}
SetLastError(ERROR_SUCCESS);
const auto extendedWindowStyle = static_cast<DWORD>(GetWindowLongPtrW(hwnd, GWL_EXSTYLE));
if (extendedWindowStyle == 0) {
WARNING << getSystemErrorMessage(kGetWindowLongPtrW);
} else {
static constexpr const DWORD badWindowStyle = (WS_EX_OVERLAPPEDWINDOW | WS_EX_STATICEDGE | WS_EX_DLGMODALFRAME | WS_EX_CONTEXTHELP);
static constexpr const DWORD goodWindowStyle = WS_EX_APPWINDOW;
if ((extendedWindowStyle & badWindowStyle) || !(extendedWindowStyle & goodWindowStyle)) {
SetLastError(ERROR_SUCCESS);
if (SetWindowLongPtrW(hwnd, GWL_EXSTYLE, ((extendedWindowStyle & ~badWindowStyle) | goodWindowStyle)) == 0) {
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
} else {
shouldUpdateFrame = true;
}
}
}
if (shouldUpdateFrame) {
triggerFrameChange(windowId);
}
Expand Down Expand Up @@ -2574,4 +2602,59 @@ bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const boo
return true;
}

bool Utils::updateFramebufferTransparency(const WId windowId)
{
Q_ASSERT(windowId);
if (!windowId) {
return false;
}
if (!API_DWM_AVAILABLE(DwmEnableBlurBehindWindow)) {
WARNING << "DwmEnableBlurBehindWindow() is not available on current platform.";
return false;
}
// DwmEnableBlurBehindWindow() won't be functional if DWM composition
// is not enabled, so we bail out early if this is the case.
if (!isDwmCompositionEnabled()) {
return false;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
bool opaque = false;
bool ok = false;
std::ignore = getDwmColorizationColor(&opaque, &ok);
if (WindowsVersionHelper::isWin8OrGreater() || (ok && !opaque)) {
#if 0 // Windows QPA will always do this for us.
DWM_BLURBEHIND bb;
SecureZeroMemory(&bb, sizeof(bb));
bb.dwFlags = (DWM_BB_ENABLE | DWM_BB_BLURREGION);
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) {
WARNING << getSystemErrorMessage(kDeleteObject);
}
}
if (FAILED(hr)) {
WARNING << getSystemErrorMessageImpl(kDwmEnableBlurBehindWindow, hr);
return false;
}
#endif
} else {
// HACK: Disable framebuffer transparency on Windows 7 when the
// colorization color is opaque, because otherwise the window
// contents is blended additively with the previous frame instead
// of replacing it
DWM_BLURBEHIND bb;
SecureZeroMemory(&bb, sizeof(bb));
bb.dwFlags = DWM_BB_ENABLE;
bb.fEnable = FALSE;
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmEnableBlurBehindWindow, hwnd, &bb);
if (FAILED(hr)) {
WARNING << getSystemErrorMessageImpl(kDwmEnableBlurBehindWindow, hr);
return false;
}
}
return true;
}

FRAMELESSHELPER_END_NAMESPACE

0 comments on commit 013f2e8

Please sign in to comment.