This commit is contained in:
Zhao Yuhang 2023-09-14 22:29:40 +08:00
parent ae9c4ae5c8
commit 099da347e8
9 changed files with 446 additions and 337 deletions

View File

@ -86,6 +86,46 @@
#include <FramelessHelper/Core/framelesshelpercore_global.h>
#ifndef SC_SIZE
# define SC_SIZE (0xF000)
#endif
#ifndef SC_SIZELEFT
# define SC_SIZELEFT (0xF001)
#endif
#ifndef SC_SIZERIGHT
# define SC_SIZERIGHT (0xF002)
#endif
#ifndef SC_SIZETOP
# define SC_SIZETOP (0xF003)
#endif
#ifndef SC_SIZETOPLEFT
# define SC_SIZETOPLEFT (0xF004)
#endif
#ifndef SC_SIZETOPRIGHT
# define SC_SIZETOPRIGHT (0xF005)
#endif
#ifndef SC_SIZEBOTTOM
# define SC_SIZEBOTTOM (0xF006)
#endif
#ifndef SC_SIZEBOTTOMLEFT
# define SC_SIZEBOTTOMLEFT (0xF007)
#endif
#ifndef SC_SIZEBOTTOMRIGHT
# define SC_SIZEBOTTOMRIGHT (0xF008)
#endif
#ifndef SC_DRAGMOVE
# define SC_DRAGMOVE (0xF012)
#endif
#ifndef WM_SIZEWAIT
# define WM_SIZEWAIT (0x0004)
#endif
@ -1166,3 +1206,39 @@ EXTERN_C_END
{
return !operator==(lhs, rhs);
}
[[nodiscard]] inline constexpr QPoint point2qpoint(const POINT &point)
{
return QPoint{ int(point.x), int(point.y) };
}
[[nodiscard]] inline constexpr POINT qpoint2point(const QPoint &point)
{
return POINT{ LONG(point.x()), LONG(point.y()) };
}
[[nodiscard]] inline constexpr QSize size2qsize(const SIZE &size)
{
return QSize{ int(size.cx), int(size.cy) };
}
[[nodiscard]] inline constexpr SIZE qsize2size(const QSize &size)
{
return SIZE{ LONG(size.width()), LONG(size.height()) };
}
[[nodiscard]] inline constexpr QRect rect2qrect(const RECT &rect)
{
return QRect{ QPoint{ int(rect.left), int(rect.top) }, QSize{ int(RECT_WIDTH(rect)), int(RECT_HEIGHT(rect)) } };
}
[[nodiscard]] inline constexpr RECT qrect2rect(const QRect &qrect)
{
return RECT{ LONG(qrect.left()), LONG(qrect.top()), LONG(qrect.right()), LONG(qrect.bottom()) };
}
[[nodiscard]] inline /*constexpr*/ QString hwnd2str(const HWND hwnd)
{
// NULL handle is allowed here.
return FRAMELESSHELPER_STRING_LITERAL("0x") + QString::number(reinterpret_cast<WId>(hwnd), 16).toUpper().rightJustified(8, u'0');
}

View File

@ -312,7 +312,7 @@ Q_NAMESPACE_EXPORT(FRAMELESSHELPER_CORE_API)
enum class Option : quint8
{
UseCrossPlatformQtImplementation,
//UseCrossPlatformQtImplementation,
ForceHideWindowFrameBorder,
ForceShowWindowFrameBorder,
DisableWindowsSnapLayout,

View File

@ -96,26 +96,33 @@ struct FramelessCallbacks
ForceChildrenRepaintCallback forceChildrenRepaint = nullptr;
ResetQtGrabbedControlCallback resetQtGrabbedControl = nullptr;
using PtrType = std::shared_ptr<FramelessCallbacks>;
[[nodiscard]] static PtrType create();
private:
Q_DISABLE_COPY_MOVE(FramelessCallbacks)
};
using FramelessCallbacksPtr = std::shared_ptr<FramelessCallbacks>;
#define CreateFramelessCallbacks(...) std::make_shared<FramelessCallbacks>(__VA_ARGS__)
struct FramelessData;
using FramelessDataPtr = std::shared_ptr<FramelessData>;
#define CreateFramelessData(...) std::make_shared<FramelessData>(__VA_ARGS__)
using FramelessCallbacksPtr = FramelessCallbacks::PtrType;
struct FramelessData
{
bool frameless = false;
FramelessCallbacksPtr callbacks = nullptr;
struct {
void *ptr = nullptr;
using DeleterFunctionPrototype = void(*)(void*);
DeleterFunctionPrototype deleter = nullptr;
} extraData = {};
[[nodiscard]] static FramelessDataPtr create();
using PtrType = std::shared_ptr<FramelessData>;
[[nodiscard]] static PtrType create();
~FramelessData();
private:
Q_DISABLE_COPY_MOVE(FramelessData)
};
using FramelessDataPtr = FramelessData::PtrType;
using FramelessDataHash = QHash<const QWindow *, FramelessDataPtr>;

View File

@ -62,6 +62,7 @@ public:
void doNotifyWallpaperHasChangedOrNot();
Q_NODISCARD static FramelessDataPtr getData(const QWindow *window);
static void removeData(const QWindow *window);
FramelessManager *q_ptr = nullptr;
Global::SystemTheme systemTheme = Global::SystemTheme::Unknown;

View File

@ -114,28 +114,16 @@ struct FramelessDataWin : public FramelessData
QRect restoreGeometry = {};
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
};
#define CreateFramelessDataWin(...) std::make_shared<FramelessDataWin>(__VA_ARGS__)
#define GetFramelessDataWin(Window) std::dynamic_pointer_cast<FramelessDataWin>(FramelessManagerPrivate::getData(Window))
[[nodiscard]] FramelessDataPtr FramelessData::create()
{
return CreateFramelessDataWin();
return std::make_shared<FramelessDataWin>();
}
static std::unique_ptr<FramelessHelperWin> g_framelessHelperWin = nullptr;
[[nodiscard]] extern QPoint point2qpoint(const POINT &point);
[[nodiscard]] extern POINT qpoint2point(const QPoint &point);
[[nodiscard]] extern QSize size2qsize(const SIZE &size);
[[nodiscard]] extern SIZE qsize2size(const QSize &size);
[[nodiscard]] extern QRect rect2qrect(const RECT &rect);
[[nodiscard]] extern RECT qrect2rect(const QRect &qrect);
[[nodiscard]] extern QString hwnd2str(const HWND hwnd);
[[nodiscard]] extern std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd);
[[nodiscard]] static inline QByteArray qtNativeEventType()
@ -218,11 +206,7 @@ void FramelessHelperWin::addWindow(const QWindow *window)
}
data->frameless = true;
data->dpi = Dpi{ Utils::getWindowDpi(window, true), Utils::getWindowDpi(window, false) };
if (!g_framelessHelperWin) {
g_framelessHelperWin = std::make_unique<FramelessHelperWin>();
qApp->installNativeEventFilter(g_framelessHelperWin.get());
}
DEBUG.noquote() << "The DPI of window" << hwnd2str(windowId) << "is" << data->dpi;
DEBUG.noquote() << "The DPI of window" << hwnd2str(qWindowId<HWND>(window)) << "is" << data->dpi;
// Remove the bad window styles added by Qt (it's not that "bad" though).
std::ignore = Utils::maybeFixupQtInternals(window);
#if 0
@ -267,19 +251,15 @@ void FramelessHelperWin::addWindow(const QWindow *window)
}
}
}
if (!g_framelessHelperWin) {
g_framelessHelperWin = std::make_unique<FramelessHelperWin>();
qApp->installNativeEventFilter(g_framelessHelperWin.get());
}
}
void FramelessHelperWin::removeWindow(const QWindow *window)
{
Q_ASSERT(window);
if (!window) {
return;
}
const auto data = GetFramelessDataWin(window);
if (!data || !data->frameless) {
return;
}
data->frameless = false;
Q_UNUSED(window);
}
bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result)
@ -301,16 +281,23 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// Anyway, we should skip the entire processing in this case.
return false;
}
const QWindow *window = Utils::findWindow(reinterpret_cast<WId>(hWnd));
if (!window) {
return false;
}
// Let's be extra safe.
if (!Utils::isValidWindow(window, false, true)) {
return false;
}
const auto data = GetFramelessDataWin(window);
Q_ASSERT(data);
if (!data || !data->frameless) {
return false;
}
// Let's be extra safe.
if (!Utils::isValidWindow(window, false, true)) {
return false;
}
const UINT uMsg = msg->message;
// We should skip these messages otherwise we will get crashes.
@ -332,7 +319,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const LPARAM lParam = msg->lParam;
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
const auto updateRestoreGeometry = [window](const bool ignoreWindowState) -> void {
const auto updateRestoreGeometry = [window, &data](const bool ignoreWindowState) -> void {
if (!ignoreWindowState && !Utils::isWindowNoState(window)) {
return;
}
@ -341,10 +328,10 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
WARNING << "The calculated restore geometry is invalid.";
return;
}
if (Utils::isValidGeometry(data.restoreGeometry) && (data.restoreGeometry == rect)) {
if (Utils::isValidGeometry(data->restoreGeometry) && (data->restoreGeometry == rect)) {
return;
}
muData.restoreGeometry = rect;
data->restoreGeometry = rect;
};
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
@ -447,13 +434,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// So we filter out these superfluous mouse leave events here to avoid this issue.
const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint{ msg->pt.x, msg->pt.y });
SystemButtonType dummy = SystemButtonType::Unknown;
if (data.params.isInsideSystemButtons(qtScenePos, &dummy)) {
muData.mouseLeaveBlocked = true;
if (data->callbacks->isInsideSystemButtons(qtScenePos, &dummy)) {
data->mouseLeaveBlocked = true;
*result = FALSE;
return true;
}
}
muData.mouseLeaveBlocked = false;
data->mouseLeaveBlocked = false;
}
switch (uMsg) {
@ -465,7 +452,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// If we are using the PMv2 DPI awareness mode, the non-client area
// of the window will be scaled by the OS automatically, so there will
// be no need to do this in that case.
Utils::enableNonClientAreaDpiScalingForWindow(windowId);
Utils::enableNonClientAreaDpiScalingForWindow(window);
} break;
#endif
case WM_NCCALCSIZE: {
@ -581,7 +568,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
clientRect->top = originalTop;
}
const bool max = IsMaximized(hWnd);
const bool full = Utils::isFullScreen(windowId);
const bool full = Utils::isFullScreen(window);
// We don't need this correction when we're fullscreen. We will
// have the WS_POPUP size, so we don't have to worry about
// borders, and the default frame will be fine.
@ -592,11 +579,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// then the window is clipped to the monitor so that the resize handle
// do not appear because you don't need them (because you can't resize
// a window when it's maximized unless you restore it).
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true);
const int frameSizeY = Utils::getResizeBorderThickness(window, false, true);
clientRect->top += frameSizeY;
if (!frameBorderVisible) {
clientRect->bottom -= frameSizeY;
const int frameSizeX = Utils::getResizeBorderThickness(windowId, true, true);
const int frameSizeX = Utils::getResizeBorderThickness(window, true, true);
clientRect->left += frameSizeX;
clientRect->right -= frameSizeX;
}
@ -791,8 +778,8 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// color, our homemade top border can almost have exactly the same
// appearance with the system's one.
const auto hitTestRecorder = qScopeGuard([&muData, &result](){
muData.lastHitTestResult = getHittedWindowPart(*result);
const auto hitTestRecorder = qScopeGuard([&data, &result](){
data->lastHitTestResult = getHittedWindowPart(*result);
});
const auto nativeGlobalPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
@ -812,7 +799,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint(nativeLocalPos.x, nativeLocalPos.y));
SystemButtonType sysButtonType = SystemButtonType::Unknown;
if (data.params.isInsideSystemButtons(qtScenePos, &sysButtonType)) {
if (data->callbacks->isInsideSystemButtons(qtScenePos, &sysButtonType)) {
// Even if the mouse is inside the chrome button area now, we should still allow the user
// to be able to resize the window with the top or right window border, this is also the
// normal behavior of a native Win32 window.
@ -858,13 +845,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// are we hitting.
const bool max = IsMaximized(hWnd);
const bool full = Utils::isFullScreen(windowId);
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true);
const bool full = Utils::isFullScreen(window);
const int frameSizeY = Utils::getResizeBorderThickness(window, false, true);
const bool isTop = (nativeLocalPos.y < frameSizeY);
const bool isTitleBar = data.params.isInsideTitleBarDraggableArea(qtScenePos);
const bool isFixedSize = data.params.isWindowFixedSize();
const bool dontOverrideCursor = data.params.getProperty(kDontOverrideCursorVar, false).toBool();
const bool dontToggleMaximize = data.params.getProperty(kDontToggleMaximizeVar, false).toBool();
const bool isTitleBar = data->callbacks->isInsideTitleBarDraggableArea(qtScenePos);
const bool isFixedSize = data->callbacks->isWindowFixedSize();
const bool dontOverrideCursor = data->callbacks->getProperty(kDontOverrideCursorVar, false).toBool();
const bool dontToggleMaximize = data->callbacks->getProperty(kDontToggleMaximizeVar, false).toBool();
if (dontToggleMaximize) {
static bool once = false;
@ -922,7 +909,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const bool isBottom = (nativeLocalPos.y >= (clientHeight - frameSizeY));
// Make the border a little wider to let the user easy to resize on corners.
const auto scaleFactor = ((isTop || isBottom) ? qreal(2) : qreal(1));
const int frameSizeX = Utils::getResizeBorderThickness(windowId, true, true);
const int frameSizeX = Utils::getResizeBorderThickness(window, true, true);
const int scaledFrameSizeX = std::round(qreal(frameSizeX) * scaleFactor);
const bool isLeft = (nativeLocalPos.x < scaledFrameSizeX);
const bool isRight = (nativeLocalPos.x >= (clientWidth - scaledFrameSizeX));
@ -975,8 +962,8 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return true;
}
case WM_MOUSEMOVE:
if ((data.lastHitTestResult != WindowPart::ChromeButton) && data.mouseLeaveBlocked) {
muData.mouseLeaveBlocked = false;
if ((data->lastHitTestResult != WindowPart::ChromeButton) && data->mouseLeaveBlocked) {
data->mouseLeaveBlocked = false;
std::ignore = requestForMouseLeaveMessage(hWnd, false);
}
break;
@ -999,11 +986,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
case WM_NCPOINTERUP:
#endif
case WM_NCMOUSEHOVER: {
const WindowPart currentWindowPart = data.lastHitTestResult;
const WindowPart currentWindowPart = data->lastHitTestResult;
if (uMsg == WM_NCMOUSEMOVE) {
if (currentWindowPart != WindowPart::ChromeButton) {
std::ignore = data.params.resetQtGrabbedControl();
if (muData.mouseLeaveBlocked) {
std::ignore = data->callbacks->resetQtGrabbedControl();
if (data->mouseLeaveBlocked) {
emulateClientAreaMessage(WM_NCMOUSELEAVE);
}
}
@ -1014,12 +1001,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// If the mouse is entering the client area, there must be a WM_NCHITTEST setting
// it to `Client` before the WM_NCMOUSELEAVE comes;
// If the mouse is leaving the window, current window part remains as `Outside`.
muData.lastHitTestResult = WindowPart::Outside;
data->lastHitTestResult = WindowPart::Outside;
}
if (currentWindowPart == WindowPart::ChromeButton) {
emulateClientAreaMessage();
if (uMsg == WM_NCMOUSEMOVE) {
// ### FIXME: Calling DefWindowProc() here is really dangerous, investigate how
// to avoid doing this.
*result = ::DefWindowProcW(hWnd, WM_NCMOUSEMOVE, wParam, lParam);
} else {
*result = (((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK)) ? TRUE : FALSE);
@ -1028,18 +1017,18 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}
} break;
case WM_NCMOUSELEAVE: {
const WindowPart currentWindowPart = data.lastHitTestResult;
const WindowPart currentWindowPart = data->lastHitTestResult;
if (currentWindowPart == WindowPart::ChromeButton) {
// If we press on the chrome button and move mouse, Windows will take the pressing area
// as HTCLIENT which maybe because of our former retransmission of WM_NCLBUTTONDOWN, as
// a result, a WM_NCMOUSELEAVE will come immediately and a lot of WM_MOUSEMOVE will come
// if we move the mouse, we should track the mouse in advance.
if (muData.mouseLeaveBlocked) {
muData.mouseLeaveBlocked = false;
if (data->mouseLeaveBlocked) {
data->mouseLeaveBlocked = false;
std::ignore = requestForMouseLeaveMessage(hWnd, false);
}
} else {
if (data.mouseLeaveBlocked) {
if (data->mouseLeaveBlocked) {
// The mouse is moving from the chrome button to other non-client area, we should
// emulate a WM_MOUSELEAVE message to reset the button state.
emulateClientAreaMessage(WM_NCMOUSELEAVE);
@ -1051,7 +1040,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// the mouse leaves window from client area and enters window from non-client area,
// but it has no bad effect.
std::ignore = data.params.resetQtGrabbedControl();
std::ignore = data->callbacks->resetQtGrabbedControl();
}
}
} break;
@ -1065,7 +1054,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// of the application a lot.
const auto windowPos = reinterpret_cast<LPWINDOWPOS>(lParam);
const QRect suggestedFrameGeometry{ windowPos->x, windowPos->y, windowPos->cx, windowPos->cy };
const QMargins frameMargins = (Utils::getWindowSystemFrameMargins(windowId) + Utils::getWindowCustomFrameMargins(window));
const QMargins frameMargins = (Utils::getWindowSystemFrameMargins(window) + Utils::getWindowCustomFrameMargins(window));
const QRect suggestedGeometry = (suggestedFrameGeometry - frameMargins);
if (Utils::toNativePixels(window, window->size()) != suggestedGeometry.size()) {
windowPos->flags |= SWP_NOCOPYBITS;
@ -1107,7 +1096,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}
#endif // (QT_VERSION <= QT_VERSION_CHECK(6, 4, 2))
case WM_DPICHANGED: {
const Dpi oldDpi = data.dpi;
const Dpi oldDpi = data->dpi;
const Dpi newDpi = {UINT(LOWORD(wParam)), UINT(HIWORD(wParam))};
if (Q_UNLIKELY(newDpi == oldDpi)) {
WARNING << "Wrong WM_DPICHANGED received: same DPI.";
@ -1115,18 +1104,18 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}
DEBUG.noquote() << "New DPI for window" << hwnd2str(hWnd)
<< "is" << newDpi << "(was" << oldDpi << ").";
muData.dpi = newDpi;
data->dpi = newDpi;
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
if (Utils::isValidGeometry(data.restoreGeometry)) {
if (Utils::isValidGeometry(data->restoreGeometry)) {
// Update the window size only. The position should not be changed.
muData.restoreGeometry.setSize(Utils::rescaleSize(data.restoreGeometry.size(), oldDpi.x, newDpi.x));
muData.restoreGeometry.setSize(Utils::rescaleSize(data->restoreGeometry.size(), oldDpi.x, newDpi.x));
}
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
data.params.forceChildrenRepaint(500);
data->callbacks->forceChildrenRepaint(500);
} break;
case WM_DWMCOMPOSITIONCHANGED:
// Re-apply the custom window frame if recovered from the basic theme.
std::ignore = Utils::updateWindowFrameMargins(windowId, false);
std::ignore = Utils::updateWindowFrameMargins(window, false);
break;
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
case WM_ENTERSIZEMOVE: // Sent to a window when the user drags the title bar or the resize border.
@ -1137,7 +1126,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
if (wParam != SIZE_MAXIMIZED) {
break;
}
if (!Utils::isValidGeometry(data.restoreGeometry)) {
if (!Utils::isValidGeometry(data->restoreGeometry)) {
updateRestoreGeometry(true);
break;
}
@ -1149,11 +1138,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
break;
}
// The restore geometry is correct, no need to bother.
if (rect2qrect(wp.rcNormalPosition) == data.restoreGeometry) {
if (rect2qrect(wp.rcNormalPosition) == data->restoreGeometry) {
break;
}
// OK, the restore geometry is wrong, let's correct it then :)
wp.rcNormalPosition = qrect2rect(data.restoreGeometry);
wp.rcNormalPosition = qrect2rect(data->restoreGeometry);
if (::SetWindowPlacement(hWnd, &wp) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kSetWindowPlacement);
}
@ -1165,7 +1154,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// 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)) {
if (Utils::isFullScreen(window)) {
*result = FALSE;
return true;
}
@ -1233,14 +1222,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
WARNING << Utils::getSystemErrorMessage(kSetWindowLongPtrW);
break;
}
std::ignore = Utils::triggerFrameChange(windowId);
std::ignore = Utils::triggerFrameChange(window);
const LRESULT originalResult = ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
::SetLastError(ERROR_SUCCESS);
if (::SetWindowLongPtrW(hWnd, GWL_STYLE, static_cast<LONG_PTR>(oldStyle)) == 0) {
WARNING << Utils::getSystemErrorMessage(kSetWindowLongPtrW);
break;
}
std::ignore = Utils::triggerFrameChange(windowId);
std::ignore = Utils::triggerFrameChange(window);
*result = originalResult;
return true;
}
@ -1251,7 +1240,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
if ((uMsg == WM_DWMCOMPOSITIONCHANGED) || (uMsg == WM_DWMCOLORIZATIONCOLORCHANGED)) {
if (Utils::isWindowAccelerated(window) && Utils::isWindowTransparent(window)) {
std::ignore = Utils::updateFramebufferTransparency(windowId);
std::ignore = Utils::updateFramebufferTransparency(window);
}
}
@ -1266,14 +1255,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
if (WindowsVersionHelper::isWin10RS5OrGreater()) {
const bool dark = (FramelessManager::instance()->systemTheme() == SystemTheme::Dark);
const auto isWidget = [&data]() -> bool {
const auto widget = data.params.getWidgetHandle();
const auto widget = data->callbacks->getWidgetHandle();
return (widget && widget->isWidgetType());
}();
if (!isWidget) {
// Causes some QtWidgets paint incorrectly, so only apply to Qt Quick applications.
std::ignore = Utils::updateGlobalWin32ControlsTheme(windowId, dark);
std::ignore = Utils::updateGlobalWin32ControlsTheme(window, dark);
}
std::ignore = Utils::refreshWin32ThemeResources(windowId, dark);
std::ignore = Utils::refreshWin32ThemeResources(window, dark);
}
}
}

View File

@ -114,6 +114,23 @@ using namespace Global;
static_assert(std::size(WindowsVersions) == (static_cast<int>(WindowsVersion::Latest) + 1));
#endif
FramelessCallbacksPtr FramelessCallbacks::create()
{
return std::make_shared<FramelessCallbacks>();
}
FramelessData::~FramelessData()
{
if (extraData.ptr) {
Q_ASSERT(extraData.deleter);
if (extraData.deleter) {
extraData.deleter(extraData.ptr);
extraData.deleter = nullptr;
}
extraData.ptr = nullptr;
}
}
void FramelessHelperCoreInitialize()
{
static bool inited = false;

View File

@ -81,18 +81,6 @@ static constexpr const int kEventDelayInterval = 1000;
}
#endif
[[nodiscard]] static inline bool usePureQtImplementation()
{
static const auto result = []() -> bool {
#ifdef Q_OS_WINDOWS
return FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation);
#else
return true;
#endif
}();
return result;
}
FramelessManagerPrivate::FramelessManagerPrivate(FramelessManager *q) : QObject(q)
{
Q_ASSERT(q);
@ -240,6 +228,19 @@ FramelessDataPtr FramelessManagerPrivate::getData(const QWindow *window)
return it.value();
}
void FramelessManagerPrivate::removeData(const QWindow *window)
{
Q_ASSERT(window);
if (!window) {
return;
}
const auto it = g_internalData()->constFind(window);
if (it == g_internalData()->constEnd()) {
return;
}
g_internalData()->erase(it);
}
bool FramelessManagerPrivate::isThemeOverrided() const
{
return (overrideTheme.value_or(SystemTheme::Unknown) != SystemTheme::Unknown);
@ -316,7 +317,7 @@ bool FramelessManager::isFramelessWindow(const QWindow *window) const
if (!window) {
return false;
}
return FramelessManagerPrivate::getData(window)->isFrameless;
return FramelessManagerPrivate::getData(window)->frameless;
}
SystemTheme FramelessManager::systemTheme() const
@ -369,19 +370,20 @@ bool FramelessManager::addWindow(const QWindow *window)
return false;
}
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
if (data->isFrameless) {
Q_ASSERT(data);
if (!data || data->frameless) {
return false;
}
data->isFrameless = true;
const bool pureQt = usePureQtImplementation();
if (pureQt) {
FramelessHelperQt::addWindow(window);
}
#ifdef Q_OS_WINDOWS
if (!pureQt) {
FramelessHelperWin::addWindow(window);
}
#if FRAMELESSHELPER_CONFIG(native_impl)
# ifdef Q_OS_WINDOWS
std::ignore = Utils::installWindowProcHook(window);
FramelessHelperWin::addWindow(window);
# elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
# elif defined(Q_OS_MACOS)
# else
# endif
#else
FramelessHelperQt::addWindow(window);
#endif
connect(window, &QWindow::destroyed, FramelessManager::instance(), [this, window](){ std::ignore = removeWindow(window); });
return true;
@ -394,19 +396,20 @@ bool FramelessManager::removeWindow(const QWindow *window)
return false;
}
const auto it = g_internalData()->constFind(window);
if ((it == g_internalData()->constEnd()) || !it.value()->isFrameless) {
if (it == g_internalData()->constEnd()) {
return false;
}
const bool pureQt = usePureQtImplementation();
if (pureQt) {
FramelessHelperQt::removeWindow(window);
}
#ifdef Q_OS_WINDOWS
if (!pureQt) {
#if FRAMELESSHELPER_CONFIG(native_impl)
# ifdef Q_OS_WINDOWS
FramelessHelperWin::removeWindow(window);
}
std::ignore = Utils::uninstallWindowProcHook(window);
std::ignore = Utils::removeMicaWindow(window);
# elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
# elif defined(Q_OS_MACOS)
# else
# endif
#else
FramelessHelperQt::removeWindow(window);
#endif
g_internalData()->erase(it);
return true;

View File

@ -50,11 +50,11 @@ _GetWindowCompositionAttribute(const HWND hWnd, PWINDOWCOMPOSITIONATTRIBDATA pvD
Q_ASSERT(hWnd);
Q_ASSERT(pvData);
if (!hWnd || !pvData) {
SetLastError(ERROR_INVALID_PARAMETER);
::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!API_USER_AVAILABLE(GetWindowCompositionAttribute)) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return API_CALL_FUNCTION4(user32, GetWindowCompositionAttribute, hWnd, pvData);
@ -66,11 +66,11 @@ _SetWindowCompositionAttribute(const HWND hWnd, PWINDOWCOMPOSITIONATTRIBDATA pvD
Q_ASSERT(hWnd);
Q_ASSERT(pvData);
if (!hWnd || !pvData) {
SetLastError(ERROR_INVALID_PARAMETER);
::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!API_USER_AVAILABLE(SetWindowCompositionAttribute)) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return API_CALL_FUNCTION4(user32, SetWindowCompositionAttribute, hWnd, pvData);
@ -111,14 +111,14 @@ _ShouldAppsUseDarkMode(VOID)
{
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
static const auto pShouldAppsUseDarkMode
= reinterpret_cast<ShouldAppsUseDarkModePtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(132)));
if (!pShouldAppsUseDarkMode) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pShouldAppsUseDarkMode();
@ -129,19 +129,19 @@ _AllowDarkModeForWindow(const HWND hWnd, const BOOL bAllow)
{
Q_ASSERT(hWnd);
if (!hWnd) {
SetLastError(ERROR_INVALID_PARAMETER);
::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
static const auto pAllowDarkModeForWindow
= reinterpret_cast<AllowDarkModeForWindowPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(133)));
if (!pAllowDarkModeForWindow) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pAllowDarkModeForWindow(hWnd, bAllow);
@ -152,14 +152,14 @@ _AllowDarkModeForApp(const BOOL bAllow)
{
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
static const auto pAllowDarkModeForApp
= reinterpret_cast<AllowDarkModeForAppPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(135)));
if (!pAllowDarkModeForApp) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pAllowDarkModeForApp(bAllow);
@ -170,14 +170,14 @@ _FlushMenuThemes(VOID)
{
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return;
}
static const auto pFlushMenuThemes
= reinterpret_cast<FlushMenuThemesPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(136)));
if (!pFlushMenuThemes) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return;
}
pFlushMenuThemes();
@ -188,14 +188,14 @@ _RefreshImmersiveColorPolicyState(VOID)
{
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return;
}
static const auto pRefreshImmersiveColorPolicyState
= reinterpret_cast<RefreshImmersiveColorPolicyStatePtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(104)));
if (!pRefreshImmersiveColorPolicyState) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return;
}
pRefreshImmersiveColorPolicyState();
@ -206,19 +206,19 @@ _IsDarkModeAllowedForWindow(const HWND hWnd)
{
Q_ASSERT(hWnd);
if (!hWnd) {
SetLastError(ERROR_INVALID_PARAMETER);
::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
static const auto pIsDarkModeAllowedForWindow
= reinterpret_cast<IsDarkModeAllowedForWindowPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(137)));
if (!pIsDarkModeAllowedForWindow) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pIsDarkModeAllowedForWindow(hWnd);
@ -229,14 +229,14 @@ _GetIsImmersiveColorUsingHighContrast(const IMMERSIVE_HC_CACHE_MODE mode)
{
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
static const auto pGetIsImmersiveColorUsingHighContrast
= reinterpret_cast<GetIsImmersiveColorUsingHighContrastPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(106)));
if (!pGetIsImmersiveColorUsingHighContrast) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pGetIsImmersiveColorUsingHighContrast(mode);
@ -248,19 +248,19 @@ _OpenNcThemeData(const HWND hWnd, LPCWSTR pszClassList)
Q_ASSERT(hWnd);
Q_ASSERT(pszClassList);
if (!hWnd || !pszClassList) {
SetLastError(ERROR_INVALID_PARAMETER);
::SetLastError(ERROR_INVALID_PARAMETER);
return nullptr;
}
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return nullptr;
}
static const auto pOpenNcThemeData
= reinterpret_cast<OpenNcThemeDataPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(49)));
if (!pOpenNcThemeData) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return nullptr;
}
return pOpenNcThemeData(hWnd, pszClassList);
@ -271,14 +271,14 @@ _ShouldSystemUseDarkMode(VOID)
{
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
static const auto pShouldSystemUseDarkMode
= reinterpret_cast<ShouldSystemUseDarkModePtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(138)));
if (!pShouldSystemUseDarkMode) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pShouldSystemUseDarkMode();
@ -289,14 +289,14 @@ _SetPreferredAppMode(const PREFERRED_APP_MODE mode)
{
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return PAM_MAX;
}
static const auto pSetPreferredAppMode
= reinterpret_cast<SetPreferredAppModePtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(135)));
if (!pSetPreferredAppMode) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return PAM_MAX;
}
return pSetPreferredAppMode(mode);
@ -307,14 +307,14 @@ _IsDarkModeAllowedForApp(VOID)
{
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
static const auto pIsDarkModeAllowedForApp
= reinterpret_cast<IsDarkModeAllowedForAppPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(139)));
if (!pIsDarkModeAllowedForApp) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pIsDarkModeAllowedForApp();
@ -325,12 +325,12 @@ _EnableChildWindowDpiMessage2(const HWND hWnd, const BOOL fEnable)
{
Q_ASSERT(hWnd);
if (!hWnd) {
SetLastError(ERROR_INVALID_PARAMETER);
::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
using EnableChildWindowDpiMessagePtr = decltype(&::_EnableChildWindowDpiMessage);
@ -355,7 +355,7 @@ _EnableChildWindowDpiMessage2(const HWND hWnd, const BOOL fEnable)
return nullptr;
}();
if (!pEnableChildWindowDpiMessage) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pEnableChildWindowDpiMessage(hWnd, fEnable);
@ -366,7 +366,7 @@ _EnablePerMonitorDialogScaling2(VOID)
{
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
using EnablePerMonitorDialogScalingPtr = decltype(&::_EnablePerMonitorDialogScaling);
@ -385,7 +385,7 @@ _EnablePerMonitorDialogScaling2(VOID)
return nullptr;
}();
if (!pEnablePerMonitorDialogScaling) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pEnablePerMonitorDialogScaling();
@ -396,12 +396,12 @@ _GetDpiForWindow2(const HWND hWnd)
{
Q_ASSERT(hWnd);
if (!hWnd) {
SetLastError(ERROR_INVALID_PARAMETER);
::SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
using GetDpiForWindowPtr = decltype(&::_GetDpiForWindow);
@ -424,7 +424,7 @@ _GetDpiForWindow2(const HWND hWnd)
return nullptr;
}();
if (!pGetDpiForWindow) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
return pGetDpiForWindow(hWnd);
@ -436,12 +436,12 @@ _GetSystemMetricsForDpi2(const int nIndex, const UINT dpi)
Q_ASSERT(nIndex >= 0);
Q_ASSERT(dpi != 0);
if ((nIndex < 0) || (dpi == 0)) {
SetLastError(ERROR_INVALID_PARAMETER);
::SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
using GetSystemMetricsForDpiPtr = decltype(&::_GetSystemMetricsForDpi);
@ -460,7 +460,7 @@ _GetSystemMetricsForDpi2(const int nIndex, const UINT dpi)
return nullptr;
}();
if (!pGetSystemMetricsForDpi) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
return pGetSystemMetricsForDpi(nIndex, dpi);
@ -473,12 +473,12 @@ _AdjustWindowRectExForDpi2(LPRECT lpRect, const DWORD dwStyle,
Q_ASSERT(lpRect);
Q_ASSERT(dpi != 0);
if (!lpRect || (dpi == 0)) {
SetLastError(ERROR_INVALID_PARAMETER);
::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
using AdjustWindowRectExForDpiPtr = decltype(&::_AdjustWindowRectExForDpi);
@ -496,7 +496,7 @@ _AdjustWindowRectExForDpi2(LPRECT lpRect, const DWORD dwStyle,
return nullptr;
}();
if (!pAdjustWindowRectExForDpi) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pAdjustWindowRectExForDpi(lpRect, dwStyle, bMenu, dwExStyle, dpi);

View File

@ -28,6 +28,7 @@
#include "framelesshelper_windows.h"
#include "framelessmanager.h"
#include "framelessmanager_p.h"
#include "framelessconfig_p.h"
#include "sysapiloader_p.h"
#include "registrykey_p.h"
@ -193,12 +194,20 @@ FRAMELESSHELPER_STRING_CONSTANT(ScreenToClient)
FRAMELESSHELPER_STRING_CONSTANT(DwmFlush)
FRAMELESSHELPER_STRING_CONSTANT(GetCursorPos)
struct Win32UtilsInternal
struct FramelessDataExtra
{
WNDPROC qtWindowProc = nullptr;
bool windowProcHooked = false;
bool mica = false;
};
Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData)
static inline void FramelessDataExtraDeleter(void *data)
{
Q_ASSERT(data);
if (data) {
delete static_cast<FramelessDataExtra *>(data);
}
}
struct Win32Message
{
@ -576,42 +585,6 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
};
#undef DEFINE_WIN32_MESSAGE
[[nodiscard]] QPoint point2qpoint(const POINT &point)
{
return QPoint{ int(point.x), int(point.y) };
}
[[nodiscard]] POINT qpoint2point(const QPoint &point)
{
return POINT{ LONG(point.x()), LONG(point.y()) };
}
[[nodiscard]] QSize size2qsize(const SIZE &size)
{
return QSize{ int(size.cx), int(size.cy) };
}
[[nodiscard]] SIZE qsize2size(const QSize &size)
{
return SIZE{ LONG(size.width()), LONG(size.height()) };
}
[[nodiscard]] QRect rect2qrect(const RECT &rect)
{
return QRect{ QPoint{ int(rect.left), int(rect.top) }, QSize{ int(RECT_WIDTH(rect)), int(RECT_HEIGHT(rect)) } };
}
[[nodiscard]] RECT qrect2rect(const QRect &qrect)
{
return RECT{ LONG(qrect.left()), LONG(qrect.top()), LONG(qrect.right()), LONG(qrect.bottom()) };
}
[[nodiscard]] QString hwnd2str(const HWND hwnd)
{
// NULL handle is allowed here.
return FRAMELESSHELPER_STRING_LITERAL("0x") + QString::number(reinterpret_cast<WId>(hwnd), 16).toUpper().rightJustified(8, u'0');
}
[[nodiscard]] std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd)
{
Q_ASSERT(hwnd);
@ -814,29 +787,29 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
return std::round(qreal(::GetSystemMetrics(index)) / dpr);
}
[[maybe_unused]] [[nodiscard]] static inline
[[maybe_unused]] [[nodiscard]] static inline constexpr
DWORD qtEdgesToWin32Orientation(const Qt::Edges edges)
{
if (edges == Qt::Edges{}) {
return 0;
} else if (edges == (Qt::LeftEdge)) {
return 0xF001; // SC_SIZELEFT
return SC_SIZELEFT;
} else if (edges == (Qt::RightEdge)) {
return 0xF002; // SC_SIZERIGHT
return SC_SIZERIGHT;
} else if (edges == (Qt::TopEdge)) {
return 0xF003; // SC_SIZETOP
return SC_SIZETOP;
} else if (edges == (Qt::TopEdge | Qt::LeftEdge)) {
return 0xF004; // SC_SIZETOPLEFT
return SC_SIZETOPLEFT;
} else if (edges == (Qt::TopEdge | Qt::RightEdge)) {
return 0xF005; // SC_SIZETOPRIGHT
return SC_SIZETOPRIGHT;
} else if (edges == (Qt::BottomEdge)) {
return 0xF006; // SC_SIZEBOTTOM
return SC_SIZEBOTTOM;
} else if (edges == (Qt::BottomEdge | Qt::LeftEdge)) {
return 0xF007; // SC_SIZEBOTTOMLEFT
return SC_SIZEBOTTOMLEFT;
} else if (edges == (Qt::BottomEdge | Qt::RightEdge)) {
return 0xF008; // SC_SIZEBOTTOMRIGHT
return SC_SIZEBOTTOMRIGHT;
} else {
return 0xF000; // SC_SIZE
return SC_SIZE;
}
}
@ -854,7 +827,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
return result;
}
[[nodiscard]] static inline bool isNonClientMessage(const UINT message)
[[nodiscard]] static inline constexpr bool isNonClientMessage(const UINT message)
{
if (((message >= WM_NCCREATE) && (message <= WM_NCACTIVATE))
|| ((message >= WM_NCMOUSEMOVE) && (message <= WM_NCMBUTTONDBLCLK))
@ -867,7 +840,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
}
}
[[nodiscard]] static inline bool isMouseMessage(const UINT message, bool *isNonClient = nullptr)
[[nodiscard]] static inline constexpr bool isMouseMessage(const UINT message, bool *isNonClient = nullptr)
{
if (((message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST))
|| ((message == WM_MOUSEHOVER) || (message == WM_MOUSELEAVE))) {
@ -887,18 +860,12 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
}
}
[[nodiscard]] static inline bool usePureQtImplementation()
{
static const bool result = FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation);
return result;
}
[[nodiscard]] static inline LRESULT CALLBACK FramelessHelperHookWindowProc
(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam)
{
Q_ASSERT(hWnd);
if (!hWnd) {
return 0;
return FALSE;
}
#if FRAMELESSHELPER_CONFIG(debug_output)
if (isWin32MessageDebuggingEnabled()) {
@ -913,14 +880,20 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
}
#endif
const QWindow *window = Utils::findWindow(reinterpret_cast<WId>(hWnd));
Q_ASSERT(window);
if (!window || !FramelessManager::instance()->isFramelessWindow(window)) {
return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
const FramelessDataPtr data = FramelessHelperExtractData(window);
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
Q_ASSERT(data);
if (!data) {
return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
const auto extraData = static_cast<FramelessDataExtra *>(data->extraData.ptr);
Q_ASSERT(extraData);
if (!extraData) {
return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
// https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowscontext.cpp#L1025
// We can see from the source code that Qt will filter out some messages first and then send the unfiltered
// messages to the event dispatcher. To activate the Snap Layout feature on Windows 11, we must process
@ -939,7 +912,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
// (and correct client area size, especially when the window is maximized/fullscreen). So we still go through
// the normal code path of the original qWindowsWndProc() function, but only for this specific message. It should
// be OK because Qt won't prevent us from handling WM_NCCALCSIZE.
if (!usePureQtImplementation() && (uMsg != WM_NCCALCSIZE)) {
if ((uMsg != WM_NCCALCSIZE)) {
MSG message;
SecureZeroMemory(&message, sizeof(message));
message.hwnd = hWnd;
@ -1008,7 +981,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
case WM_RBUTTONUP: {
const QPoint nativeLocalPos = getNativePosFromMouse();
const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, nativeLocalPos);
if (data->callbacks.isInsideTitleBarDraggableArea(qtScenePos)) {
if (data->callbacks->isInsideTitleBarDraggableArea(qtScenePos)) {
POINT pos = {nativeLocalPos.x(), nativeLocalPos.y()};
if (::ClientToScreen(hWnd, &pos) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kClientToScreen);
@ -1051,13 +1024,13 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
// behavior is not what we would want to see because it doesn't know our
// window doesn't have any window frame now, so return early here to avoid
// entering Qt's own handling logic.
return 0; // Return 0 means we have handled this event.
return FALSE; // Return 0 means we have handled this event.
}
Q_ASSERT(g_win32UtilsData()->qtWindowProc);
if (g_win32UtilsData()->qtWindowProc) {
Q_ASSERT(extraData->qtWindowProc);
if (extraData->qtWindowProc) {
// Hand over to Qt's original window proc function for events we are not
// interested in.
return ::CallWindowProcW(g_win32UtilsData()->qtWindowProc, hWnd, uMsg, wParam, lParam);
return ::CallWindowProcW(extraData->qtWindowProc, hWnd, uMsg, wParam, lParam);
} else {
return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
@ -1123,20 +1096,28 @@ bool Utils::updateWindowFrameMargins(const QWindow *window, const bool reset)
if (!API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea)) {
return false;
}
// We can't extend the window frame when DWM composition is disabled.
// We can't extend the window frame when DWM composition is disabled anyway.
// No need to try further in this case.
if (!isDwmCompositionEnabled()) {
return false;
}
const FramelessDataPtr data = FramelessHelperExtractData(window);
const bool micaEnabled = (data && data->micaEnabled);
const auto margins = [micaEnabled, reset]() -> MARGINS {
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
Q_ASSERT(data);
if (!data) {
return false;
}
const auto extraData = static_cast<FramelessDataExtra *>(data->extraData.ptr);
Q_ASSERT(extraData);
if (!extraData) {
return false;
}
const auto margins = [extraData, reset]() -> MARGINS {
// To make Mica/Mica Alt work for normal Win32 windows, we have to
// let the window frame extend to the whole window (or disable the
// redirection surface, but this will break GDI's rendering, so we
// can't do this, unfortunately), so we can't change the window frame
// margins in this case, otherwise Mica/Mica Alt will be broken.
if (micaEnabled) {
if (extraData->mica) {
return {-1, -1, -1, -1};
}
if (reset || isWindowFrameBorderVisible()) {
@ -1282,7 +1263,7 @@ bool Utils::showSystemMenu(const QWindow *window, const QPoint &pos, const bool
if (!FramelessManager::instance()->isFramelessWindow(window)) {
return false;
}
const FramelessDataPtr data = FramelessHelperExtractData(window);
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
Q_ASSERT(data);
if (!data) {
return false;
@ -1298,11 +1279,11 @@ bool Utils::showSystemMenu(const QWindow *window, const QPoint &pos, const bool
}
// Tweak the menu items according to the current window status and user settings.
const bool disableRestore = data->callbacks.getProperty(kSysMenuDisableRestoreVar, false).toBool();
const bool disableMinimize = data->callbacks.getProperty(kSysMenuDisableMinimizeVar, false).toBool();
const bool disableMaximize = data->callbacks.getProperty(kSysMenuDisableMaximizeVar, false).toBool();
const bool disableRestore = data->callbacks->getProperty(kSysMenuDisableRestoreVar, false).toBool();
const bool disableMinimize = data->callbacks->getProperty(kSysMenuDisableMinimizeVar, false).toBool();
const bool disableMaximize = data->callbacks->getProperty(kSysMenuDisableMaximizeVar, false).toBool();
const bool maxOrFull = (IsMaximized(hWnd) || isFullScreen(window));
const bool fixedSize = data->callbacks.isWindowFixedSize();
const bool fixedSize = data->callbacks->isWindowFixedSize();
::EnableMenuItem(hMenu, SC_RESTORE, (MF_BYCOMMAND | ((maxOrFull && !fixedSize && !disableRestore) ? MFS_ENABLED : MFS_DISABLED)));
// The first menu item should be selected by default if the menu is brought
// up by keyboard. I don't know how to pre-select a menu item but it seems
@ -1342,7 +1323,7 @@ bool Utils::showSystemMenu(const QWindow *window, const QPoint &pos, const bool
// highlighting until we unhighlight it manually.
::HiliteMenuItem(hWnd, hMenu, SC_RESTORE, (MF_BYCOMMAND | MFS_UNHILITE));
if (result == 0) {
if (result == FALSE) {
// The user canceled the menu, no need to continue.
return true;
}
@ -1877,7 +1858,7 @@ bool Utils::startSystemMove(QWindow *window, const QPoint &globalPos)
return false;
}
const auto hwnd = qWindowId<HWND>(window);
if (::PostMessageW(hwnd, WM_SYSCOMMAND, 0xF012 /*SC_DRAGMOVE*/, 0) == FALSE) {
if (::PostMessageW(hwnd, WM_SYSCOMMAND, SC_DRAGMOVE, 0) == FALSE) {
WARNING << getSystemErrorMessage(kPostMessageW);
return false;
}
@ -1914,10 +1895,8 @@ bool Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi
bool Utils::isWindowFrameBorderVisible()
{
static const auto result = []() -> bool {
#if FRAMELESSHELPER_CONFIG(native_impl)
const FramelessConfig * const config = FramelessConfig::instance();
if (config->isSet(Option::UseCrossPlatformQtImplementation)) {
return false;
}
if (config->isSet(Option::ForceShowWindowFrameBorder)) {
return true;
}
@ -1925,6 +1904,9 @@ bool Utils::isWindowFrameBorderVisible()
return false;
}
return WindowsVersionHelper::isWin10OrGreater();
#else
return false;
#endif
}();
return result;
}
@ -1950,8 +1932,20 @@ bool Utils::installWindowProcHook(const QWindow *window)
if (!window) {
return false;
}
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
Q_ASSERT(data);
if (!data) {
return false;
}
if (!data->extraData.ptr) {
data->extraData.ptr = new FramelessDataExtra();
}
if (!data->extraData.deleter) {
data->extraData.deleter = FramelessDataExtraDeleter;
}
const auto extraData = static_cast<FramelessDataExtra *>(data->extraData.ptr);
const auto hwnd = qWindowId<HWND>(window);
if (!g_win32UtilsData()->qtWindowProc) {
if (!extraData->qtWindowProc) {
::SetLastError(ERROR_SUCCESS);
const auto qtWindowProc = reinterpret_cast<WNDPROC>(::GetWindowLongPtrW(hwnd, GWLP_WNDPROC));
Q_ASSERT(qtWindowProc);
@ -1959,53 +1953,56 @@ bool Utils::installWindowProcHook(const QWindow *window)
WARNING << getSystemErrorMessage(kGetWindowLongPtrW);
return false;
}
g_win32UtilsData()->qtWindowProc = qtWindowProc;
extraData->qtWindowProc = qtWindowProc;
}
FramelessDataPtr data = FramelessHelperExtractData(window);
if (!data) {
data.reset(new FramelessData);
FramelessHelperSetData(const_cast<QWindow *>(window), data);
}
if (!data->windowProcHooked) {
if (!extraData->windowProcHooked) {
::SetLastError(ERROR_SUCCESS);
if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(FramelessHelperHookWindowProc)) == 0) {
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
return false;
}
data->windowProcHooked = true;
extraData->windowProcHooked = true;
}
return true;
}
bool Utils::uninstallWindowProcHook(const WId windowId)
bool Utils::uninstallWindowProcHook(const QWindow *window)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return false;
}
const auto it = g_win32UtilsData()->data.constFind(windowId);
if (it != g_win32UtilsData()->data.constEnd()) {
g_win32UtilsData()->data.erase(it);
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
Q_ASSERT(data);
if (!data) {
return false;
}
if (g_win32UtilsData()->data.isEmpty() && g_win32UtilsData()->qtWindowProc) {
const auto hwnd = reinterpret_cast<HWND>(windowId);
const auto extraData = static_cast<FramelessDataExtra *>(data->extraData.ptr);
if (!extraData || !extraData->windowProcHooked) {
return false;
}
Q_ASSERT(extraData->qtWindowProc);
if (!extraData->qtWindowProc) {
return false;
}
const auto hwnd = qWindowId<HWND>(window);
::SetLastError(ERROR_SUCCESS);
if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(g_win32UtilsData()->qtWindowProc)) == 0) {
if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(extraData->qtWindowProc)) == 0) {
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
return false;
}
g_win32UtilsData()->qtWindowProc = nullptr;
}
extraData->qtWindowProc = nullptr;
extraData->windowProcHooked = false;
return true;
}
bool Utils::setAeroSnappingEnabled(const WId windowId, const bool enable)
bool Utils::setAeroSnappingEnabled(const QWindow *window, const bool enable)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return false;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
const auto hwnd = qWindowId<HWND>(window);
::SetLastError(ERROR_SUCCESS);
const auto oldWindowStyle = static_cast<DWORD>(::GetWindowLongPtrW(hwnd, GWL_STYLE));
if (oldWindowStyle == 0) {
@ -2027,7 +2024,7 @@ bool Utils::setAeroSnappingEnabled(const WId windowId, const bool enable)
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
return false;
}
return triggerFrameChange(windowId);
return triggerFrameChange(window);
}
bool Utils::tryToEnableHighestDpiAwarenessLevel()
@ -2138,10 +2135,10 @@ bool Utils::tryToEnableHighestDpiAwarenessLevel()
return false;
}
bool Utils::updateGlobalWin32ControlsTheme(const WId windowId, const bool dark)
bool Utils::updateGlobalWin32ControlsTheme(const QWindow *window, const bool dark)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return false;
}
// There's no global dark theme for common Win32 controls before Win10 1809.
@ -2151,7 +2148,7 @@ bool Utils::updateGlobalWin32ControlsTheme(const WId windowId, const bool dark)
if (!API_THEME_AVAILABLE(SetWindowTheme)) {
return false;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
const auto hwnd = qWindowId<HWND>(window);
const HRESULT hr = API_CALL_FUNCTION(uxtheme, SetWindowTheme, hwnd,
(dark ? kSystemDarkThemeResourceName : kSystemLightThemeResourceName), nullptr);
if (FAILED(hr)) {
@ -2209,10 +2206,10 @@ bool Utils::shouldAppsUseDarkMode_windows()
return resultFromRegistry();
}
bool Utils::setCornerStyleForWindow(const WId windowId, const WindowCornerStyle style)
bool Utils::setCornerStyleForWindow(const QWindow *window, const WindowCornerStyle style)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return false;
}
// We cannot change the window corner style until Windows 11.
@ -2222,7 +2219,7 @@ bool Utils::setCornerStyleForWindow(const WId windowId, const WindowCornerStyle
if (!API_DWM_AVAILABLE(DwmSetWindowAttribute)) {
return false;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
const auto hwnd = qWindowId<HWND>(window);
const auto wcp = [style]() -> _DWM_WINDOW_CORNER_PREFERENCE {
switch (style) {
case WindowCornerStyle::Default:
@ -2246,22 +2243,32 @@ bool Utils::setCornerStyleForWindow(const WId windowId, const WindowCornerStyle
return true;
}
bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode, const QColor &color)
bool Utils::setBlurBehindWindowEnabled(const QWindow *window, const BlurMode mode, const QColor &color)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return false;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
Q_ASSERT(data);
if (!data) {
return false;
}
const auto extraData = static_cast<FramelessDataExtra *>(data->extraData.ptr);
Q_ASSERT(extraData);
if (!extraData) {
return false;
}
const auto hwnd = qWindowId<HWND>(window);
if (WindowsVersionHelper::isWin8OrGreater()) {
if (!(API_DWM_AVAILABLE(DwmSetWindowAttribute)
&& API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea))) {
WARNING << "Blur behind window is not available on current platform.";
return false;
}
const auto restoreWindowFrameMargins = [windowId]() -> void {
g_win32UtilsData()->micaWindowIds.removeAll(windowId);
std::ignore = updateWindowFrameMargins(windowId, false);
const auto restoreWindowFrameMargins = [window, extraData]() -> void {
extraData->mica = false;
std::ignore = updateWindowFrameMargins(window, false);
};
static const bool preferMicaAlt = (qEnvironmentVariableIntValue("FRAMELESSHELPER_PREFER_MICA_ALT") != 0);
const auto blurMode = [mode]() -> BlurMode {
@ -2334,7 +2341,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
return result;
} else {
if ((blurMode == BlurMode::Windows_Mica) || (blurMode == BlurMode::Windows_MicaAlt)) {
g_win32UtilsData()->micaWindowIds.append(windowId);
extraData->mica = true;
// By giving a negative value, DWM will extend the window frame into the whole
// client area. We need this step because the Mica material can only be applied
// to the non-client area of a window. Without this step, you'll get a window
@ -2531,13 +2538,13 @@ bool Utils::isBlurBehindWindowSupported()
return result;
}
bool Utils::hideOriginalTitleBarElements(const WId windowId, const bool disable)
bool Utils::hideOriginalTitleBarElements(const QWindow *window, const bool disable)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return false;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
const auto hwnd = qWindowId<HWND>(window);
static constexpr const DWORD validBits = (WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON | WTNCA_NOSYSMENU);
const DWORD mask = (disable ? validBits : 0);
const HRESULT hr = _SetWindowThemeNonClientAttributes(hwnd, mask, mask);
@ -2604,13 +2611,13 @@ bool Utils::registerThemeChangeNotification()
return true;
}
bool Utils::refreshWin32ThemeResources(const WId windowId, const bool dark)
bool Utils::refreshWin32ThemeResources(const QWindow *window, const bool dark)
{
// Code learned from the following repositories. Thank very much for their great effort!
// https://github.com/ysc3839/win32-darkmode/blob/master/win32-darkmode/DarkMode.h
// https://github.com/TortoiseGit/TortoiseGit/blob/master/src/TortoiseGitBlame/MainFrm.cpp
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return false;
}
// We have no way to adjust such things until Win10 1809.
@ -2620,7 +2627,7 @@ bool Utils::refreshWin32ThemeResources(const WId windowId, const bool dark)
if (!API_DWM_AVAILABLE(DwmSetWindowAttribute)) {
return false;
}
const auto hWnd = reinterpret_cast<HWND>(windowId);
const auto hWnd = qWindowId<HWND>(window);
const DWORD borderFlag = (WindowsVersionHelper::isWin1020H1OrGreater()
? _DWMWA_USE_IMMERSIVE_DARK_MODE : _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1);
const BOOL darkFlag = (dark ? TRUE : FALSE);
@ -2689,10 +2696,10 @@ bool Utils::refreshWin32ThemeResources(const WId windowId, const bool dark)
return true;
}
bool Utils::enableNonClientAreaDpiScalingForWindow(const WId windowId)
bool Utils::enableNonClientAreaDpiScalingForWindow(const QWindow *window)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return false;
}
if (!API_USER_AVAILABLE(EnableNonClientDpiScaling)) {
@ -2702,7 +2709,7 @@ bool Utils::enableNonClientAreaDpiScalingForWindow(const WId windowId)
if (getDpiAwarenessForCurrentProcess() == DpiAwareness::PerMonitorVersion2) {
return true;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
const auto hwnd = qWindowId<HWND>(window);
if (API_CALL_FUNCTION4(user32, EnableNonClientDpiScaling, hwnd) == FALSE) {
WARNING << getSystemErrorMessage(kEnableNonClientDpiScaling);
return false;
@ -2816,10 +2823,10 @@ DpiAwareness Utils::getDpiAwarenessForCurrentProcess(bool *highest)
return DpiAwareness::Unknown;
}
bool Utils::fixupChildWindowsDpiMessage(const WId windowId)
bool Utils::fixupChildWindowsDpiMessage(const QWindow *window)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return false;
}
// This hack is only available on Windows 10 and newer, and starting from
@ -2830,7 +2837,7 @@ bool Utils::fixupChildWindowsDpiMessage(const WId windowId)
&& (getDpiAwarenessForCurrentProcess() == DpiAwareness::PerMonitorVersion2))) {
return true;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
const auto hwnd = qWindowId<HWND>(window);
if (_EnableChildWindowDpiMessage2(hwnd, TRUE) != FALSE) {
return true;
}
@ -2884,13 +2891,13 @@ bool Utils::setDarkModeAllowedForApp(const bool allow)
return true;
}
bool Utils::bringWindowToFront(const WId windowId)
bool Utils::bringWindowToFront(const QWindow *window)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return false;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
const auto hwnd = qWindowId<HWND>(window);
const HWND oldForegroundWindow = ::GetForegroundWindow();
if (!oldForegroundWindow) {
// The foreground window can be NULL, it's not an API error.
@ -2956,13 +2963,13 @@ bool Utils::bringWindowToFront(const WId windowId)
return moveWindowToMonitor(hwnd, activeMonitor.value());
}
QPoint Utils::getWindowPlacementOffset(const WId windowId)
QPoint Utils::getWindowPlacementOffset(const QWindow *window)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return {};
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
const auto hwnd = qWindowId<HWND>(window);
::SetLastError(ERROR_SUCCESS);
const auto exStyle = static_cast<DWORD>(::GetWindowLongPtrW(hwnd, GWL_EXSTYLE));
if (exStyle == 0) {
@ -2983,13 +2990,13 @@ QPoint Utils::getWindowPlacementOffset(const WId windowId)
return {work.left - total.left, work.top - total.top};
}
QRect Utils::getWindowRestoreGeometry(const WId windowId)
QRect Utils::getWindowRestoreGeometry(const QWindow *window)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return {};
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
const auto hwnd = qWindowId<HWND>(window);
WINDOWPLACEMENT wp;
SecureZeroMemory(&wp, sizeof(wp));
wp.length = sizeof(wp);
@ -2997,16 +3004,25 @@ QRect Utils::getWindowRestoreGeometry(const WId windowId)
WARNING << getSystemErrorMessage(kGetWindowPlacement);
return {};
}
return rect2qrect(wp.rcNormalPosition).translated(getWindowPlacementOffset(windowId));
return rect2qrect(wp.rcNormalPosition).translated(getWindowPlacementOffset(window));
}
bool Utils::removeMicaWindow(const WId windowId)
bool Utils::removeMicaWindow(const QWindow *window)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return false;
}
g_win32UtilsData()->micaWindowIds.removeAll(windowId);
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
Q_ASSERT(data);
if (!data) {
return false;
}
const auto extraData = static_cast<FramelessDataExtra *>(data->extraData.ptr);
if (!extraData || !extraData->mica) {
return false;
}
extraData->mica = false;
return true;
}
@ -3041,13 +3057,13 @@ quint64 Utils::getKeyState()
return result;
}
bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const bool checkTopLevel)
bool Utils::isValidWindow(const QWindow *window, const bool checkVisible, const bool checkTopLevel)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return false;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
const auto hwnd = qWindowId<HWND>(window);
if (::IsWindow(hwnd) == FALSE) {
return false;
}
@ -3056,7 +3072,7 @@ bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const boo
return false;
}
const LONG_PTR exStyles = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
if ((exStyles != 0) && (exStyles & WS_EX_TOOLWINDOW)) {
if ((exStyles == 0) || (exStyles & WS_EX_TOOLWINDOW)) {
return false;
}
RECT rect = { 0, 0, 0, 0 };
@ -3079,10 +3095,10 @@ bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const boo
return true;
}
bool Utils::updateFramebufferTransparency(const WId windowId)
bool Utils::updateFramebufferTransparency(const QWindow *window)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return false;
}
if (!API_DWM_AVAILABLE(DwmEnableBlurBehindWindow)) {
@ -3093,7 +3109,7 @@ bool Utils::updateFramebufferTransparency(const WId windowId)
if (!isDwmCompositionEnabled()) {
return false;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
const auto hwnd = qWindowId<HWND>(window);
bool opaque = false;
bool ok = false;
std::ignore = getDwmColorizationColor(&opaque, &ok);
@ -3102,11 +3118,11 @@ bool Utils::updateFramebufferTransparency(const WId windowId)
DWM_BLURBEHIND bb;
SecureZeroMemory(&bb, sizeof(bb));
bb.dwFlags = (DWM_BB_ENABLE | DWM_BB_BLURREGION);
bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
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) {
if (::DeleteObject(bb.hRgnBlur) == FALSE) {
WARNING << getSystemErrorMessage(kDeleteObject);
}
}
@ -3133,14 +3149,14 @@ bool Utils::updateFramebufferTransparency(const WId windowId)
return true;
}
QMargins Utils::getWindowSystemFrameMargins(const WId windowId)
QMargins Utils::getWindowSystemFrameMargins(const QWindow *window)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return {};
}
const auto horizontalMargin = int(getResizeBorderThickness(windowId, true, true));
const auto verticalMargin = int(getResizeBorderThickness(windowId, false, true));
const auto horizontalMargin = int(getResizeBorderThickness(window, true, true));
const auto verticalMargin = int(getResizeBorderThickness(window, false, true));
return QMargins{ horizontalMargin, verticalMargin, horizontalMargin, verticalMargin };
}