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 bool isValidGeometry(const QRect &rect);
|
||||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor();
|
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor();
|
||||||
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 defaultScreenDpi();
|
[[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
|
#ifdef Q_OS_WINDOWS
|
||||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowsVersionOrGreater(const Global::WindowsVersion version);
|
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowsVersionOrGreater(const Global::WindowsVersion version);
|
||||||
|
@ -101,7 +103,7 @@ FRAMELESSHELPER_CORE_API void syncWmPaintWithDwm();
|
||||||
FRAMELESSHELPER_CORE_API void showSystemMenu(
|
FRAMELESSHELPER_CORE_API void showSystemMenu(
|
||||||
const WId windowId, const QPoint &pos,
|
const WId windowId, const QPoint &pos,
|
||||||
const bool selectFirstEntry, const SystemParameters *params);
|
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 Global::DwmColorizationArea getDwmColorizationArea();
|
||||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isHighContrastModeEnabled();
|
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isHighContrastModeEnabled();
|
||||||
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getPrimaryScreenDpi(const bool horizontal);
|
[[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 void removeSysMenuHook(const WId windowId);
|
||||||
FRAMELESSHELPER_CORE_API quint64 queryMouseButtonState();
|
FRAMELESSHELPER_CORE_API quint64 queryMouseButtonState();
|
||||||
FRAMELESSHELPER_CORE_API bool isValidWindow(const WId windowId, const bool checkVisible, const bool checkTopLevel);
|
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
|
#endif // Q_OS_WINDOWS
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
|
|
|
@ -562,6 +562,7 @@ void FramelessHelperWin::addWindow(FramelessParamsConst params)
|
||||||
qApp->installNativeEventFilter(g_framelessWin32HelperData()->nativeEventFilter.get());
|
qApp->installNativeEventFilter(g_framelessWin32HelperData()->nativeEventFilter.get());
|
||||||
}
|
}
|
||||||
DEBUG.noquote() << "The DPI of window" << hwnd2str(windowId) << "is" << data.dpi;
|
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).
|
// Remove the bad window styles added by Qt (it's not that "bad" though).
|
||||||
Utils::maybeFixupQtInternals(windowId);
|
Utils::maybeFixupQtInternals(windowId);
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -571,7 +572,7 @@ void FramelessHelperWin::addWindow(FramelessParamsConst params)
|
||||||
// otherwise we'll get lots of warning messages when we change the window
|
// 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
|
// geometry, it will also affect the final window geometry because QPA will
|
||||||
// always take it into account when setting window size and position.
|
// always take it into account when setting window size and position.
|
||||||
Utils::updateInternalWindowFrameMargins(params->getWindowHandle(), true);
|
Utils::updateInternalWindowFrameMargins(const_cast<QWindow *>(window), true);
|
||||||
#endif
|
#endif
|
||||||
// Tell DWM our preferred frame margin.
|
// Tell DWM our preferred frame margin.
|
||||||
Utils::updateWindowFrameMargins(windowId, false);
|
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
|
// 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.
|
// size, we of course don't want such thing from happening.
|
||||||
Utils::fixupChildWindowsDpiMessage(windowId);
|
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()) {
|
if (WindowsVersionHelper::isWin10RS1OrGreater()) {
|
||||||
// Tell DWM we may need dark theme non-client area (title bar & frame border).
|
// Tell DWM we may need dark theme non-client area (title bar & frame border).
|
||||||
FramelessHelper::Core::setApplicationOSThemeAware();
|
FramelessHelper::Core::setApplicationOSThemeAware();
|
||||||
|
@ -671,6 +677,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
||||||
}
|
}
|
||||||
const FramelessWin32HelperData &data = it.value();
|
const FramelessWin32HelperData &data = it.value();
|
||||||
FramelessWin32HelperData &muData = it.value();
|
FramelessWin32HelperData &muData = it.value();
|
||||||
|
const QWindow *window = data.params.getWindowHandle();
|
||||||
const bool frameBorderVisible = Utils::isWindowFrameBorderVisible();
|
const bool frameBorderVisible = Utils::isWindowFrameBorderVisible();
|
||||||
const WPARAM wParam = msg->wParam;
|
const WPARAM wParam = msg->wParam;
|
||||||
const LPARAM lParam = msg->lParam;
|
const LPARAM lParam = msg->lParam;
|
||||||
|
@ -1032,8 +1039,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
||||||
WARNING << Utils::getSystemErrorMessage(kScreenToClient);
|
WARNING << Utils::getSystemErrorMessage(kScreenToClient);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const QPoint qtScenePos = Utils::fromNativeLocalPosition(
|
const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint(nativeLocalPos.x, nativeLocalPos.y));
|
||||||
data.params.getWindowHandle(), QPoint(nativeLocalPos.x, nativeLocalPos.y));
|
|
||||||
const bool max = IsMaximized(hWnd);
|
const bool max = IsMaximized(hWnd);
|
||||||
const bool full = Utils::isFullScreen(windowId);
|
const bool full = Utils::isFullScreen(windowId);
|
||||||
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true);
|
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true);
|
||||||
|
@ -1255,6 +1261,18 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
#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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1331,6 +1349,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
||||||
break;
|
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) {
|
if (WindowsVersionHelper::isWin11OrGreater() && data.fallbackTitleBarWindowId) {
|
||||||
switch (uMsg) {
|
switch (uMsg) {
|
||||||
case WM_SIZE: // Sent to a window after its size has changed.
|
case WM_SIZE: // Sent to a window after its size has changed.
|
||||||
|
|
|
@ -34,8 +34,11 @@
|
||||||
#include <QtGui/qguiapplication.h>
|
#include <QtGui/qguiapplication.h>
|
||||||
#include <QtGui/qfontmetrics.h>
|
#include <QtGui/qfontmetrics.h>
|
||||||
#include <QtGui/qpalette.h>
|
#include <QtGui/qpalette.h>
|
||||||
|
#include <QtGui/qsurface.h>
|
||||||
|
#include <QtGui/qsurfaceformat.h>
|
||||||
#ifndef FRAMELESSHELPER_CORE_NO_PRIVATE
|
#ifndef FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||||
# include <QtGui/private/qhighdpiscaling_p.h>
|
# include <QtGui/private/qhighdpiscaling_p.h>
|
||||||
|
# include <QtGui/private/qwindow_p.h>
|
||||||
#endif // FRAMELESSHELPER_CORE_NO_PRIVATE
|
#endif // FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
||||||
# include <QtGui/qstylehints.h>
|
# include <QtGui/qstylehints.h>
|
||||||
|
@ -587,4 +590,42 @@ QColor Utils::getAccentColor()
|
||||||
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
|
#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
|
FRAMELESSHELPER_END_NAMESPACE
|
||||||
|
|
|
@ -776,7 +776,7 @@ QString Utils::getSystemErrorMessage(const QString &function)
|
||||||
return getSystemErrorMessageImpl(function, code);
|
return getSystemErrorMessageImpl(function, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor Utils::getDwmColorizationColor()
|
QColor Utils::getDwmColorizationColor(bool *opaque, bool *ok)
|
||||||
{
|
{
|
||||||
const auto resultFromRegistry = []() -> QColor {
|
const auto resultFromRegistry = []() -> QColor {
|
||||||
const RegistryKey registry(RegistryRootKey::CurrentUser, dwmRegistryKey());
|
const RegistryKey registry(RegistryRootKey::CurrentUser, dwmRegistryKey());
|
||||||
|
@ -790,15 +790,27 @@ QColor Utils::getDwmColorizationColor()
|
||||||
return QColor::fromRgba(qvariant_cast<DWORD>(value));
|
return QColor::fromRgba(qvariant_cast<DWORD>(value));
|
||||||
};
|
};
|
||||||
if (!API_DWM_AVAILABLE(DwmGetColorizationColor)) {
|
if (!API_DWM_AVAILABLE(DwmGetColorizationColor)) {
|
||||||
|
if (ok) {
|
||||||
|
*ok = false;
|
||||||
|
}
|
||||||
return resultFromRegistry();
|
return resultFromRegistry();
|
||||||
}
|
}
|
||||||
DWORD color = 0;
|
DWORD color = 0;
|
||||||
BOOL opaque = FALSE;
|
BOOL bOpaque = FALSE;
|
||||||
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmGetColorizationColor, &color, &opaque);
|
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmGetColorizationColor, &color, &bOpaque);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
WARNING << getSystemErrorMessageImpl(kDwmGetColorizationColor, hr);
|
WARNING << getSystemErrorMessageImpl(kDwmGetColorizationColor, hr);
|
||||||
|
if (ok) {
|
||||||
|
*ok = false;
|
||||||
|
}
|
||||||
return resultFromRegistry();
|
return resultFromRegistry();
|
||||||
}
|
}
|
||||||
|
if (opaque) {
|
||||||
|
*opaque = (bOpaque != FALSE);
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
*ok = true;
|
||||||
|
}
|
||||||
return QColor::fromRgba(color);
|
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
|
// and this will also break the normal functionalities for our windows, so we do the
|
||||||
// correction here unconditionally.
|
// correction here unconditionally.
|
||||||
static constexpr const DWORD badWindowStyle = WS_POPUP;
|
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)) {
|
if ((windowStyle & badWindowStyle) || !(windowStyle & goodWindowStyle)) {
|
||||||
SetLastError(ERROR_SUCCESS);
|
SetLastError(ERROR_SUCCESS);
|
||||||
if (SetWindowLongPtrW(hwnd, GWL_STYLE, ((windowStyle & ~badWindowStyle) | goodWindowStyle)) == 0) {
|
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) {
|
if (shouldUpdateFrame) {
|
||||||
triggerFrameChange(windowId);
|
triggerFrameChange(windowId);
|
||||||
}
|
}
|
||||||
|
@ -2574,4 +2602,59 @@ bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const boo
|
||||||
return true;
|
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
|
FRAMELESSHELPER_END_NAMESPACE
|
||||||
|
|
Loading…
Reference in New Issue