win: minor improvement
This commit is contained in:
parent
2035fed510
commit
013f2e845f
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
|
|
@ -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>
|
||||
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue