diff --git a/include/FramelessHelper/Core/private/framelesshelpercore_global_p.h b/include/FramelessHelper/Core/private/framelesshelpercore_global_p.h index 330392e..b77370d 100644 --- a/include/FramelessHelper/Core/private/framelesshelpercore_global_p.h +++ b/include/FramelessHelper/Core/private/framelesshelpercore_global_p.h @@ -104,26 +104,32 @@ private: }; using FramelessCallbacksPtr = FramelessCallbacks::PtrType; +struct FramelessExtraData +{ + using PtrType = std::shared_ptr; + //[[nodiscard]] static PtrType create(); + +private: + Q_DISABLE_COPY_MOVE(FramelessExtraData) +}; +using FramelessExtraDataPtr = FramelessExtraData::PtrType; +using FramelessExtraDataPtrs = QList; +using FramelessExtraDataHash = QHash; + struct FramelessData { bool frameless = false; FramelessCallbacksPtr callbacks = nullptr; - struct { - void *ptr = nullptr; - using DeleterFunctionPrototype = void(*)(void*); - DeleterFunctionPrototype deleter = nullptr; - } extraData = {}; + FramelessExtraDataHash extraData = {}; using PtrType = std::shared_ptr; [[nodiscard]] static PtrType create(); - ~FramelessData(); - private: Q_DISABLE_COPY_MOVE(FramelessData) }; using FramelessDataPtr = FramelessData::PtrType; - +using FramelessDataPtrs = QList; using FramelessDataHash = QHash; template diff --git a/include/FramelessHelper/Core/utils.h b/include/FramelessHelper/Core/utils.h index 27e3423..bbcd764 100644 --- a/include/FramelessHelper/Core/utils.h +++ b/include/FramelessHelper/Core/utils.h @@ -25,9 +25,6 @@ #pragma once #include -#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) -# include -#endif // Q_OS_LINUX #if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) QT_BEGIN_NAMESPACE @@ -37,8 +34,6 @@ QT_END_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE -struct SystemParameters; - namespace Utils { diff --git a/include/FramelessHelper/Quick/private/framelessquickhelper_p.h b/include/FramelessHelper/Quick/private/framelessquickhelper_p.h index ce97403..a327161 100644 --- a/include/FramelessHelper/Quick/private/framelessquickhelper_p.h +++ b/include/FramelessHelper/Quick/private/framelessquickhelper_p.h @@ -40,7 +40,6 @@ class QuickMicaMaterial; class QuickWindowBorder; #endif class FramelessQuickHelper; -struct FramelessQuickHelperData; class FRAMELESSHELPER_QUICK_API FramelessQuickHelperPrivate : public QObject { @@ -83,8 +82,6 @@ public: Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const; Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const; void setSystemButtonState(const QuickGlobal::SystemButtonType button, const QuickGlobal::ButtonState state); - Q_NODISCARD const FramelessQuickHelperData *getWindowData() const; - Q_NODISCARD FramelessQuickHelperData *getWindowDataMutable() const; void rebindWindow(); FramelessQuickHelper *q_ptr = nullptr; diff --git a/src/core/framelessconfig.cpp b/src/core/framelessconfig.cpp index fdfaf73..0c7d867 100644 --- a/src/core/framelessconfig.cpp +++ b/src/core/framelessconfig.cpp @@ -56,7 +56,7 @@ struct FramelessConfigEntry static constexpr const std::array(Option::Last) + 1> FramelessOptionsTable = { - FramelessConfigEntry{ "FRAMELESSHELPER_USE_CROSS_PLATFORM_QT_IMPLEMENTATION", "Options/UseCrossPlatformQtImplementation" }, + //FramelessConfigEntry{ "FRAMELESSHELPER_USE_CROSS_PLATFORM_QT_IMPLEMENTATION", "Options/UseCrossPlatformQtImplementation" }, FramelessConfigEntry{ "FRAMELESSHELPER_FORCE_HIDE_WINDOW_FRAME_BORDER", "Options/ForceHideWindowFrameBorder" }, FramelessConfigEntry{ "FRAMELESSHELPER_FORCE_SHOW_WINDOW_FRAME_BORDER", "Options/ForceShowWindowFrameBorder" }, FramelessConfigEntry{ "FRAMELESSHELPER_DISABLE_WINDOWS_SNAP_LAYOUT", "Options/DisableWindowsSnapLayout" }, @@ -85,14 +85,14 @@ Q_GLOBAL_STATIC(FramelessConfigData, g_framelessConfigData) static inline void warnInappropriateOptions() { const FramelessConfig * const cfg = FramelessConfig::instance(); + if (cfg->isSet(Option::UseCrossPlatformQtImplementation)) { + WARNING << "Option::UseCrossPlatformQtImplementation is deprecated and has no effect now. It will be removed in a future version."; + } #ifdef Q_OS_WINDOWS if (cfg->isSet(Option::DisableWindowsSnapLayout)) { - WARNING << "Option::DisableWindowsSnapLayout is deprecated and will removed in a future version. It has not effect now."; + WARNING << "Option::DisableWindowsSnapLayout is deprecated and has no effect now. It will be removed in a future version."; } #else - if (cfg->isSet(Option::UseCrossPlatformQtImplementation)) { - WARNING << "Option::UseCrossPlatformQtImplementation is default on non-Windows platforms."; - } if (cfg->isSet(Option::ForceHideWindowFrameBorder)) { WARNING << "Option::ForceHideWindowFrameBorder is only available on Windows."; } diff --git a/src/core/framelesshelper_win.cpp b/src/core/framelesshelper_win.cpp index 2d3d043..24a2e71 100644 --- a/src/core/framelesshelper_win.cpp +++ b/src/core/framelesshelper_win.cpp @@ -114,8 +114,21 @@ struct FramelessDataWin : public FramelessData QRect restoreGeometry = {}; #endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) }; +using FramelessDataWinPtr = std::shared_ptr; -#define GetFramelessDataWin(Window) std::dynamic_pointer_cast(FramelessManagerPrivate::getData(Window)) +[[nodiscard]] static inline FramelessDataWinPtr tryGetData(const QWindow *window) +{ + Q_ASSERT(window); + if (!window) { + return nullptr; + } + const FramelessDataPtr data = FramelessManagerPrivate::getData(window); + Q_ASSERT(data); + if (!data) { + return nullptr; + } + return std::dynamic_pointer_cast(data); +} [[nodiscard]] FramelessDataPtr FramelessData::create() { @@ -199,7 +212,7 @@ void FramelessHelperWin::addWindow(const QWindow *window) if (!window) { return; } - const auto data = GetFramelessDataWin(window); + const FramelessDataWinPtr data = tryGetData(window); Q_ASSERT(data); if (!data || data->frameless) { return; @@ -292,7 +305,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me return false; } - const auto data = GetFramelessDataWin(window); + const FramelessDataWinPtr data = tryGetData(window); Q_ASSERT(data); if (!data || !data->frameless) { return false; diff --git a/src/core/framelesshelpercore_global.cpp b/src/core/framelesshelpercore_global.cpp index 82a2134..7ab5686 100644 --- a/src/core/framelesshelpercore_global.cpp +++ b/src/core/framelesshelpercore_global.cpp @@ -119,15 +119,20 @@ FramelessCallbacksPtr FramelessCallbacks::create() return std::make_shared(); } -FramelessData::~FramelessData() +FramelessExtraDataPtr FramelessExtraData::create() { - if (extraData.ptr) { - Q_ASSERT(extraData.deleter); - if (extraData.deleter) { - extraData.deleter(extraData.ptr); - extraData.deleter = nullptr; + return std::make_shared(); +} + +FramelessExtraData::~FramelessExtraData() +{ + if (ptr) { + Q_ASSERT(deleter); + if (deleter) { + deleter(ptr); + deleter = nullptr; } - extraData.ptr = nullptr; + ptr = nullptr; } } diff --git a/src/core/utils_win.cpp b/src/core/utils_win.cpp index 53fe40c..d49e87f 100644 --- a/src/core/utils_win.cpp +++ b/src/core/utils_win.cpp @@ -194,19 +194,48 @@ FRAMELESSHELPER_STRING_CONSTANT(ScreenToClient) FRAMELESSHELPER_STRING_CONSTANT(DwmFlush) FRAMELESSHELPER_STRING_CONSTANT(GetCursorPos) -struct FramelessDataExtra +static constexpr const auto UTILS_WIN_EXTRA_DATA_ID = quint8(1); + +struct UtilsWinExtraData : public FramelessExtraData { WNDPROC qtWindowProc = nullptr; bool windowProcHooked = false; bool mica = false; -}; -static inline void FramelessDataExtraDeleter(void *data) + [[nodiscard]] static FramelessExtraDataPtr create(); +}; +using UtilsWinExtraDataPtr = std::shared_ptr; + +FramelessExtraDataPtr UtilsWinExtraData::create() { - Q_ASSERT(data); - if (data) { - delete static_cast(data); + return std::make_shared(); +} + +template +[[nodiscard]] static inline UtilsWinExtraDataPtr tryGetExtraData(const T t, const bool create) +{ + FramelessDataPtr data = nullptr; + using T2 = std::remove_cvref_t; + if constexpr (std::is_same_v) { + data = FramelessManagerPrivate::getData(t); + } else if constexpr (std::is_same_v) { + data = t; + } else { + Q_UNREACHABLE_RETURN(nullptr); } + Q_ASSERT(data); + if (!data) { + return nullptr; + } + auto it = data->extraData.find(UTILS_WIN_EXTRA_DATA_ID); + if (it == data->extraData.end()) { + if (create) { + it = data->extraData.insert(UTILS_WIN_EXTRA_DATA_ID, UtilsWinExtraData::create()); + } else { + return nullptr; + } + } + return std::dynamic_pointer_cast(it.value()); } struct Win32Message @@ -889,7 +918,7 @@ static constexpr const std::array g_win32MessageMap = if (!data) { return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); } - const auto extraData = static_cast(data->extraData.ptr); + const UtilsWinExtraDataPtr extraData = tryGetExtraData(data, false); Q_ASSERT(extraData); if (!extraData) { return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); @@ -1101,12 +1130,7 @@ bool Utils::updateWindowFrameMargins(const QWindow *window, const bool reset) if (!isDwmCompositionEnabled()) { return false; } - const FramelessDataPtr data = FramelessManagerPrivate::getData(window); - Q_ASSERT(data); - if (!data) { - return false; - } - const auto extraData = static_cast(data->extraData.ptr); + const UtilsWinExtraDataPtr extraData = tryGetExtraData(window, false); Q_ASSERT(extraData); if (!extraData) { return false; @@ -1932,18 +1956,7 @@ 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(data->extraData.ptr); + const UtilsWinExtraDataPtr extraData = tryGetExtraData(window, true); const auto hwnd = qWindowId(window); if (!extraData->qtWindowProc) { ::SetLastError(ERROR_SUCCESS); @@ -1972,12 +1985,7 @@ bool Utils::uninstallWindowProcHook(const QWindow *window) if (!window) { return false; } - const FramelessDataPtr data = FramelessManagerPrivate::getData(window); - Q_ASSERT(data); - if (!data) { - return false; - } - const auto extraData = static_cast(data->extraData.ptr); + const UtilsWinExtraDataPtr extraData = tryGetExtraData(window, false); if (!extraData || !extraData->windowProcHooked) { return false; } @@ -2249,12 +2257,7 @@ bool Utils::setBlurBehindWindowEnabled(const QWindow *window, const BlurMode mod if (!window) { return false; } - const FramelessDataPtr data = FramelessManagerPrivate::getData(window); - Q_ASSERT(data); - if (!data) { - return false; - } - const auto extraData = static_cast(data->extraData.ptr); + const UtilsWinExtraDataPtr extraData = tryGetExtraData(window, false); Q_ASSERT(extraData); if (!extraData) { return false; @@ -3013,12 +3016,8 @@ bool Utils::removeMicaWindow(const QWindow *window) if (!window) { return false; } - const FramelessDataPtr data = FramelessManagerPrivate::getData(window); - Q_ASSERT(data); - if (!data) { - return false; - } - const auto extraData = static_cast(data->extraData.ptr); + const UtilsWinExtraDataPtr extraData = tryGetExtraData(window, false); + Q_ASSERT(extraData); if (!extraData || !extraData->mica) { return false; } diff --git a/src/quick/framelessquickhelper.cpp b/src/quick/framelessquickhelper.cpp index 0b93722..c199f3a 100644 --- a/src/quick/framelessquickhelper.cpp +++ b/src/quick/framelessquickhelper.cpp @@ -32,6 +32,7 @@ #endif #include #include +#include #include #include #ifdef Q_OS_WINDOWS @@ -72,10 +73,10 @@ FRAMELESSHELPER_BEGIN_NAMESPACE using namespace Global; -struct FramelessQuickHelperData +static constexpr const auto FRAMELESS_QUICK_HELPER_EXTRA_DATA_ID = quint8(3); + +struct FramelessQuickHelperExtraData : public FramelessExtraData { - bool ready = false; - SystemParameters params = {}; QPointer titleBarItem = nullptr; QList> hitTestVisibleItems = {}; QPointer windowIconButton = nullptr; @@ -84,11 +85,42 @@ struct FramelessQuickHelperData QPointer maximizeButton = nullptr; QPointer closeButton = nullptr; QList hitTestVisibleRects = {}; + + [[nodiscard]] static FramelessExtraDataPtr create(); }; +using FramelessQuickHelperExtraDataPtr = std::shared_ptr; -using FramelessQuickHelperInternal = QHash; +FramelessExtraDataPtr FramelessQuickHelperExtraData::create() +{ + return std::make_shared(); +} -Q_GLOBAL_STATIC(FramelessQuickHelperInternal, g_framelessQuickHelperData) +template +[[nodiscard]] static inline FramelessQuickHelperExtraDataPtr tryGetExtraData(const T t, const bool create) +{ + FramelessDataPtr data = nullptr; + using T2 = std::remove_cvref_t; + if constexpr (std::is_same_v) { + data = FramelessManagerPrivate::getData(t); + } else if constexpr (std::is_same_v) { + data = t; + } else { + Q_UNREACHABLE_RETURN(nullptr); + } + Q_ASSERT(data); + if (!data) { + return nullptr; + } + auto it = data->extraData.find(FRAMELESS_QUICK_HELPER_EXTRA_DATA_ID); + if (it == data->extraData.end()) { + if (create) { + it = data->extraData.insert(FRAMELESS_QUICK_HELPER_EXTRA_DATA_ID, FramelessQuickHelperExtraData::create()); + } else { + return nullptr; + } + } + return std::dynamic_pointer_cast(it.value()); +} FramelessQuickHelperPrivate::FramelessQuickHelperPrivate(FramelessQuickHelper *q) : QObject(q) { @@ -130,53 +162,54 @@ void FramelessQuickHelperPrivate::attach() return; } - FramelessQuickHelperData * const data = getWindowDataMutable(); - if (!data || data->ready) { + const FramelessDataPtr data = FramelessManagerPrivate::getData(window); + Q_ASSERT(data); + if (!data) { return; } + + if (!data->callbacks) { + data->callbacks = FramelessCallbacks::create(); + data->callbacks->getWindowId = [window]() -> WId { return window->winId(); }; + data->callbacks->getWindowFlags = [window]() -> Qt::WindowFlags { return window->flags(); }; + data->callbacks->setWindowFlags = [window](const Qt::WindowFlags flags) -> void { window->setFlags(flags); }; + data->callbacks->getWindowSize = [window]() -> QSize { return window->size(); }; + data->callbacks->setWindowSize = [window](const QSize &size) -> void { window->resize(size); }; + data->callbacks->getWindowPosition = [window]() -> QPoint { return window->position(); }; + data->callbacks->setWindowPosition = [window](const QPoint &pos) -> void { window->setX(pos.x()); window->setY(pos.y()); }; + data->callbacks->getWindowScreen = [window]() -> QScreen * { return window->screen(); }; + data->callbacks->isWindowFixedSize = [q]() -> bool { return q->isWindowFixedSize(); }; + data->callbacks->setWindowFixedSize = [q](const bool value) -> void { q->setWindowFixedSize(value); }; + data->callbacks->getWindowState = [window]() -> Qt::WindowState { return window->windowState(); }; + data->callbacks->setWindowState = [window](const Qt::WindowState state) -> void { window->setWindowState(state); }; + data->callbacks->getWindowHandle = [window]() -> QWindow * { return window; }; + data->callbacks->windowToScreen = [window](const QPoint &pos) -> QPoint { return window->mapToGlobal(pos); }; + data->callbacks->screenToWindow = [window](const QPoint &pos) -> QPoint { return window->mapFromGlobal(pos); }; + data->callbacks->isInsideSystemButtons = [this](const QPoint &pos, SystemButtonType *button) -> bool { + QuickGlobal::SystemButtonType button2 = QuickGlobal::SystemButtonType::Unknown; + const bool result = isInSystemButtons(pos, &button2); + *button = FRAMELESSHELPER_ENUM_QUICK_TO_CORE(SystemButtonType, button2); + return result; + }; + data->callbacks->isInsideTitleBarDraggableArea = [this](const QPoint &pos) -> bool { return isInTitleBarDraggableArea(pos); }; + data->callbacks->getWindowDevicePixelRatio = [window]() -> qreal { return window->effectiveDevicePixelRatio(); }; + data->callbacks->setSystemButtonState = [this](const SystemButtonType button, const ButtonState state) -> void { + setSystemButtonState(FRAMELESSHELPER_ENUM_CORE_TO_QUICK(SystemButtonType, button), FRAMELESSHELPER_ENUM_CORE_TO_QUICK(ButtonState, state)); + }; + data->callbacks->shouldIgnoreMouseEvents = [this](const QPoint &pos) -> bool { return shouldIgnoreMouseEvents(pos); }; + data->callbacks->showSystemMenu = [q](const QPoint &pos) -> void { q->showSystemMenu(pos); }; + data->callbacks->setProperty = [this](const char *name, const QVariant &value) -> void { setProperty(name, value); }; + data->callbacks->getProperty = [this](const char *name, const QVariant &defaultValue) -> QVariant { return getProperty(name, defaultValue); }; + data->callbacks->setCursor = [window](const QCursor &cursor) -> void { window->setCursor(cursor); }; + data->callbacks->unsetCursor = [window]() -> void { window->unsetCursor(); }; + data->callbacks->getWidgetHandle = []() -> QObject * { return nullptr; }; + data->callbacks->forceChildrenRepaint = [this](const int delay) -> void { repaintAllChildren(delay); }; + data->callbacks->resetQtGrabbedControl = []() -> bool { return false; }; + } + + std::ignore = tryGetExtraData(data, true); - SystemParameters params = {}; - params.getWindowId = [window]() -> WId { return window->winId(); }; - params.getWindowFlags = [window]() -> Qt::WindowFlags { return window->flags(); }; - params.setWindowFlags = [window](const Qt::WindowFlags flags) -> void { window->setFlags(flags); }; - params.getWindowSize = [window]() -> QSize { return window->size(); }; - params.setWindowSize = [window](const QSize &size) -> void { window->resize(size); }; - params.getWindowPosition = [window]() -> QPoint { return window->position(); }; - params.setWindowPosition = [window](const QPoint &pos) -> void { window->setX(pos.x()); window->setY(pos.y()); }; - params.getWindowScreen = [window]() -> QScreen * { return window->screen(); }; - params.isWindowFixedSize = [q]() -> bool { return q->isWindowFixedSize(); }; - params.setWindowFixedSize = [q](const bool value) -> void { q->setWindowFixedSize(value); }; - params.getWindowState = [window]() -> Qt::WindowState { return window->windowState(); }; - params.setWindowState = [window](const Qt::WindowState state) -> void { window->setWindowState(state); }; - params.getWindowHandle = [window]() -> QWindow * { return window; }; - params.windowToScreen = [window](const QPoint &pos) -> QPoint { return window->mapToGlobal(pos); }; - params.screenToWindow = [window](const QPoint &pos) -> QPoint { return window->mapFromGlobal(pos); }; - params.isInsideSystemButtons = [this](const QPoint &pos, SystemButtonType *button) -> bool { - QuickGlobal::SystemButtonType button2 = QuickGlobal::SystemButtonType::Unknown; - const bool result = isInSystemButtons(pos, &button2); - *button = FRAMELESSHELPER_ENUM_QUICK_TO_CORE(SystemButtonType, button2); - return result; - }; - params.isInsideTitleBarDraggableArea = [this](const QPoint &pos) -> bool { return isInTitleBarDraggableArea(pos); }; - params.getWindowDevicePixelRatio = [window]() -> qreal { return window->effectiveDevicePixelRatio(); }; - params.setSystemButtonState = [this](const SystemButtonType button, const ButtonState state) -> void { - setSystemButtonState(FRAMELESSHELPER_ENUM_CORE_TO_QUICK(SystemButtonType, button), - FRAMELESSHELPER_ENUM_CORE_TO_QUICK(ButtonState, state)); - }; - params.shouldIgnoreMouseEvents = [this](const QPoint &pos) -> bool { return shouldIgnoreMouseEvents(pos); }; - params.showSystemMenu = [q](const QPoint &pos) -> void { q->showSystemMenu(pos); }; - params.setProperty = [this](const char *name, const QVariant &value) -> void { setProperty(name, value); }; - params.getProperty = [this](const char *name, const QVariant &defaultValue) -> QVariant { return getProperty(name, defaultValue); }; - params.setCursor = [window](const QCursor &cursor) -> void { window->setCursor(cursor); }; - params.unsetCursor = [window]() -> void { window->unsetCursor(); }; - params.getWidgetHandle = []() -> QObject * { return nullptr; }; - params.forceChildrenRepaint = [this](const int delay) -> void { repaintAllChildren(delay); }; - params.resetQtGrabbedControl = []() -> bool { return false; }; - - FramelessManager::instance()->addWindow(¶ms); - - data->params = params; - data->ready = true; + std::ignore = FramelessManager::instance()->addWindow(window); // We have to wait for a little time before moving the top level window // , because the platform window may not finish initializing by the time @@ -198,17 +231,11 @@ void FramelessQuickHelperPrivate::attach() void FramelessQuickHelperPrivate::detach() { Q_Q(FramelessQuickHelper); - QQuickWindow * const w = q->window(); - if (!w) { + const QQuickWindow * const window = q->window(); + if (!window) { return; } - const WId windowId = w->winId(); - const auto it = g_framelessQuickHelperData()->constFind(windowId); - if (it == g_framelessQuickHelperData()->constEnd()) { - return; - } - g_framelessQuickHelperData()->erase(it); - FramelessManager::instance()->removeWindow(windowId); + std::ignore = FramelessManager::instance()->removeWindow(window); } void FramelessQuickHelperPrivate::emitSignalForAllInstances(const char *signal) @@ -433,37 +460,43 @@ bool FramelessQuickHelperPrivate::isInSystemButtons(const QPoint &pos, QuickGlob if (!button) { return false; } - const FramelessQuickHelperData *data = getWindowData(); - if (!data) { + Q_Q(const FramelessQuickHelper); + const QQuickWindow * const window = q->window(); + if (!window) { + return false; + } + const FramelessQuickHelperExtraDataPtr extraData = tryGetExtraData(window, false); + Q_ASSERT(extraData); + if (!extraData) { return false; } *button = QuickGlobal::SystemButtonType::Unknown; - if (data->windowIconButton && data->windowIconButton->isVisible() && data->windowIconButton->isEnabled()) { - if (mapItemGeometryToScene(data->windowIconButton).contains(pos)) { + if (extraData->windowIconButton && extraData->windowIconButton->isVisible() && extraData->windowIconButton->isEnabled()) { + if (mapItemGeometryToScene(extraData->windowIconButton).contains(pos)) { *button = QuickGlobal::SystemButtonType::WindowIcon; return true; } } - if (data->contextHelpButton && data->contextHelpButton->isVisible() && data->contextHelpButton->isEnabled()) { - if (mapItemGeometryToScene(data->contextHelpButton).contains(pos)) { + if (extraData->contextHelpButton && extraData->contextHelpButton->isVisible() && extraData->contextHelpButton->isEnabled()) { + if (mapItemGeometryToScene(extraData->contextHelpButton).contains(pos)) { *button = QuickGlobal::SystemButtonType::Help; return true; } } - if (data->minimizeButton && data->minimizeButton->isVisible() && data->minimizeButton->isEnabled()) { - if (mapItemGeometryToScene(data->minimizeButton).contains(pos)) { + if (extraData->minimizeButton && extraData->minimizeButton->isVisible() && extraData->minimizeButton->isEnabled()) { + if (mapItemGeometryToScene(extraData->minimizeButton).contains(pos)) { *button = QuickGlobal::SystemButtonType::Minimize; return true; } } - if (data->maximizeButton && data->maximizeButton->isVisible() && data->maximizeButton->isEnabled()) { - if (mapItemGeometryToScene(data->maximizeButton).contains(pos)) { + if (extraData->maximizeButton && extraData->maximizeButton->isVisible() && extraData->maximizeButton->isEnabled()) { + if (mapItemGeometryToScene(extraData->maximizeButton).contains(pos)) { *button = QuickGlobal::SystemButtonType::Maximize; return true; } } - if (data->closeButton && data->closeButton->isVisible() && data->closeButton->isEnabled()) { - if (mapItemGeometryToScene(data->closeButton).contains(pos)) { + if (extraData->closeButton && extraData->closeButton->isVisible() && extraData->closeButton->isEnabled()) { + if (mapItemGeometryToScene(extraData->closeButton).contains(pos)) { *button = QuickGlobal::SystemButtonType::Close; return true; } @@ -473,18 +506,6 @@ bool FramelessQuickHelperPrivate::isInSystemButtons(const QPoint &pos, QuickGlob bool FramelessQuickHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos) const { - const FramelessQuickHelperData *data = getWindowData(); - if (!data) { - return false; - } - if (!data->titleBarItem) { - // There's no title bar at all, the mouse will always be in the client area. - return false; - } - if (!data->titleBarItem->isVisible() || !data->titleBarItem->isEnabled()) { - // The title bar is hidden or disabled for some reason, treat it as there's no title bar. - return false; - } Q_Q(const FramelessQuickHelper); const QQuickWindow * const window = q->window(); if (!window) { @@ -492,8 +513,21 @@ bool FramelessQuickHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos) c // so we assume there's no title bar. return false; } + const FramelessQuickHelperExtraDataPtr extraData = tryGetExtraData(window, false); + Q_ASSERT(extraData); + if (!extraData) { + return false; + } + if (!extraData->titleBarItem) { + // There's no title bar at all, the mouse will always be in the client area. + return false; + } + if (!extraData->titleBarItem->isVisible() || !extraData->titleBarItem->isEnabled()) { + // The title bar is hidden or disabled for some reason, treat it as there's no title bar. + return false; + } const QRect windowRect = {QPoint(0, 0), window->size()}; - const QRect titleBarRect = mapItemGeometryToScene(data->titleBarItem); + const QRect titleBarRect = mapItemGeometryToScene(extraData->titleBarItem); if (!titleBarRect.intersects(windowRect)) { // The title bar is totally outside of the window for some reason, // also treat it as there's no title bar. @@ -501,24 +535,24 @@ bool FramelessQuickHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos) c } QRegion region = titleBarRect; const auto systemButtons = { - data->windowIconButton, data->contextHelpButton, - data->minimizeButton, data->maximizeButton, - data->closeButton + extraData->windowIconButton, extraData->contextHelpButton, + extraData->minimizeButton, extraData->maximizeButton, + extraData->closeButton }; for (auto &&button : std::as_const(systemButtons)) { if (button && button->isVisible() && button->isEnabled()) { region -= mapItemGeometryToScene(button); } } - if (!data->hitTestVisibleItems.isEmpty()) { - for (auto &&item : std::as_const(data->hitTestVisibleItems)) { + if (!extraData->hitTestVisibleItems.isEmpty()) { + for (auto &&item : std::as_const(extraData->hitTestVisibleItems)) { if (item && item->isVisible() && item->isEnabled()) { region -= mapItemGeometryToScene(item); } } } - if (!data->hitTestVisibleRects.isEmpty()) { - for (auto &&rect : std::as_const(data->hitTestVisibleRects)) { + if (!extraData->hitTestVisibleRects.isEmpty()) { + for (auto &&rect : std::as_const(extraData->hitTestVisibleRects)) { if (rect.isValid()) { region -= rect; } @@ -556,38 +590,6 @@ void FramelessQuickHelperPrivate::setSystemButtonState(const QuickGlobal::System Q_UNUSED(state); } -const FramelessQuickHelperData *FramelessQuickHelperPrivate::getWindowData() const -{ - Q_Q(const FramelessQuickHelper); - const QQuickWindow * const window = q->window(); - //Q_ASSERT(window); - if (!window) { - return nullptr; - } - const WId windowId = window->winId(); - auto it = g_framelessQuickHelperData()->find(windowId); - if (it == g_framelessQuickHelperData()->end()) { - it = g_framelessQuickHelperData()->insert(windowId, {}); - } - return &it.value(); -} - -FramelessQuickHelperData *FramelessQuickHelperPrivate::getWindowDataMutable() const -{ - Q_Q(const FramelessQuickHelper); - const QQuickWindow * const window = q->window(); - //Q_ASSERT(window); - if (!window) { - return nullptr; - } - const WId windowId = window->winId(); - auto it = g_framelessQuickHelperData()->find(windowId); - if (it == g_framelessQuickHelperData()->end()) { - it = g_framelessQuickHelperData()->insert(windowId, {}); - } - return &it.value(); -} - void FramelessQuickHelperPrivate::rebindWindow() { Q_Q(FramelessQuickHelper); @@ -668,33 +670,41 @@ void FramelessQuickHelper::setHitTestVisible_item(QQuickItem *item, const bool v if (!item) { return; } - Q_D(FramelessQuickHelper); - FramelessQuickHelperData *data = d->getWindowDataMutable(); - if (!data) { + const QQuickWindow * const w = window(); + if (!w) { + return; + } + const FramelessQuickHelperExtraDataPtr extraData = tryGetExtraData(w, false); + Q_ASSERT(extraData); + if (!extraData) { return; } if (visible) { - data->hitTestVisibleItems.append(item); + extraData->hitTestVisibleItems.append(item); } else { - data->hitTestVisibleItems.removeAll(item); + extraData->hitTestVisibleItems.removeAll(item); } } void FramelessQuickHelper::setHitTestVisible_rect(const QRect &rect, const bool visible) { - Q_ASSERT(rect.isValid()); - if (!rect.isValid()) { + Q_ASSERT(Utils::isValidGeometry(rect)); + if (!Utils::isValidGeometry(rect)) { return; } - Q_D(FramelessQuickHelper); - FramelessQuickHelperData *data = d->getWindowDataMutable(); - if (!data) { + const QQuickWindow * const w = window(); + if (!w) { + return; + } + const FramelessQuickHelperExtraDataPtr extraData = tryGetExtraData(w, false); + Q_ASSERT(extraData); + if (!extraData) { return; } if (visible) { - data->hitTestVisibleRects.append(rect); + extraData->hitTestVisibleRects.append(rect); } else { - data->hitTestVisibleRects.removeAll(rect); + extraData->hitTestVisibleRects.removeAll(rect); } } @@ -714,9 +724,13 @@ void FramelessQuickHelper::setHitTestVisible_object(QObject *object, const bool bool FramelessQuickHelper::isContentExtendedIntoTitleBar() const { - Q_D(const FramelessQuickHelper); - const FramelessQuickHelperData *data = d->getWindowData(); - return (data ? data->ready : false); + const QQuickWindow * const w = window(); + if (!w) { + return false; + } + const FramelessDataPtr data = FramelessManagerPrivate::getData(w); + Q_ASSERT(data); + return (data && data->frameless); } void FramelessQuickHelper::extendsContentIntoTitleBar(const bool value) @@ -736,9 +750,16 @@ void FramelessQuickHelper::extendsContentIntoTitleBar(const bool value) QQuickItem *FramelessQuickHelper::titleBarItem() const { - Q_D(const FramelessQuickHelper); - const FramelessQuickHelperData *data = d->getWindowData(); - return (data ? data->titleBarItem : nullptr); + const QQuickWindow * const w = window(); + if (!w) { + return nullptr; + } + const FramelessQuickHelperExtraDataPtr extraData = tryGetExtraData(w, false); + Q_ASSERT(extraData); + if (!extraData) { + return nullptr; + } + return extraData->titleBarItem; } void FramelessQuickHelper::setTitleBarItem(QQuickItem *value) @@ -747,12 +768,17 @@ void FramelessQuickHelper::setTitleBarItem(QQuickItem *value) if (!value) { return; } - Q_D(FramelessQuickHelper); - FramelessQuickHelperData *data = d->getWindowDataMutable(); - if (!data || (data->titleBarItem == value)) { + const QQuickWindow * const w = window(); + if (!w) { return; } - data->titleBarItem = value; + const FramelessQuickHelperExtraDataPtr extraData = tryGetExtraData(w, false); + Q_ASSERT(extraData); + if (!extraData || (extraData->titleBarItem == value)) { + return; + } + extraData->titleBarItem = value; + Q_D(FramelessQuickHelper); d->emitSignalForAllInstances("titleBarItemChanged"); } @@ -763,27 +789,31 @@ void FramelessQuickHelper::setSystemButton(QQuickItem *item, const QuickGlobal:: if (!item || (buttonType == QuickGlobal::SystemButtonType::Unknown)) { return; } - Q_D(FramelessQuickHelper); - FramelessQuickHelperData *data = d->getWindowDataMutable(); - if (!data) { + const QQuickWindow * const w = window(); + if (!w) { + return; + } + const FramelessQuickHelperExtraDataPtr extraData = tryGetExtraData(w, false); + Q_ASSERT(extraData); + if (!extraData) { return; } switch (buttonType) { case QuickGlobal::SystemButtonType::WindowIcon: - data->windowIconButton = item; + extraData->windowIconButton = item; break; case QuickGlobal::SystemButtonType::Help: - data->contextHelpButton = item; + extraData->contextHelpButton = item; break; case QuickGlobal::SystemButtonType::Minimize: - data->minimizeButton = item; + extraData->minimizeButton = item; break; case QuickGlobal::SystemButtonType::Maximize: case QuickGlobal::SystemButtonType::Restore: - data->maximizeButton = item; + extraData->maximizeButton = item; break; case QuickGlobal::SystemButtonType::Close: - data->closeButton = item; + extraData->closeButton = item; break; case QuickGlobal::SystemButtonType::Unknown: Q_UNREACHABLE(); @@ -796,15 +826,12 @@ void FramelessQuickHelper::showSystemMenu(const QPoint &pos) if (!w) { return; } - const WId windowId = w->winId(); const QPoint nativePos = Utils::toNativeGlobalPosition(w, pos); #ifdef Q_OS_WINDOWS - Q_D(FramelessQuickHelper); - std::ignore = Utils::showSystemMenu(windowId, nativePos, false, &d->getWindowData()->params); + std::ignore = Utils::showSystemMenu(w, nativePos, false); #elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) - Utils::openSystemMenu(windowId, nativePos); + Utils::openSystemMenu(w, nativePos); #else - Q_UNUSED(windowId); Q_UNUSED(nativePos); #endif } @@ -832,11 +859,11 @@ void FramelessQuickHelper::windowStartSystemResize2(const Qt::Edges edges, const void FramelessQuickHelper::moveWindowToDesktopCenter() { - if (!window()) { + const QQuickWindow * const w = window(); + if (!w) { return; } - Q_D(FramelessQuickHelper); - Utils::moveWindowToDesktopCenter(&d->getWindowData()->params, true); + std::ignore = Utils::moveWindowToDesktopCenter(w, true); } void FramelessQuickHelper::bringWindowToFront() @@ -846,7 +873,7 @@ void FramelessQuickHelper::bringWindowToFront() return; } #ifdef Q_OS_WINDOWS - std::ignore = Utils::bringWindowToFront(w->winId()); + std::ignore = Utils::bringWindowToFront(w); #else if (w->visibility() == QQuickWindow::Hidden) { w->show(); @@ -898,7 +925,7 @@ void FramelessQuickHelper::setWindowFixedSize(const bool value) w->setMaximumSize(QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX)); } #ifdef Q_OS_WINDOWS - std::ignore = Utils::setAeroSnappingEnabled(w->winId(), !value); + std::ignore = Utils::setAeroSnappingEnabled(w, !value); #endif Q_D(FramelessQuickHelper); d->emitSignalForAllInstances("windowFixedSizeChanged"); @@ -935,7 +962,7 @@ void FramelessQuickHelper::setBlurBehindWindowEnabled(const bool value) } mode = QuickGlobal::BlurMode::Disable; } - if (Utils::setBlurBehindWindowEnabled(w->winId(), FRAMELESSHELPER_ENUM_QUICK_TO_CORE(BlurMode, mode), {})) { + if (Utils::setBlurBehindWindowEnabled(w, FRAMELESSHELPER_ENUM_QUICK_TO_CORE(BlurMode, mode), {})) { d->blurBehindWindowEnabled = value; d->emitSignalForAllInstances("blurBehindWindowEnabledChanged"); } else { diff --git a/src/widgets/framelesswidgetshelper.cpp b/src/widgets/framelesswidgetshelper.cpp index 9208e95..eb8e354 100644 --- a/src/widgets/framelesswidgetshelper.cpp +++ b/src/widgets/framelesswidgetshelper.cpp @@ -35,6 +35,7 @@ #include "widgetssharedhelper_p.h" #include #include +#include #include #include #include @@ -71,10 +72,10 @@ FRAMELESSHELPER_BEGIN_NAMESPACE using namespace Global; -struct FramelessWidgetsHelperData +static constexpr const auto FRAMELESS_WIDGETS_HELPER_EXTRA_DATA_ID = quint8(2); + +struct FramelessWidgetsHelperExtraData : public FramelessExtraData { - bool ready = false; - SystemParameters params = {}; QPointer titleBarWidget = nullptr; QList> hitTestVisibleWidgets = {}; QPointer windowIconButton = nullptr; @@ -83,11 +84,42 @@ struct FramelessWidgetsHelperData QPointer maximizeButton = nullptr; QPointer closeButton = nullptr; QList hitTestVisibleRects = {}; + + [[nodiscard]] static FramelessExtraDataPtr create(); }; +using FramelessWidgetsHelperExtraDataPtr = std::shared_ptr; -using FramelessWidgetsHelperInternal = QHash; +FramelessExtraDataPtr FramelessWidgetsHelperExtraData::create() +{ + return std::make_shared(); +} -Q_GLOBAL_STATIC(FramelessWidgetsHelperInternal, g_framelessWidgetsHelperData) +template +[[nodiscard]] static inline FramelessWidgetsHelperExtraDataPtr tryGetExtraData(const T t, const bool create) +{ + FramelessDataPtr data = nullptr; + using T2 = std::remove_cvref_t; + if constexpr (std::is_same_v) { + data = FramelessManagerPrivate::getData(t); + } else if constexpr (std::is_same_v) { + data = t; + } else { + Q_UNREACHABLE_RETURN(nullptr); + } + Q_ASSERT(data); + if (!data) { + return nullptr; + } + auto it = data->extraData.find(FRAMELESS_WIDGETS_HELPER_EXTRA_DATA_ID); + if (it == data->extraData.end()) { + if (create) { + it = data->extraData.insert(FRAMELESS_WIDGETS_HELPER_EXTRA_DATA_ID, FramelessWidgetsHelperExtraData::create()); + } else { + return nullptr; + } + } + return std::dynamic_pointer_cast(it.value()); +} [[nodiscard]] static inline bool isWidgetFixedSize(const QWidget * const widget) { @@ -421,7 +453,7 @@ void FramelessWidgetsHelperPrivate::attach() params.resetQtGrabbedControl = []() -> bool { if (qt_button_down) { static constexpr const auto invalidPos = QPoint{ -99999, -99999 }; - const auto event = std::make_unique( + const auto event = new QMouseEvent( QEvent::MouseButtonRelease, invalidPos, invalidPos, @@ -429,7 +461,7 @@ void FramelessWidgetsHelperPrivate::attach() Qt::LeftButton, QGuiApplication::mouseButtons() ^ Qt::LeftButton, QGuiApplication::keyboardModifiers()); - QApplication::sendEvent(qt_button_down, event.get()); + QApplication::postEvent(qt_button_down, event); qt_button_down = nullptr; return true; }