From 6bba66abcdc40cbb9f4199401057d49d03ae1b69 Mon Sep 17 00:00:00 2001 From: yeshanshan Date: Mon, 28 Sep 2026 12:50:45 +0800 Subject: [PATCH 1/3] feat: adapt dtkgui to Treeland protocol changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: 适配 dtkgui 到 Treeland 协议变更 1. Split personalizationwaylandclientextension into three independent protocol wrappers: treelandappearance, treelanddecoration, and treelandbackgroundeffect 2. Update dtreelandplatforminterface to use treeland_appearance_v1 read-only global, replace PersonalizationManager/AppearanceContext dependencies, setters become no-op 3. Update dtreelandplatformwindowinterface to use treeland_decoration_context_v1 + ext_background_effect_v1 surface, split dirty state management 4. Update dtreelandwindowmanagerhelper to independently detect hasBlurWindow()/hasNoTitlebar() via separate globals 5. Update plugins.cmake to reference three new protocol XML files 6. Update config.tests/treeland_test CMakeLists.txt and main.cpp 7. Update debian/control to require treeland-protocols >= 0.7.0 8. Add window blur area support in dplatformhandle.cpp 1. 将 personalizationwaylandclientextension 拆分为三个独立的协议封装: treelandappearance、treelanddecoration、treelandbackgroundeffect 2. 更新 dtreelandplatforminterface 使用 treeland_appearance_v1 只读 global,移除 PersonalizationManager/AppearanceContext 依赖,setter 改为 no-op 3. 更新 dtreelandplatformwindowinterface 使用 treeland_decoration_context_v1 + ext_background_effect_v1 surface, 拆分 dirty state 管理 4. 更新 dtreelandwindowmanagerhelper 各 global 独立检测 hasBlurWindow()/hasNoTitlebar() 5. 更新 plugins.cmake 引用三个新协议 XML 文件 6. 更新 config.tests/treeland_test 的 CMakeLists.txt 和 main.cpp 7. 更新 debian/control 要求 treeland-protocols >= 0.7.0 8. 在 dplatformhandle.cpp 中添加窗口模糊区域支持 Log: Treeland 协议从单一 personalization-manager 拆分为 appearance、decoration、background-effect 三个独立协议,dtkgui 需要适配新的协议接口 Influence: dtkgui Treeland 平台插件,影响窗口装饰、模糊效果和外观属性的 Wayland 适配 --- debian/control | 2 +- src/kernel/dplatformhandle.cpp | 12 ++ .../config.tests/treeland_test/CMakeLists.txt | 25 ++- .../config.tests/treeland_test/main.cpp | 14 +- .../treeland/dtreelandplatforminterface.cpp | 45 ++--- .../treeland/dtreelandplatforminterface.h | 15 +- .../dtreelandplatformwindowinterface.cpp | 127 ++++++++++--- .../dtreelandplatformwindowinterface.h | 28 ++- .../treeland/dtreelandwindowmanagerhelper.cpp | 14 +- .../personalizationwaylandclientextension.cpp | 170 ------------------ .../personalizationwaylandclientextension.h | 90 ---------- .../treelandappearanceclientextension.cpp | 156 ++++++++++++++++ .../treelandappearanceclientextension.h | 59 ++++++ ...reelandbackgroundeffectclientextension.cpp | 87 +++++++++ .../treelandbackgroundeffectclientextension.h | 58 ++++++ .../treelanddecorationclientextension.cpp | 77 ++++++++ .../treelanddecorationclientextension.h | 50 ++++++ src/plugins/plugins.cmake | 21 ++- 18 files changed, 686 insertions(+), 364 deletions(-) delete mode 100644 src/plugins/platform/treeland/personalizationwaylandclientextension.cpp delete mode 100644 src/plugins/platform/treeland/personalizationwaylandclientextension.h create mode 100644 src/plugins/platform/treeland/treelandappearanceclientextension.cpp create mode 100644 src/plugins/platform/treeland/treelandappearanceclientextension.h create mode 100644 src/plugins/platform/treeland/treelandbackgroundeffectclientextension.cpp create mode 100644 src/plugins/platform/treeland/treelandbackgroundeffectclientextension.h create mode 100644 src/plugins/platform/treeland/treelanddecorationclientextension.cpp create mode 100644 src/plugins/platform/treeland/treelanddecorationclientextension.h diff --git a/debian/control b/debian/control index 08816240..7cc69635 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,7 @@ Build-Depends: debhelper-compat (= 12), libgmock-dev, libdtkcommon-dev, librsvg2-dev, - treeland-protocols (>>0.5.8), + treeland-protocols (>= 0.7.0), extra-cmake-modules, libdtkdata, libdtkcore-dev , diff --git a/src/kernel/dplatformhandle.cpp b/src/kernel/dplatformhandle.cpp index 2c668042..c8f527ae 100644 --- a/src/kernel/dplatformhandle.cpp +++ b/src/kernel/dplatformhandle.cpp @@ -607,6 +607,12 @@ bool DPlatformHandle::setWindowBlurAreaByWM(QWindow *window, const QVector(platformWindowImpl(&handle))) { return impl->setWindowBlurArea(area); } +#endif +#ifndef DTK_DISABLE_TREELAND + if (auto impl = dynamic_cast(platformWindowImpl(&handle))) { + impl->setWindowBlurAreas(area); + return true; + } #endif handle.setEnableBlurWindow(true); return true; @@ -663,6 +669,12 @@ bool DPlatformHandle::setWindowBlurAreaByWM(QWindow *window, const QList(platformWindowImpl(&handle))) { return impl->setWindowBlurArea(paths); } +#endif +#ifndef DTK_DISABLE_TREELAND + if (auto impl = dynamic_cast(platformWindowImpl(&handle))) { + impl->setWindowBlurPaths(paths); + return true; + } #endif handle.setEnableBlurWindow(true); return true; diff --git a/src/plugins/platform/config.tests/treeland_test/CMakeLists.txt b/src/plugins/platform/config.tests/treeland_test/CMakeLists.txt index 862e858b..d551da6a 100644 --- a/src/plugins/platform/config.tests/treeland_test/CMakeLists.txt +++ b/src/plugins/platform/config.tests/treeland_test/CMakeLists.txt @@ -21,12 +21,17 @@ pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client) find_package(TreelandProtocols) set(TreelandProtocols_FOUND ${TreelandProtocols_FOUND}) +find_package(ECM REQUIRED NO_MODULE) +set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${ECM_MODULE_PATH}") +find_package(WaylandProtocols) add_executable(${PROJECT_NAME} main.cpp) if("${QT_VERSION_MAJOR}" STREQUAL "6") qt6_generate_wayland_protocol_client_sources(${PROJECT_NAME} FILES - ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-personalization-manager-v1.xml + ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-appearance-unstable-v1.xml + ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-decoration-unstable-v1.xml + ${WaylandProtocols_DATADIR}/staging/ext-background-effect/ext-background-effect-v1.xml ) if (${Qt6Core_VERSION} VERSION_GREATER_EQUAL "6.10.0") @@ -36,14 +41,20 @@ if("${QT_VERSION_MAJOR}" STREQUAL "6") else() # ECM setup include(FeatureSummary) - find_package(ECM REQUIRED NO_MODULE) - set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${ECM_MODULE_PATH}") find_package(QtWaylandScanner) - ecm_add_qtwayland_client_protocol(TABLET_SRCS - PROTOCOL ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-personalization-manager-v1.xml - BASENAME treeland-personalization-manager-v1 + ecm_add_qtwayland_client_protocol(CLIENT_SRCS + PROTOCOL ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-appearance-unstable-v1.xml + BASENAME treeland-appearance-unstable-v1 ) - target_sources(${PROJECT_NAME} PRIVATE ${TABLET_SRCS}) + ecm_add_qtwayland_client_protocol(CLIENT_SRCS + PROTOCOL ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-decoration-unstable-v1.xml + BASENAME treeland-decoration-unstable-v1 + ) + ecm_add_qtwayland_client_protocol(CLIENT_SRCS + PROTOCOL ${WaylandProtocols_DATADIR}/staging/ext-background-effect/ext-background-effect-v1.xml + BASENAME ext-background-effect-v1 + ) + target_sources(${PROJECT_NAME} PRIVATE ${CLIENT_SRCS}) target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::XkbCommonSupportPrivate diff --git a/src/plugins/platform/config.tests/treeland_test/main.cpp b/src/plugins/platform/config.tests/treeland_test/main.cpp index 433aefae..ef1e2f8f 100644 --- a/src/plugins/platform/config.tests/treeland_test/main.cpp +++ b/src/plugins/platform/config.tests/treeland_test/main.cpp @@ -9,7 +9,7 @@ #include #include -#include "qwayland-treeland-personalization-manager-v1.h" +#include "qwayland-treeland-decoration-unstable-v1.h" #include #include @@ -17,15 +17,15 @@ #include #include -class PersonalizationWindowContext : public QWaylandClientExtensionTemplate, - public QtWayland::treeland_personalization_window_context_v1 +class TreelandDecorationContext : public QWaylandClientExtensionTemplate, + public QtWayland::treeland_decoration_context_v1 { public: - PersonalizationWindowContext(struct ::treeland_personalization_window_context_v1 *context) - : QWaylandClientExtensionTemplate(1) - , QtWayland::treeland_personalization_window_context_v1(context) + TreelandDecorationContext(struct ::treeland_decoration_context_v1 *context) + : QWaylandClientExtensionTemplate(1) + , QtWayland::treeland_decoration_context_v1(context) { - set_titlebar(enable_mode::enable_mode_disable); + set_titlebar_mode(titlebar_mode_hide); } }; diff --git a/src/plugins/platform/treeland/dtreelandplatforminterface.cpp b/src/plugins/platform/treeland/dtreelandplatforminterface.cpp index 54150e3b..b73e3aac 100644 --- a/src/plugins/platform/treeland/dtreelandplatforminterface.cpp +++ b/src/plugins/platform/treeland/dtreelandplatforminterface.cpp @@ -6,7 +6,7 @@ #include "dplatformtheme.h" #include "private/dplatforminterface_p.h" -#include "personalizationwaylandclientextension.h" +#include "treelandappearanceclientextension.h" #include #include @@ -16,7 +16,6 @@ DGUI_BEGIN_NAMESPACE DTreelandPlatformInterface::DTreelandPlatformInterface(DPlatformTheme *platformTheme) : DPlatformInterface(platformTheme) - , m_manager(nullptr) , m_activeColor(QColor()) , m_titleHeight(0) , m_fontName(QByteArray()) @@ -27,24 +26,21 @@ DTreelandPlatformInterface::DTreelandPlatformInterface(DPlatformTheme *platformT , m_windowRadius(0) , m_scrollBarPolicy(0) , m_themeName(QByteArray()) - , m_blurOpacity(0) + , m_blurOpacity(0.0) { - m_manager = PersonalizationManager::instance(); - connect(m_manager, &PersonalizationManager::activeChanged, this, [this](){ - if (m_manager->isActive()) { + connect(TreelandAppearance::instance(), &TreelandAppearance::activeChanged, this, [this](){ + if (TreelandAppearance::instance()->isSupported()) { initContext(); } }); + if (TreelandAppearance::instance()->isSupported()) { + initContext(); + } } void DTreelandPlatformInterface::initContext() { - if (m_appearanceContext.isNull()) { - m_appearanceContext.reset(new PersonalizationAppearanceContext(m_manager->get_appearance_context(), this)); - } - if (m_fontContext.isNull()) { - m_fontContext.reset(new PersonalizationFontContext(m_manager->get_font_context(), this)); - } + TreelandAppearance::instance()->m_interface = this; } QByteArray DTreelandPlatformInterface::iconThemeName() const @@ -74,7 +70,6 @@ QColor DTreelandPlatformInterface::activeColor() const QColor DTreelandPlatformInterface::darkActiveColor() const { - // treeland does not provide dark active color, return active color as fallback return m_activeColor; } @@ -95,44 +90,32 @@ int DTreelandPlatformInterface::windowRadius(int defaultValue) const void DTreelandPlatformInterface::setWindowRadius(int windowRadius) { - if (m_appearanceContext) { - m_appearanceContext->set_round_corner_radius(windowRadius); - } + Q_UNUSED(windowRadius) } void DTreelandPlatformInterface::setIconThemeName(const QByteArray &iconThemeName) { - if (m_appearanceContext) { - m_appearanceContext->set_icon_theme(iconThemeName); - } + Q_UNUSED(iconThemeName) } void DTreelandPlatformInterface::setFontName(const QByteArray &fontName) { - if (m_fontContext) { - m_fontContext->set_font(fontName); - } + Q_UNUSED(fontName) } void DTreelandPlatformInterface::setMonoFontName(const QByteArray &monoFontName) { - if (m_fontContext) { - m_fontContext->set_monospace_font(monoFontName); - } + Q_UNUSED(monoFontName) } void DTreelandPlatformInterface::setFontPointSize(qreal fontPointSize) { - if (m_fontContext) { - m_fontContext->set_font_size(fontPointSize); - } + Q_UNUSED(fontPointSize) } void DTreelandPlatformInterface::setActiveColor(const QColor activeColor) { - if (m_appearanceContext) { - m_appearanceContext->set_active_color(activeColor.name()); - } + Q_UNUSED(activeColor) } DGUI_END_NAMESPACE diff --git a/src/plugins/platform/treeland/dtreelandplatforminterface.h b/src/plugins/platform/treeland/dtreelandplatforminterface.h index 729b347b..646080aa 100644 --- a/src/plugins/platform/treeland/dtreelandplatforminterface.h +++ b/src/plugins/platform/treeland/dtreelandplatforminterface.h @@ -14,17 +14,12 @@ DGUI_BEGIN_NAMESPACE class DTreelandPlatformInterfacePrivate; -class PersonalizationManager; -class PersonalizationFontContext; -class PersonalizationAppearanceContext; -class PersonalizationWindowContext; +class TreelandAppearance; class DTreelandPlatformInterface : public QObject, public DPlatformInterface, public DCORE_NAMESPACE::DObject { Q_OBJECT - friend PersonalizationFontContext; - friend PersonalizationAppearanceContext; - friend PersonalizationWindowContext; + friend TreelandAppearance; public: explicit DTreelandPlatformInterface(DPlatformTheme *platformTheme); @@ -51,10 +46,6 @@ class DTreelandPlatformInterface : public QObject, public DPlatformInterface, pu void initContext(); private: - PersonalizationManager *m_manager; - QScopedPointer m_appearanceContext; - QScopedPointer m_fontContext; - QColor m_activeColor; int m_titleHeight; QByteArray m_fontName; @@ -65,7 +56,7 @@ class DTreelandPlatformInterface : public QObject, public DPlatformInterface, pu int m_windowRadius; int m_scrollBarPolicy; QByteArray m_themeName; - uint32_t m_blurOpacity; + qreal m_blurOpacity; }; DGUI_END_NAMESPACE diff --git a/src/plugins/platform/treeland/dtreelandplatformwindowinterface.cpp b/src/plugins/platform/treeland/dtreelandplatformwindowinterface.cpp index cf9b54af..331701b7 100644 --- a/src/plugins/platform/treeland/dtreelandplatformwindowinterface.cpp +++ b/src/plugins/platform/treeland/dtreelandplatformwindowinterface.cpp @@ -16,7 +16,8 @@ #include "dvtablehook.h" -#include "personalizationwaylandclientextension.h" +#include "treelanddecorationclientextension.h" +#include "treelandbackgroundeffectclientextension.h" DCORE_USE_NAMESPACE @@ -158,15 +159,6 @@ bool MoveWindowHelper::windowEvent(QWindow *w, QEvent *event) return ret; } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QPointF delta = me->globalPosition() - self->m_pressPoint; -#else - QPointF delta = me->globalPos() - self->m_pressPoint; -#endif - if (delta.manhattanLength() < QGuiApplication::styleHints()->startDragDistance()) { - return ret; - } - if (!self->m_windowMoving && self->m_enableSystemMove) { self->m_windowMoving = true; @@ -185,9 +177,10 @@ bool MoveWindowHelper::windowEvent(QWindow *w, QEvent *event) } QMap DTreeLandPlatformWindowHelper::windowMap; -DTreeLandPlatformWindowHelper *DTreeLandPlatformWindowHelper::get(QWindow *window) + +DTreeLandPlatformWindowHelper *DTreeLandPlatformWindowHelper::get(QWindow *window) { - if (!PersonalizationManager::instance()->isSupported()) { + if (!TreelandDecorationManager::instance()->isSupported()) { return nullptr; } @@ -208,9 +201,9 @@ DTreeLandPlatformWindowHelper::DTreeLandPlatformWindowHelper(QWindow *window) { window->installEventFilter(this); - if (!PersonalizationManager::instance()->isActive()) { - qWarning() << "Personalization is not active" << window; - connect(PersonalizationManager::instance(), &PersonalizationManager::activeChanged, this, &DTreeLandPlatformWindowHelper::onActiveChanged, Qt::QueuedConnection); + if (!TreelandDecorationManager::instance()->isActive()) { + qWarning() << "TreelandDecoration is not active" << window; + connect(TreelandDecorationManager::instance(), &TreelandDecorationManager::activeChanged, this, &DTreeLandPlatformWindowHelper::onActiveChanged, Qt::QueuedConnection); } if (window->handle()) { @@ -224,6 +217,10 @@ DTreeLandPlatformWindowHelper::~DTreeLandPlatformWindowHelper() delete m_windowContext; m_windowContext = nullptr; } + if (m_effectSurface) { + delete m_effectSurface; + m_effectSurface = nullptr; + } windowMap.remove(static_cast(parent())); } @@ -231,7 +228,7 @@ bool DTreeLandPlatformWindowHelper::eventFilter(QObject *watched, QEvent *event) if (event->type() == QEvent::PlatformSurface) { QPlatformSurfaceEvent *se = static_cast(event); if (se->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) { - if (PersonalizationManager::instance()->isActive()) { + if (TreelandDecorationManager::instance()->isActive()) { initWaylandWindow(); onSurfaceCreated(); } @@ -254,7 +251,7 @@ void DTreeLandPlatformWindowHelper::initWaylandWindow() void DTreeLandPlatformWindowHelper::onActiveChanged() { - if (PersonalizationManager::instance()->isActive()) { + if (TreelandDecorationManager::instance()->isActive()) { if (window()->handle()) { initWaylandWindow(); onSurfaceCreated(); @@ -265,6 +262,7 @@ void DTreeLandPlatformWindowHelper::onActiveChanged() void DTreeLandPlatformWindowHelper::onSurfaceCreated() { m_dirty = m_initialized; + m_blurDirty = true; scheduleApply(); } @@ -274,9 +272,13 @@ void DTreeLandPlatformWindowHelper::onSurfaceDestroyed() delete m_windowContext; m_windowContext = nullptr; } + if (m_effectSurface) { + delete m_effectSurface; + m_effectSurface = nullptr; + } } -PersonalizationWindowContext *DTreeLandPlatformWindowHelper::windowContext() const +TreelandDecorationContext *DTreeLandPlatformWindowHelper::windowContext() const { if (m_windowContext) { return m_windowContext; @@ -298,7 +300,7 @@ PersonalizationWindowContext *DTreeLandPlatformWindowHelper::windowContext() con } if (!m_windowContext) { - const_cast(this)->m_windowContext = new PersonalizationWindowContext(PersonalizationManager::instance()->get_window_context(surface)); + const_cast(this)->m_windowContext = new TreelandDecorationContext(TreelandDecorationManager::instance()->get_decoration_context(surface)); } return m_windowContext; @@ -341,7 +343,9 @@ void DTreeLandPlatformWindowHelper::setShadowColor(const QColor &shadowColor) void DTreeLandPlatformWindowHelper::setEnableBlurWindow(bool enableBlurWindow) { - updateFeature(m_blur, enableBlurWindow, Blur); + m_blurEnabled = enableBlurWindow; + m_blurDirty = true; + scheduleApply(); } void DTreeLandPlatformWindowHelper::setWindowEffect(DPlatformHandle::EffectScenes effectScene) @@ -354,6 +358,30 @@ void DTreeLandPlatformWindowHelper::setPlatformHandle(DPlatformHandle *handle) m_platformHandle = handle; } +void DTreeLandPlatformWindowHelper::setWindowBlurAreas(const QVector &areas) +{ + QRegion region; + for (const auto &area : areas) { + region += QRect(area.x, area.y, area.width, area.height); + } + m_blurRegion = region; + m_blurEnabled = true; + m_blurDirty = true; + scheduleApply(); +} + +void DTreeLandPlatformWindowHelper::setWindowBlurPaths(const QList &paths) +{ + QRegion region; + for (const auto &path : paths) { + region += QRegion(path.toFillPolygon().toPolygon()); + } + m_blurRegion = region; + m_blurEnabled = true; + m_blurDirty = true; + scheduleApply(); +} + void DTreeLandPlatformWindowHelper::scheduleApply() { if (m_applyScheduled) @@ -369,15 +397,11 @@ void DTreeLandPlatformWindowHelper::applyPending() if (auto context = windowContext()) { if (m_dirty & NoTitlebar) { m_dirty &= ~NoTitlebar; - context->set_titlebar(m_noTitlebar ? PersonalizationWindowContext::enable_mode_disable : PersonalizationWindowContext::enable_mode_enable); + context->set_titlebar_mode(m_noTitlebar ? titlebar_mode_hide : titlebar_mode_show); } if (m_dirty & Radius) { m_dirty &= ~Radius; - context->set_round_corner_radius(m_radius); - } - if (m_dirty & Blur) { - m_dirty &= ~Blur; - context->set_blend_mode(m_blur ? PersonalizationWindowContext::blend_mode_blur : PersonalizationWindowContext::blend_mode_transparent); + context->set_corner_radius(m_radius); } if (m_dirty & Border) { m_dirty &= ~Border; @@ -395,7 +419,7 @@ void DTreeLandPlatformWindowHelper::applyPending() if (m_dirty & WindowEffect) { m_dirty &= ~WindowEffect; if (m_effectScene.testFlag(DPlatformHandle::EffectNoRadius)) { - context->set_round_corner_radius(0); + context->set_corner_radius(0); } if (m_effectScene.testFlag(DPlatformHandle::EffectNoShadow)) { context->set_shadow(0, 0, 0, 0, 0, 0, 0); @@ -405,6 +429,40 @@ void DTreeLandPlatformWindowHelper::applyPending() } } } + + if (m_blurDirty) { + m_blurDirty = false; + if (m_blurEnabled && BackgroundEffectManager::instance()->isSupported() + && BackgroundEffectManager::instance()->hasBlurCapability()) { + if (!m_effectSurface) { + auto waylandWindow = dynamic_cast(window()->handle()); + if (waylandWindow && waylandWindow->waylandSurface()) { + auto surface = waylandWindow->waylandSurface()->object(); + if (surface) { + m_effectSurface = new BackgroundEffectSurface( + BackgroundEffectManager::instance()->get_background_effect(surface)); + } + } + } + if (m_effectSurface) { + if (m_blurRegion.isEmpty()) { + m_effectSurface->set_blur_region(nullptr); + } else { + auto waylandWindow = dynamic_cast(window()->handle()); + if (waylandWindow) { + auto wlRegion = waylandWindow->display()->createRegion(m_blurRegion); + m_effectSurface->set_blur_region(wlRegion); + wl_region_destroy(wlRegion); + } + } + } + } else { + if (m_effectSurface) { + delete m_effectSurface; + m_effectSurface = nullptr; + } + } + } } DTreeLandPlatformWindowInterface::DTreeLandPlatformWindowInterface(QWindow *window, DPlatformHandle *platformHandle, QObject *parent) @@ -576,4 +634,19 @@ void DTreeLandPlatformWindowInterface::setWindowEffect(DPlatformHandle::EffectSc Q_EMIT m_platformHandle->windowEffectChanged(); } } + +void DTreeLandPlatformWindowInterface::setWindowBlurAreas(const QVector &areas) +{ + if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { + helper->setWindowBlurAreas(areas); + } +} + +void DTreeLandPlatformWindowInterface::setWindowBlurPaths(const QList &paths) +{ + if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { + helper->setWindowBlurPaths(paths); + } +} + DGUI_END_NAMESPACE diff --git a/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h b/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h index 37413e82..b578deb6 100644 --- a/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h +++ b/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h @@ -8,11 +8,14 @@ #include "dtkgui_global.h" #include #include +#include +#include #include #include "private/dplatformwindowinterface_p.h" DGUI_BEGIN_NAMESPACE -class PersonalizationWindowContext; +class TreelandDecorationContext; +class BackgroundEffectSurface; class DTreeLandPlatformWindowHelper : public QObject { Q_OBJECT public: @@ -22,15 +25,14 @@ class DTreeLandPlatformWindowHelper : public QObject { enum Feature { NoTitlebar = 1 << 0, Radius = 1 << 1, - Blur = 1 << 2, - Border = 1 << 3, - Shadow = 1 << 4, - WindowEffect = 1 << 5, + Border = 1 << 2, + Shadow = 1 << 3, + WindowEffect = 1 << 4, }; Q_DECLARE_FLAGS(Features, Feature) QWindow *window() const { return qobject_cast(parent()); } - PersonalizationWindowContext *windowContext() const; + TreelandDecorationContext *windowContext() const; void setEnabledNoTitlebar(bool enable); void setWindowRadius(int windowRadius); @@ -42,6 +44,8 @@ class DTreeLandPlatformWindowHelper : public QObject { void setEnableBlurWindow(bool enableBlurWindow); void setWindowEffect(DPlatformHandle::EffectScenes effectScene); void setPlatformHandle(DPlatformHandle *handle); + void setWindowBlurAreas(const QVector &areas); + void setWindowBlurPaths(const QList &paths); bool isEnabledNoTitlebar() const { return m_noTitlebar; } int windowRadius() const { return m_radius; } @@ -50,7 +54,7 @@ class DTreeLandPlatformWindowHelper : public QObject { int shadowRadius() const { return m_shadowRadius; } QPoint shadowOffset() const { return m_shadowOffset; } QColor shadowColor() const { return m_shadowColor; } - bool enableBlurWindow() const { return m_blur; } + bool enableBlurWindow() const { return m_blurEnabled; } DPlatformHandle::EffectScenes windowEffect() const { return m_effectScene; } private slots: @@ -73,12 +77,15 @@ private slots: } private: - PersonalizationWindowContext *m_windowContext = nullptr; + TreelandDecorationContext *m_windowContext = nullptr; + BackgroundEffectSurface *m_effectSurface = nullptr; static QMap windowMap; DPlatformHandle *m_platformHandle = nullptr; bool m_noTitlebar = false; - bool m_blur = false; + bool m_blurEnabled = false; + QRegion m_blurRegion; + bool m_blurDirty = false; int m_radius = 0; int m_borderWidth = 0; QColor m_borderColor; @@ -123,6 +130,9 @@ class DTreeLandPlatformWindowInterface : public QObject, public DPlatformWindowI DPlatformHandle::EffectScene windowEffect() override; void setWindowEffect(DPlatformHandle::EffectScenes effectScene) override; + + void setWindowBlurAreas(const QVector &areas); + void setWindowBlurPaths(const QList &paths); }; DGUI_END_NAMESPACE diff --git a/src/plugins/platform/treeland/dtreelandwindowmanagerhelper.cpp b/src/plugins/platform/treeland/dtreelandwindowmanagerhelper.cpp index de73ca0d..61da0fd7 100644 --- a/src/plugins/platform/treeland/dtreelandwindowmanagerhelper.cpp +++ b/src/plugins/platform/treeland/dtreelandwindowmanagerhelper.cpp @@ -1,24 +1,28 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dtreelandwindowmanagerhelper.h" -#include "personalizationwaylandclientextension.h" +#include "treelandbackgroundeffectclientextension.h" +#include "treelanddecorationclientextension.h" DGUI_BEGIN_NAMESPACE TreelandWindowManagerHelper::TreelandWindowManagerHelper(QObject *parent) : DWindowManagerHelper(parent) { - connect(PersonalizationManager::instance(), &PersonalizationManager::activeChanged, this, [this](){ + connect(BackgroundEffectManager::instance(), &BackgroundEffectManager::blurCapabilityChanged, this, [this](){ Q_EMIT hasBlurWindowChanged(); + }); + connect(TreelandDecorationManager::instance(), &TreelandDecorationManager::activeChanged, this, [this](){ Q_EMIT hasNoTitlebarChanged(); }); } bool TreelandWindowManagerHelper::hasBlurWindow() const { - return PersonalizationManager::instance()->isSupported(); + return BackgroundEffectManager::instance()->isSupported() + && BackgroundEffectManager::instance()->hasBlurCapability(); } bool TreelandWindowManagerHelper::hasComposite() const @@ -28,7 +32,7 @@ bool TreelandWindowManagerHelper::hasComposite() const bool TreelandWindowManagerHelper::hasNoTitlebar() const { - return PersonalizationManager::instance()->isSupported(); + return TreelandDecorationManager::instance()->isSupported(); } DGUI_END_NAMESPACE diff --git a/src/plugins/platform/treeland/personalizationwaylandclientextension.cpp b/src/plugins/platform/treeland/personalizationwaylandclientextension.cpp deleted file mode 100644 index 085b37ea..00000000 --- a/src/plugins/platform/treeland/personalizationwaylandclientextension.cpp +++ /dev/null @@ -1,170 +0,0 @@ -// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#include "personalizationwaylandclientextension.h" - -#include -#include -#include -#include -#include "dplatformtheme.h" - -#include -#include -#include - -DGUI_BEGIN_NAMESPACE - -PersonalizationManager::PersonalizationManager() - : QWaylandClientExtensionTemplate(treeland_personalization_manager_v1_interface.version) - , m_isSupported(false) -{ - QtWaylandClient::QWaylandIntegration *waylandIntegration = static_cast(QGuiApplicationPrivate::platformIntegration()); - if (!waylandIntegration) { - qWarning() << "waylandIntegration is nullptr!!!"; - return; - } - m_waylandDisplay = waylandIntegration->display(); - if (m_waylandDisplay == nullptr) { - qWarning() << "waylandDisplay is nullptr!!!"; - return; - } - addListener(); - m_isSupported = m_waylandDisplay->hasRegistryGlobal(QString::fromUtf8(treeland_personalization_manager_v1_interface.name)); - if (!m_isSupported) { - qWarning() << "PersonalizationManager is not support"; - } -} - -void PersonalizationManager::addListener() -{ - m_waylandDisplay->addRegistryListener(&handleListenerGlobal, this); -} - -void PersonalizationManager::removeListener() -{ - m_waylandDisplay->removeListener(&handleListenerGlobal, this); -} - -void PersonalizationManager::handleListenerGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version) -{ - if (interface == treeland_personalization_manager_v1_interface.name) { - PersonalizationManager *integration = static_cast(data); - if (!integration) { - qWarning() << "integration is nullptr!!!"; - return; - } - - integration->init(registry, id, version); - } -} - -PersonalizationManager *PersonalizationManager::instance() -{ - static PersonalizationManager instance; - return &instance; -} - -PersonalizationWindowContext::PersonalizationWindowContext(struct ::treeland_personalization_window_context_v1 *context) - : QWaylandClientExtensionTemplate(treeland_personalization_window_context_v1_interface.version) - , QtWayland::treeland_personalization_window_context_v1(context) -{ - -} - -PersonalizationWindowContext::~PersonalizationWindowContext() -{ - if (isInitialized()) - destroy(); -} - -PersonalizationAppearanceContext::~PersonalizationAppearanceContext() -{ - if (isInitialized()) - destroy(); -} - -PersonalizationAppearanceContext::PersonalizationAppearanceContext(struct ::treeland_personalization_appearance_context_v1 *context, DTreelandPlatformInterface *interface) - : QWaylandClientExtensionTemplate(treeland_personalization_appearance_context_v1_interface.version) - , QtWayland::treeland_personalization_appearance_context_v1(context) - , m_interface(interface) -{ - get_round_corner_radius(); - get_icon_theme(); - get_active_color(); - get_window_theme_type(); - get_window_opacity(); -} - -void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_round_corner_radius(int32_t radius) -{ - m_interface->m_windowRadius = radius; - emit m_interface->m_platformTheme->windowRadiusChanged(radius); -} - -void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_icon_theme(const QString &theme_name) -{ - m_interface->m_iconThemeName = theme_name.toUtf8(); - emit m_interface->m_platformTheme->iconThemeNameChanged(theme_name.toUtf8()); -} - -void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_active_color(const QString &active_color) -{ - m_interface->m_activeColor = active_color; - emit m_interface->m_platformTheme->activeColorChanged(active_color); -} - -void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_window_theme_type(uint32_t type) -{ - QString theme = QStringLiteral("deepin"); - if (type == PersonalizationAppearanceContext::theme_type::theme_type_dark) { - theme = theme + QStringLiteral("-dark"); - } - m_interface->m_themeName = theme.toUtf8(); - emit m_interface->m_platformTheme->themeNameChanged(theme.toUtf8()); -} - -void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_window_opacity(uint32_t opacity) -{ - m_interface->m_blurOpacity = opacity; -} - -PersonalizationFontContext::~PersonalizationFontContext() -{ - if (isInitialized()) - destroy(); -} - -PersonalizationFontContext::PersonalizationFontContext(struct ::treeland_personalization_font_context_v1 *context, DTreelandPlatformInterface *interface) - : QWaylandClientExtensionTemplate(treeland_personalization_font_context_v1_interface.version) - , QtWayland::treeland_personalization_font_context_v1(context) - , m_interface(interface) -{ - get_font(); - get_monospace_font(); - get_font_size(); -} - -void PersonalizationFontContext::treeland_personalization_font_context_v1_font(const QString &font_name) -{ - m_interface->m_fontName = font_name.toUtf8(); - emit m_interface->m_platformTheme->fontNameChanged(font_name.toUtf8()); -} - -void PersonalizationFontContext::treeland_personalization_font_context_v1_monospace_font(const QString &font_name) -{ - m_interface->m_monoFontName = font_name.toUtf8(); - emit m_interface->m_platformTheme->monoFontNameChanged(font_name.toUtf8()); -} - -void PersonalizationFontContext::treeland_personalization_font_context_v1_font_size(uint32_t font_size) -{ - // treeland侧无法存储浮点数,约定 font_size 为 10 倍的 pointSize - qreal pointSize = font_size / 10.0; - pointSize = qBound(8.25, pointSize, 15.00); - m_interface->m_fontPointSize = pointSize; - emit m_interface->m_platformTheme->fontPointSizeChanged(pointSize); -} - -DGUI_END_NAMESPACE diff --git a/src/plugins/platform/treeland/personalizationwaylandclientextension.h b/src/plugins/platform/treeland/personalizationwaylandclientextension.h deleted file mode 100644 index 15634a57..00000000 --- a/src/plugins/platform/treeland/personalizationwaylandclientextension.h +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#ifndef PERSONALIZATIONWAYLANDCLIENTEXTENSION_H -#define PERSONALIZATIONWAYLANDCLIENTEXTENSION_H - -#include "dtreelandplatforminterface.h" -#include "qwayland-treeland-personalization-manager-v1.h" - -#include -#include - -#include -#include - -DGUI_BEGIN_NAMESPACE - -class PersonalizationAppearanceContext; -class PersonalizationCursorContext; -class PersonalizationFontContext; -class DTreelandPlatformInterfacePrivate; - -class PersonalizationManager: public QWaylandClientExtensionTemplate, - public QtWayland::treeland_personalization_manager_v1 -{ - Q_OBJECT -public: - static PersonalizationManager *instance(); - - [[nodiscard]]inline bool isSupported() const { return m_isSupported; } - -private: - void addListener(); - void removeListener(); - - explicit PersonalizationManager(); - static void handleListenerGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version); - -private: - QtWaylandClient::QWaylandDisplay *m_waylandDisplay; - bool m_isSupported; -}; - -class PersonalizationWindowContext : public QWaylandClientExtensionTemplate, - public QtWayland::treeland_personalization_window_context_v1 -{ - Q_OBJECT -public: - explicit PersonalizationWindowContext(struct ::treeland_personalization_window_context_v1 *context); - ~PersonalizationWindowContext() override; -}; - -class PersonalizationAppearanceContext : public QWaylandClientExtensionTemplate, - public QtWayland::treeland_personalization_appearance_context_v1 -{ - Q_OBJECT -public: - explicit PersonalizationAppearanceContext(struct ::treeland_personalization_appearance_context_v1 *context, DTreelandPlatformInterface *interface); - ~PersonalizationAppearanceContext() override; - -protected: - void treeland_personalization_appearance_context_v1_round_corner_radius(int32_t radius) override; - void treeland_personalization_appearance_context_v1_icon_theme(const QString &theme_name) override; - void treeland_personalization_appearance_context_v1_active_color(const QString &active_color) override; - void treeland_personalization_appearance_context_v1_window_theme_type(uint32_t type) override; - void treeland_personalization_appearance_context_v1_window_opacity(uint32_t opacity) override; -private: - DTreelandPlatformInterface *m_interface; -}; - -class PersonalizationFontContext : public QWaylandClientExtensionTemplate, - public QtWayland::treeland_personalization_font_context_v1 -{ - Q_OBJECT -public: - explicit PersonalizationFontContext(struct ::treeland_personalization_font_context_v1 *context, DTreelandPlatformInterface *interface); - ~PersonalizationFontContext() override; - -protected: - void treeland_personalization_font_context_v1_font(const QString &font_name) override; - void treeland_personalization_font_context_v1_monospace_font(const QString &font_name) override; - void treeland_personalization_font_context_v1_font_size(uint32_t font_size) override; -private: - DTreelandPlatformInterface *m_interface; -}; - -DGUI_END_NAMESPACE - -#endif // PERSONALIZATIONWAYLANDCLIENTEXTENSION_H diff --git a/src/plugins/platform/treeland/treelandappearanceclientextension.cpp b/src/plugins/platform/treeland/treelandappearanceclientextension.cpp new file mode 100644 index 00000000..cd04ba4d --- /dev/null +++ b/src/plugins/platform/treeland/treelandappearanceclientextension.cpp @@ -0,0 +1,156 @@ +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "treelandappearanceclientextension.h" + +#include +#include +#include +#include "dplatformtheme.h" + +#include +#include + +DGUI_BEGIN_NAMESPACE + +TreelandAppearance::TreelandAppearance() + : QWaylandClientExtensionTemplate(treeland_appearance_v1_interface.version) + , m_isSupported(false) + , m_interface(nullptr) +{ + QtWaylandClient::QWaylandIntegration *waylandIntegration = static_cast(QGuiApplicationPrivate::platformIntegration()); + if (!waylandIntegration) { + qWarning() << "waylandIntegration is nullptr!!!"; + return; + } + m_waylandDisplay = waylandIntegration->display(); + if (m_waylandDisplay == nullptr) { + qWarning() << "waylandDisplay is nullptr!!!"; + return; + } + addListener(); + m_isSupported = m_waylandDisplay->hasRegistryGlobal(QString::fromUtf8(treeland_appearance_v1_interface.name)); + if (!m_isSupported) { + qWarning() << "TreelandAppearance is not support"; + } +} + +void TreelandAppearance::addListener() +{ + m_waylandDisplay->addRegistryListener(&handleListenerGlobal, this); +} + +void TreelandAppearance::removeListener() +{ + m_waylandDisplay->removeListener(&handleListenerGlobal, this); +} + +void TreelandAppearance::handleListenerGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version) +{ + if (interface == treeland_appearance_v1_interface.name) { + TreelandAppearance *integration = static_cast(data); + if (!integration) { + qWarning() << "integration is nullptr!!!"; + return; + } + integration->init(registry, id, version); + } +} + +TreelandAppearance *TreelandAppearance::instance() +{ + static TreelandAppearance instance; + return &instance; +} + +void TreelandAppearance::treeland_appearance_v1_cursor_theme(const QString &name) +{ + Q_UNUSED(name) + // dtkgui currently has no public API for cursor theme; cache only if needed in future +} + +void TreelandAppearance::treeland_appearance_v1_cursor_size(uint32_t width, uint32_t height) +{ + Q_UNUSED(width) + Q_UNUSED(height) + // dtkgui currently has no public API for cursor size +} + +void TreelandAppearance::treeland_appearance_v1_font(const QString &font_name) +{ + if (m_interface) { + m_interface->m_fontName = font_name.toUtf8(); + emit m_interface->m_platformTheme->fontNameChanged(font_name.toUtf8()); + } +} + +void TreelandAppearance::treeland_appearance_v1_monospace_font(const QString &font_name) +{ + if (m_interface) { + m_interface->m_monoFontName = font_name.toUtf8(); + emit m_interface->m_platformTheme->monoFontNameChanged(font_name.toUtf8()); + } +} + +void TreelandAppearance::treeland_appearance_v1_font_size(uint32_t size) +{ + if (m_interface) { + // New protocol: font_size is in points directly, no longer 10x + qreal pointSize = static_cast(size); + m_interface->m_fontPointSize = pointSize; + emit m_interface->m_platformTheme->fontPointSizeChanged(pointSize); + } +} + +void TreelandAppearance::treeland_appearance_v1_icon_theme(const QString &theme_name) +{ + if (m_interface) { + m_interface->m_iconThemeName = theme_name.toUtf8(); + emit m_interface->m_platformTheme->iconThemeNameChanged(theme_name.toUtf8()); + } +} + +void TreelandAppearance::treeland_appearance_v1_accent_color(uint32_t r, uint32_t g, uint32_t b) +{ + if (m_interface) { + m_interface->m_activeColor = QColor(static_cast(r), static_cast(g), static_cast(b)); + emit m_interface->m_platformTheme->activeColorChanged(m_interface->m_activeColor); + } +} + +void TreelandAppearance::treeland_appearance_v1_window_opacity(wl_fixed_t opacity) +{ + if (m_interface) { + m_interface->m_blurOpacity = wl_fixed_to_double(opacity); + } +} + +void TreelandAppearance::treeland_appearance_v1_color_scheme(uint32_t scheme) +{ + if (m_interface) { + QString theme = QStringLiteral("deepin"); + if (scheme == static_cast(color_scheme_dark)) { + theme = theme + QStringLiteral("-dark"); + } + m_interface->m_themeName = theme.toUtf8(); + emit m_interface->m_platformTheme->themeNameChanged(theme.toUtf8()); + } +} + +void TreelandAppearance::treeland_appearance_v1_titlebar_height(uint32_t height) +{ + if (m_interface) { + m_interface->m_titleHeight = static_cast(height); + } +} + +void TreelandAppearance::treeland_appearance_v1_corner_radius(uint32_t radius) +{ + if (m_interface) { + m_interface->m_windowRadius = static_cast(radius); + emit m_interface->m_platformTheme->windowRadiusChanged(static_cast(radius)); + } +} + +DGUI_END_NAMESPACE diff --git a/src/plugins/platform/treeland/treelandappearanceclientextension.h b/src/plugins/platform/treeland/treelandappearanceclientextension.h new file mode 100644 index 00000000..88a73b2e --- /dev/null +++ b/src/plugins/platform/treeland/treelandappearanceclientextension.h @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef TREELANDAPPEARANCECLIENTEXTENSION_H +#define TREELANDAPPEARANCECLIENTEXTENSION_H + +#include "dtreelandplatforminterface.h" +#include "qwayland-treeland-appearance-unstable-v1.h" + +#include +#include + +#include +#include + +DGUI_BEGIN_NAMESPACE + +class DTreelandPlatformInterfacePrivate; + +class TreelandAppearance : public QWaylandClientExtensionTemplate, + public QtWayland::treeland_appearance_v1 +{ + Q_OBJECT + friend class DTreelandPlatformInterface; +public: + static TreelandAppearance *instance(); + + [[nodiscard]] inline bool isSupported() const { return m_isSupported; } + +private: + void addListener(); + void removeListener(); + + explicit TreelandAppearance(); + static void handleListenerGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version); + +protected: + void treeland_appearance_v1_cursor_theme(const QString &name) override; + void treeland_appearance_v1_cursor_size(uint32_t width, uint32_t height) override; + void treeland_appearance_v1_font(const QString &font_name) override; + void treeland_appearance_v1_monospace_font(const QString &font_name) override; + void treeland_appearance_v1_font_size(uint32_t size) override; + void treeland_appearance_v1_icon_theme(const QString &theme_name) override; + void treeland_appearance_v1_accent_color(uint32_t r, uint32_t g, uint32_t b) override; + void treeland_appearance_v1_window_opacity(wl_fixed_t opacity) override; + void treeland_appearance_v1_color_scheme(uint32_t scheme) override; + void treeland_appearance_v1_titlebar_height(uint32_t height) override; + void treeland_appearance_v1_corner_radius(uint32_t radius) override; + +private: + QtWaylandClient::QWaylandDisplay *m_waylandDisplay; + bool m_isSupported; + DTreelandPlatformInterface *m_interface; +}; + +DGUI_END_NAMESPACE + +#endif // TREELANDAPPEARANCECLIENTEXTENSION_H diff --git a/src/plugins/platform/treeland/treelandbackgroundeffectclientextension.cpp b/src/plugins/platform/treeland/treelandbackgroundeffectclientextension.cpp new file mode 100644 index 00000000..589a7943 --- /dev/null +++ b/src/plugins/platform/treeland/treelandbackgroundeffectclientextension.cpp @@ -0,0 +1,87 @@ +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "treelandbackgroundeffectclientextension.h" + +#include +#include +#include + +#include +#include + +DGUI_BEGIN_NAMESPACE + +BackgroundEffectManager::BackgroundEffectManager() + : QWaylandClientExtensionTemplate(ext_background_effect_manager_v1_interface.version) + , m_isSupported(false) + , m_hasBlurCapability(false) +{ + QtWaylandClient::QWaylandIntegration *waylandIntegration = static_cast(QGuiApplicationPrivate::platformIntegration()); + if (!waylandIntegration) { + qWarning() << "waylandIntegration is nullptr!!!"; + return; + } + m_waylandDisplay = waylandIntegration->display(); + if (m_waylandDisplay == nullptr) { + qWarning() << "waylandDisplay is nullptr!!!"; + return; + } + addListener(); + m_isSupported = m_waylandDisplay->hasRegistryGlobal(QString::fromUtf8(ext_background_effect_manager_v1_interface.name)); + if (!m_isSupported) { + qWarning() << "BackgroundEffectManager is not support"; + } +} + +void BackgroundEffectManager::addListener() +{ + m_waylandDisplay->addRegistryListener(&handleListenerGlobal, this); +} + +void BackgroundEffectManager::removeListener() +{ + m_waylandDisplay->removeListener(&handleListenerGlobal, this); +} + +void BackgroundEffectManager::handleListenerGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version) +{ + if (interface == ext_background_effect_manager_v1_interface.name) { + BackgroundEffectManager *integration = static_cast(data); + if (!integration) { + qWarning() << "integration is nullptr!!!"; + return; + } + integration->init(registry, id, version); + } +} + +BackgroundEffectManager *BackgroundEffectManager::instance() +{ + static BackgroundEffectManager instance; + return &instance; +} + +void BackgroundEffectManager::ext_background_effect_manager_v1_capabilities(uint32_t flags) +{ + bool hadBlur = m_hasBlurCapability; + m_hasBlurCapability = (flags & static_cast(capability_blur)) != 0; + if (hadBlur != m_hasBlurCapability) { + emit blurCapabilityChanged(); + } +} + +BackgroundEffectSurface::BackgroundEffectSurface(struct ::ext_background_effect_surface_v1 *surface) + : QWaylandClientExtensionTemplate(ext_background_effect_surface_v1_interface.version) + , QtWayland::ext_background_effect_surface_v1(surface) +{ +} + +BackgroundEffectSurface::~BackgroundEffectSurface() +{ + if (isInitialized()) + destroy(); +} + +DGUI_END_NAMESPACE diff --git a/src/plugins/platform/treeland/treelandbackgroundeffectclientextension.h b/src/plugins/platform/treeland/treelandbackgroundeffectclientextension.h new file mode 100644 index 00000000..b2f99c67 --- /dev/null +++ b/src/plugins/platform/treeland/treelandbackgroundeffectclientextension.h @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef TREELANDBACKGROUNDEFFECTCLIENTEXTENSION_H +#define TREELANDBACKGROUNDEFFECTCLIENTEXTENSION_H + +#include "qwayland-ext-background-effect-v1.h" + +#include +#include + +#include +#include + +DGUI_BEGIN_NAMESPACE + +class BackgroundEffectManager : public QWaylandClientExtensionTemplate, + public QtWayland::ext_background_effect_manager_v1 +{ + Q_OBJECT +public: + static BackgroundEffectManager *instance(); + + [[nodiscard]] inline bool isSupported() const { return m_isSupported; } + [[nodiscard]] inline bool hasBlurCapability() const { return m_hasBlurCapability; } + +Q_SIGNALS: + void blurCapabilityChanged(); + +private: + void addListener(); + void removeListener(); + + explicit BackgroundEffectManager(); + static void handleListenerGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version); + +protected: + void ext_background_effect_manager_v1_capabilities(uint32_t flags) override; + +private: + QtWaylandClient::QWaylandDisplay *m_waylandDisplay; + bool m_isSupported; + bool m_hasBlurCapability; +}; + +class BackgroundEffectSurface : public QWaylandClientExtensionTemplate, + public QtWayland::ext_background_effect_surface_v1 +{ + Q_OBJECT +public: + explicit BackgroundEffectSurface(struct ::ext_background_effect_surface_v1 *surface); + ~BackgroundEffectSurface() override; +}; + +DGUI_END_NAMESPACE + +#endif // TREELANDBACKGROUNDEFFECTCLIENTEXTENSION_H diff --git a/src/plugins/platform/treeland/treelanddecorationclientextension.cpp b/src/plugins/platform/treeland/treelanddecorationclientextension.cpp new file mode 100644 index 00000000..b80baa39 --- /dev/null +++ b/src/plugins/platform/treeland/treelanddecorationclientextension.cpp @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "treelanddecorationclientextension.h" + +#include +#include +#include + +#include +#include + +DGUI_BEGIN_NAMESPACE + +TreelandDecorationManager::TreelandDecorationManager() + : QWaylandClientExtensionTemplate(treeland_decoration_manager_v1_interface.version) + , m_isSupported(false) +{ + QtWaylandClient::QWaylandIntegration *waylandIntegration = static_cast(QGuiApplicationPrivate::platformIntegration()); + if (!waylandIntegration) { + qWarning() << "waylandIntegration is nullptr!!!"; + return; + } + m_waylandDisplay = waylandIntegration->display(); + if (m_waylandDisplay == nullptr) { + qWarning() << "waylandDisplay is nullptr!!!"; + return; + } + addListener(); + m_isSupported = m_waylandDisplay->hasRegistryGlobal(QString::fromUtf8(treeland_decoration_manager_v1_interface.name)); + if (!m_isSupported) { + qWarning() << "TreelandDecorationManager is not support"; + } +} + +void TreelandDecorationManager::addListener() +{ + m_waylandDisplay->addRegistryListener(&handleListenerGlobal, this); +} + +void TreelandDecorationManager::removeListener() +{ + m_waylandDisplay->removeListener(&handleListenerGlobal, this); +} + +void TreelandDecorationManager::handleListenerGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version) +{ + if (interface == treeland_decoration_manager_v1_interface.name) { + TreelandDecorationManager *integration = static_cast(data); + if (!integration) { + qWarning() << "integration is nullptr!!!"; + return; + } + integration->init(registry, id, version); + } +} + +TreelandDecorationManager *TreelandDecorationManager::instance() +{ + static TreelandDecorationManager instance; + return &instance; +} + +TreelandDecorationContext::TreelandDecorationContext(struct ::treeland_decoration_context_v1 *context) + : QWaylandClientExtensionTemplate(treeland_decoration_context_v1_interface.version) + , QtWayland::treeland_decoration_context_v1(context) +{ +} + +TreelandDecorationContext::~TreelandDecorationContext() +{ + if (isInitialized()) + destroy(); +} + +DGUI_END_NAMESPACE diff --git a/src/plugins/platform/treeland/treelanddecorationclientextension.h b/src/plugins/platform/treeland/treelanddecorationclientextension.h new file mode 100644 index 00000000..4b5abeb9 --- /dev/null +++ b/src/plugins/platform/treeland/treelanddecorationclientextension.h @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef TREELANDDECORATIONCLIENTEXTENSION_H +#define TREELANDDECORATIONCLIENTEXTENSION_H + +#include "qwayland-treeland-decoration-unstable-v1.h" + +#include +#include + +#include +#include + +DGUI_BEGIN_NAMESPACE + +class TreelandDecorationManager : public QWaylandClientExtensionTemplate, + public QtWayland::treeland_decoration_manager_v1 +{ + Q_OBJECT +public: + static TreelandDecorationManager *instance(); + + [[nodiscard]] inline bool isSupported() const { return m_isSupported; } + +private: + void addListener(); + void removeListener(); + + explicit TreelandDecorationManager(); + static void handleListenerGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version); + +private: + QtWaylandClient::QWaylandDisplay *m_waylandDisplay; + bool m_isSupported; +}; + +class TreelandDecorationContext : public QWaylandClientExtensionTemplate, + public QtWayland::treeland_decoration_context_v1 +{ + Q_OBJECT +public: + explicit TreelandDecorationContext(struct ::treeland_decoration_context_v1 *context); + ~TreelandDecorationContext() override; +}; + +DGUI_END_NAMESPACE + +#endif // TREELANDDECORATIONCLIENTEXTENSION_H diff --git a/src/plugins/plugins.cmake b/src/plugins/plugins.cmake index bfaa5b47..bdc8ad61 100644 --- a/src/plugins/plugins.cmake +++ b/src/plugins/plugins.cmake @@ -58,23 +58,34 @@ if(NOT DTK_DISABLE_TREELAND) find_package(TreelandProtocols) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS WaylandClient) set(TreelandProtocols_FOUND ${TreelandProtocols_FOUND}) + find_package(ECM REQUIRED NO_MODULE) + set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${ECM_MODULE_PATH}") + find_package(WaylandProtocols) endif() if(NOT DTK_DISABLE_TREELAND AND TreelandProtocols_FOUND) message("Support Treeland!") if("${QT_VERSION_MAJOR}" STREQUAL "6") qt6_generate_wayland_protocol_client_sources(${LIB_NAME} FILES - ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-personalization-manager-v1.xml + ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-appearance-unstable-v1.xml + ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-decoration-unstable-v1.xml + ${WaylandProtocols_DATADIR}/staging/ext-background-effect/ext-background-effect-v1.xml ) else() # ECM setup include(FeatureSummary) - find_package(ECM REQUIRED NO_MODULE) - set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${ECM_MODULE_PATH}") find_package(QtWaylandScanner) ecm_add_qtwayland_client_protocol(CLIENT_LIB_SRCS - PROTOCOL ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-personalization-manager-v1.xml - BASENAME treeland-personalization-manager-v1 + PROTOCOL ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-appearance-unstable-v1.xml + BASENAME treeland-appearance-unstable-v1 + ) + ecm_add_qtwayland_client_protocol(CLIENT_LIB_SRCS + PROTOCOL ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-decoration-unstable-v1.xml + BASENAME treeland-decoration-unstable-v1 + ) + ecm_add_qtwayland_client_protocol(CLIENT_LIB_SRCS + PROTOCOL ${WaylandProtocols_DATADIR}/staging/ext-background-effect/ext-background-effect-v1.xml + BASENAME ext-background-effect-v1 ) target_sources(${LIB_NAME} PRIVATE ${CLIENT_LIB_SRCS} From abd732f67820fd034afbeb2b236155d6758ad45d Mon Sep 17 00:00:00 2001 From: yeshanshan Date: Mon, 28 Sep 2026 13:17:31 +0800 Subject: [PATCH 2/3] fix: align code with treeland-protocols 0.6.0 API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: 对齐 treeland-protocols 0.6.0 协议 API 1. Fix accent_color override signature to 4 params (r, g, b, a) to match treeland_appearance_v1 base class generated by 0.6.0 protocol 2. Qualify titlebar_mode enum references with TreelandDecorationContext:: scope in dtreelandplatformwindowinterface.cpp 3. Update debian/control treeland-protocols dependency from >= 0.7.0 to >= 0.6.0 (0.7.0 does not exist upstream) 1. 修复 accent_color 重写签名为 4 参数 (r, g, b, a),匹配 0.6.0 协议 生成的 treeland_appearance_v1 基类签名 2. 在 dtreelandplatformwindowinterface.cpp 中为 titlebar_mode 枚举引用 添加 TreelandDecorationContext:: 作用域限定 3. 更新 debian/control 中 treeland-protocols 依赖从 >= 0.7.0 改为 >= 0.6.0(上游不存在 0.7.0 版本) Log: treeland-protocols 上游最高版本为 0.6.0,代码针对不存在的 0.7.0 API 编写导致编译失败,需对齐 0.6.0 协议 API Influence: dtkgui Treeland 平台插件编译修复,影响 accent_color 签名和 titlebar_mode 枚举作用域 --- debian/control | 2 +- .../platform/treeland/dtreelandplatformwindowinterface.cpp | 2 +- .../platform/treeland/treelandappearanceclientextension.cpp | 4 ++-- .../platform/treeland/treelandappearanceclientextension.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/debian/control b/debian/control index 7cc69635..8efc408f 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,7 @@ Build-Depends: debhelper-compat (= 12), libgmock-dev, libdtkcommon-dev, librsvg2-dev, - treeland-protocols (>= 0.7.0), + treeland-protocols (>= 0.6.0), extra-cmake-modules, libdtkdata, libdtkcore-dev , diff --git a/src/plugins/platform/treeland/dtreelandplatformwindowinterface.cpp b/src/plugins/platform/treeland/dtreelandplatformwindowinterface.cpp index 331701b7..34510a77 100644 --- a/src/plugins/platform/treeland/dtreelandplatformwindowinterface.cpp +++ b/src/plugins/platform/treeland/dtreelandplatformwindowinterface.cpp @@ -397,7 +397,7 @@ void DTreeLandPlatformWindowHelper::applyPending() if (auto context = windowContext()) { if (m_dirty & NoTitlebar) { m_dirty &= ~NoTitlebar; - context->set_titlebar_mode(m_noTitlebar ? titlebar_mode_hide : titlebar_mode_show); + context->set_titlebar_mode(m_noTitlebar ? TreelandDecorationContext::titlebar_mode_hide : TreelandDecorationContext::titlebar_mode_show); } if (m_dirty & Radius) { m_dirty &= ~Radius; diff --git a/src/plugins/platform/treeland/treelandappearanceclientextension.cpp b/src/plugins/platform/treeland/treelandappearanceclientextension.cpp index cd04ba4d..bffba303 100644 --- a/src/plugins/platform/treeland/treelandappearanceclientextension.cpp +++ b/src/plugins/platform/treeland/treelandappearanceclientextension.cpp @@ -111,10 +111,10 @@ void TreelandAppearance::treeland_appearance_v1_icon_theme(const QString &theme_ } } -void TreelandAppearance::treeland_appearance_v1_accent_color(uint32_t r, uint32_t g, uint32_t b) +void TreelandAppearance::treeland_appearance_v1_accent_color(uint32_t r, uint32_t g, uint32_t b, uint32_t a) { if (m_interface) { - m_interface->m_activeColor = QColor(static_cast(r), static_cast(g), static_cast(b)); + m_interface->m_activeColor = QColor(static_cast(r), static_cast(g), static_cast(b), static_cast(a)); emit m_interface->m_platformTheme->activeColorChanged(m_interface->m_activeColor); } } diff --git a/src/plugins/platform/treeland/treelandappearanceclientextension.h b/src/plugins/platform/treeland/treelandappearanceclientextension.h index 88a73b2e..5e4a192c 100644 --- a/src/plugins/platform/treeland/treelandappearanceclientextension.h +++ b/src/plugins/platform/treeland/treelandappearanceclientextension.h @@ -42,7 +42,7 @@ class TreelandAppearance : public QWaylandClientExtensionTemplate Date: Tue, 13 Oct 2026 17:30:10 +0800 Subject: [PATCH 3/3] fix: fix protocol destruction, CMake variables and uninitialized members MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: 修复协议析构、CMake 变量缩进和未初始化成员变量 1. Add DTreelandPlatformInterface destructor to null out TreelandAppearance::m_interface, preventing use-after-free when the interface is destroyed but the singleton still receives Wayland events 2. Add in-class initializers (= {}) for m_effectScene, m_initialized and m_dirty in DTreeLandPlatformWindowHelper 3. Add nullptr initializer for m_waylandDisplay in TreelandAppearance, TreelandDecorationManager and BackgroundEffectManager 4. Fix indentation of qt6_generate_wayland_protocol_client_sources call in plugins.cmake for consistency 1. 添加 DTreelandPlatformInterface 析构函数,在析构时将 TreelandAppearance::m_interface 置空,避免接口对象销毁后 单例仍接收 Wayland 事件导致 use-after-free 2. 为 DTreeLandPlatformWindowHelper 的 m_effectScene、m_initialized 和 m_dirty 添加类内初始化 (= {}) 3. 为 TreelandAppearance、TreelandDecorationManager 和 BackgroundEffectManager 的 m_waylandDisplay 添加 nullptr 初始化 4. 修复 plugins.cmake 中 qt6_generate_wayland_protocol_client_sources 调用的缩进,保持一致性 Log: 用户 PR 审核反馈协议析构、CMake 变量和变量定义三方面问题,排查后修复 use-after-free 风险、未初始化成员变量和 CMake 缩进 Influence: dtkgui Treeland 平台插件协议对象生命周期安全性和代码规范修复 --- .../platform/treeland/dtreelandplatforminterface.cpp | 5 +++++ .../platform/treeland/dtreelandplatforminterface.h | 1 + .../platform/treeland/dtreelandplatformwindowinterface.h | 6 +++--- .../platform/treeland/treelandappearanceclientextension.h | 2 +- .../treeland/treelandbackgroundeffectclientextension.h | 2 +- .../platform/treeland/treelanddecorationclientextension.h | 2 +- src/plugins/plugins.cmake | 8 ++++---- 7 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/plugins/platform/treeland/dtreelandplatforminterface.cpp b/src/plugins/platform/treeland/dtreelandplatforminterface.cpp index b73e3aac..c3447fb5 100644 --- a/src/plugins/platform/treeland/dtreelandplatforminterface.cpp +++ b/src/plugins/platform/treeland/dtreelandplatforminterface.cpp @@ -38,6 +38,11 @@ DTreelandPlatformInterface::DTreelandPlatformInterface(DPlatformTheme *platformT } } +DTreelandPlatformInterface::~DTreelandPlatformInterface() +{ + TreelandAppearance::instance()->m_interface = nullptr; +} + void DTreelandPlatformInterface::initContext() { TreelandAppearance::instance()->m_interface = this; diff --git a/src/plugins/platform/treeland/dtreelandplatforminterface.h b/src/plugins/platform/treeland/dtreelandplatforminterface.h index 646080aa..f8185086 100644 --- a/src/plugins/platform/treeland/dtreelandplatforminterface.h +++ b/src/plugins/platform/treeland/dtreelandplatforminterface.h @@ -22,6 +22,7 @@ class DTreelandPlatformInterface : public QObject, public DPlatformInterface, pu friend TreelandAppearance; public: explicit DTreelandPlatformInterface(DPlatformTheme *platformTheme); + ~DTreelandPlatformInterface() override; QByteArray iconThemeName() const override; QByteArray fontName() const override; diff --git a/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h b/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h index b578deb6..d494008b 100644 --- a/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h +++ b/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h @@ -92,9 +92,9 @@ private slots: int m_shadowRadius = 0; QPoint m_shadowOffset; QColor m_shadowColor; - DPlatformHandle::EffectScenes m_effectScene; - Features m_initialized; - Features m_dirty; + DPlatformHandle::EffectScenes m_effectScene = {}; + Features m_initialized = {}; + Features m_dirty = {}; bool m_applyScheduled = false; }; diff --git a/src/plugins/platform/treeland/treelandappearanceclientextension.h b/src/plugins/platform/treeland/treelandappearanceclientextension.h index 5e4a192c..0306932a 100644 --- a/src/plugins/platform/treeland/treelandappearanceclientextension.h +++ b/src/plugins/platform/treeland/treelandappearanceclientextension.h @@ -49,7 +49,7 @@ class TreelandAppearance : public QWaylandClientExtensionTemplate