From 02ac5910bf0976f20fd4cc045dc2561e4faf5675 Mon Sep 17 00:00:00 2001 From: yeshanshan Date: Fri, 16 Oct 2026 18:06:47 +0800 Subject: [PATCH] feat: adapt Treeland 0.7.0 protocol split MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Split the monolithic treeland-personalization-manager-v1 protocol into three dedicated implementations: appearance (treeland-appearance- unstable-v1), decoration (treeland-decoration-unstable-v1), and background effect (ext-background-effect-v1) 2. Add new TreelandAppearance client extension to handle appearance properties including font, font size (point size divided by 10 with clamping to 8.25-15.00pt), icon theme, accent color, window opacity, color scheme, titlebar height, and corner radius 3. Add new TreelandDecorationManager and TreelandDecorationContext to handle window decoration properties like titlebar mode, corner radius, border, and shadow 4. Add new BackgroundEffectManager and BackgroundEffectSurface to handle blur window and blur region functionality with capability detection 5. Refactor DTreeLandPlatformWindowHelper to use separate feature flags for BlurWindow and BlurRegion, storing them independently 6. Apply decoration only after the surface's first configure (check isExposed) to avoid overriding xdg-decoration negotiation 7. Update DPlatformHandle to route blur area and blur path calls to the new DTreeLandPlatformWindowInterface methods 8. Update treeland window manager helper to check decoration and background effect managers separately for hasNoTitlebar and hasBlurWindow 9. Update build dependencies to require treeland-protocols >= 0.7.0 and wayland-protocols >= 1.45 10. Update CMake to scan the three new protocol XML files for both Qt6 and Qt5 builds 11. Remove obsolete personalizationwaylandclientextension files 12. Preserve uniform window lifecycle and property scheduling logic while adding repositioning drag threshold handling Log: Adapted to Treeland 0.7.0 split protocols for appearance, decoration, and background effect; separated blur window toggle from blur region with independent saving; applied decoration after first surface configure Influence: 1. Verify window decoration properties (titlebar, corner radius, border, shadow) apply correctly on freshly created windows 2. Test blur window toggle and blur region independently - enabling one should not affect the other 3. Verify blur area and blur path APIs route to background effect protocol on Treeland 4. Test window resizing when blur window is enabled to ensure blur region updates 5. Verify font size handling still divides by 10 and clamps to 8.25- 15.00pt range 6. Test window dragging with the updated manhattan length threshold logic 7. Verify fallback behavior when Treeland protocols are unsupported (returns false/empty values) 8. Check that decoration changes are not applied before the window is exposed 9. Test blur capability changes triggering re-application of blur state 10. Verify build succeeds with treeland-protocols 0.7.0 and wayland- protocols 1.45 feat: 适配 Treeland 0.7.0 协议拆分 1. 将单一的 treeland-personalization-manager-v1 协议拆分为三个独立实 现:appearance(treeland-appearance-unstable-v1)、decoration(treeland- decoration-unstable-v1)和 background effect(ext-background-effect-v1) 2. 新增 TreelandAppearance 客户端扩展,处理外观属性,包括字体、字号 (pointSize 除以 10 并限制在 8.25-15.00pt 范围内)、图标主题、强调色、窗 口不透明度、配色方案、标题栏高度和圆角半径 3. 新增 TreelandDecorationManager 和 TreelandDecorationContext,处理窗口 装饰属性,如标题栏模式、圆角半径、边框和阴影 4. 新增 BackgroundEffectManager 和 BackgroundEffectSurface,处理全窗模糊 和局部区域模糊功能,并支持能力检测 5. 重构 DTreeLandPlatformWindowHelper,使用独立的特性标记 BlurWindow 和 BlurRegion,并分别保存 6. 在 surface 首次 configure 完成后(检查 isExposed)才应用装饰,避免覆 盖 xdg-decoration 协商结果 7. 更新 DPlatformHandle,将模糊区域和模糊路径的调用路由到新的 DTreeLandPlatformWindowInterface 方法 8. 更新 treeland 窗口管理器辅助类,分别检查 decoration 和 background effect 管理器以确定 hasNoTitlebar 和 hasBlurWindow 9. 更新构建依赖,要求 treeland-protocols >= 0.7.0 和 wayland-protocols >= 1.45 10. 更新 CMake,为 Qt6 和 Qt5 构建扫描三个新的协议 XML 文件 11. 移除废弃的 personalizationwaylandclientextension 文件 12. 保留统一窗口生命周期和属性调度逻辑,同时增加拖拽重定位阈值处理 Log: 适配 Treeland 0.7.0 拆分协议,涵盖 appearance、decoration 和 background effect;全窗模糊开关与局部区域模糊独立保存;首次 surface 配置 完成后应用装饰 Influence: 1. 验证窗口装饰属性(标题栏、圆角、边框、阴影)在新建窗口上正确应用 2. 单独测试全窗模糊开关和局部区域模糊 - 启用其中一个不应影响另一个 3. 验证模糊区域和模糊路径 API 在 Treeland 上正确路由到 background effect 协议 4. 启用全窗模糊时测试窗口缩放,确保模糊区域正确更新 5. 验证字号处理逻辑仍除以 10 并限制在 8.25-15.00pt 范围内 6. 使用更新后的曼哈顿距离阈值逻辑测试窗口拖拽功能 7. 验证 Treeland 协议不支持时的回退行为(返回 false/空值) 8. 检查窗口未 exposed 前装饰变更不会被应用 9. 测试模糊能力变化触发模糊状态重新应用 10. 验证使用 treeland-protocols 0.7.0 和 wayland-protocols 1.45 构建成功 PMS: TASK-396717 --- debian/control | 3 +- src/kernel/dplatformhandle.cpp | 12 + .../config.tests/treeland_test/CMakeLists.txt | 29 ++- .../config.tests/treeland_test/main.cpp | 16 +- .../treeland/dtreelandplatforminterface.cpp | 47 +--- .../treeland/dtreelandplatforminterface.h | 19 +- .../dtreelandplatformwindowinterface.cpp | 243 ++++++++++++++---- .../dtreelandplatformwindowinterface.h | 43 +++- .../treeland/dtreelandwindowmanagerhelper.cpp | 14 +- .../personalizationwaylandclientextension.cpp | 170 ------------ .../personalizationwaylandclientextension.h | 90 ------- .../treelandappearanceclientextension.cpp | 114 ++++++++ .../treelandappearanceclientextension.h | 47 ++++ ...reelandbackgroundeffectclientextension.cpp | 94 +++++++ .../treelandbackgroundeffectclientextension.h | 61 +++++ .../treelanddecorationclientextension.cpp | 77 ++++++ .../treelanddecorationclientextension.h | 50 ++++ src/plugins/plugins.cmake | 25 +- 18 files changed, 748 insertions(+), 406 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..e3817f57 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,8 @@ Build-Depends: debhelper-compat (= 12), libgmock-dev, libdtkcommon-dev, librsvg2-dev, - treeland-protocols (>>0.5.8), + treeland-protocols (>= 0.7.0), + wayland-protocols (>= 1.45), 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..d608e09f 100644 --- a/src/plugins/platform/config.tests/treeland_test/CMakeLists.txt +++ b/src/plugins/platform/config.tests/treeland_test/CMakeLists.txt @@ -1,4 +1,4 @@ -# 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 @@ -19,14 +19,19 @@ endif() find_package(PkgConfig REQUIRED) pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client) -find_package(TreelandProtocols) +find_package(TreelandProtocols 0.7.0 REQUIRED) set(TreelandProtocols_FOUND ${TreelandProtocols_FOUND}) +find_package(ECM REQUIRED NO_MODULE) +set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${ECM_MODULE_PATH}") +find_package(WaylandProtocols 1.45 REQUIRED) 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..fb231524 100644 --- a/src/plugins/platform/config.tests/treeland_test/main.cpp +++ b/src/plugins/platform/config.tests/treeland_test/main.cpp @@ -1,4 +1,4 @@ -// 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 @@ -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..b40a0f2a 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,25 +26,12 @@ 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()) { - initContext(); - } - }); + new TreelandAppearance(this); } -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)); - } -} +DTreelandPlatformInterface::~DTreelandPlatformInterface() = default; QByteArray DTreelandPlatformInterface::iconThemeName() const { @@ -74,7 +60,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 +80,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..0b40f6af 100644 --- a/src/plugins/platform/treeland/dtreelandplatforminterface.h +++ b/src/plugins/platform/treeland/dtreelandplatforminterface.h @@ -14,19 +14,15 @@ 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); + ~DTreelandPlatformInterface() override; QByteArray iconThemeName() const override; QByteArray fontName() const override; @@ -48,13 +44,6 @@ class DTreelandPlatformInterface : public QObject, public DPlatformInterface, pu void setActiveColor(const QColor activeColor) override; private: - void initContext(); - -private: - PersonalizationManager *m_manager; - QScopedPointer m_appearanceContext; - QScopedPointer m_fontContext; - QColor m_activeColor; int m_titleHeight; QByteArray m_fontName; @@ -65,7 +54,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..8ae1b476 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 @@ -123,6 +124,11 @@ bool MoveWindowHelper::windowEvent(QWindow *w, QEvent *event) if (delta.manhattanLength() < QGuiApplication::styleHints()->startDragDistance()) { return DVtableHook::callOriginalFun(w, qWindowEventMember(), event); } + + if (!self->m_pressPoint.isNull() + && (currentPos - self->m_pressPoint).manhattanLength() < QGuiApplication::styleHints()->startDragDistance()) { + return DVtableHook::callOriginalFun(w, qWindowEventMember(), event); + } } bool is_mouse_move = event->type() == QEvent::MouseMove @@ -158,15 +164,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,12 +182,9 @@ bool MoveWindowHelper::windowEvent(QWindow *w, QEvent *event) } QMap DTreeLandPlatformWindowHelper::windowMap; -DTreeLandPlatformWindowHelper *DTreeLandPlatformWindowHelper::get(QWindow *window) -{ - if (!PersonalizationManager::instance()->isSupported()) { - return nullptr; - } +DTreeLandPlatformWindowHelper *DTreeLandPlatformWindowHelper::get(QWindow *window) +{ if (!window) { return nullptr; } @@ -208,9 +202,19 @@ 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); + connect(BackgroundEffectManager::instance(), &BackgroundEffectManager::blurCapabilityChanged, + this, [this] { + const auto initializedBlur = m_initialized & (Features(BlurWindow) | BlurRegion); + if (initializedBlur) { + m_dirty |= initializedBlur; + scheduleApply(); + } + }); + + if (TreelandDecorationManager::instance()->isSupported() + && !TreelandDecorationManager::instance()->isActive()) { + // Activation is queued by QWaylandClientExtension; retry when it completes. + connect(TreelandDecorationManager::instance(), &TreelandDecorationManager::activeChanged, this, &DTreeLandPlatformWindowHelper::onActiveChanged, Qt::QueuedConnection); } if (window->handle()) { @@ -220,21 +224,28 @@ DTreeLandPlatformWindowHelper::DTreeLandPlatformWindowHelper(QWindow *window) DTreeLandPlatformWindowHelper::~DTreeLandPlatformWindowHelper() { - if (m_windowContext) { - delete m_windowContext; - m_windowContext = nullptr; + if (m_decorationContext) { + delete m_decorationContext; + m_decorationContext = nullptr; } windowMap.remove(static_cast(parent())); + delete m_backgroundEffectSurface; + m_backgroundEffectSurface = nullptr; } bool DTreeLandPlatformWindowHelper::eventFilter(QObject *watched, QEvent *event) { + if (event->type() == QEvent::Expose && m_dirty) { + scheduleApply(); + } + if (event->type() == QEvent::Resize && m_blurWindowEnabled) { + m_dirty |= BlurWindow; + scheduleApply(); + } if (event->type() == QEvent::PlatformSurface) { QPlatformSurfaceEvent *se = static_cast(event); if (se->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) { - if (PersonalizationManager::instance()->isActive()) { - initWaylandWindow(); - onSurfaceCreated(); - } + initWaylandWindow(); + onSurfaceCreated(); } } return QObject::eventFilter(watched, event); @@ -254,7 +265,7 @@ void DTreeLandPlatformWindowHelper::initWaylandWindow() void DTreeLandPlatformWindowHelper::onActiveChanged() { - if (PersonalizationManager::instance()->isActive()) { + if (TreelandDecorationManager::instance()->isActive()) { if (window()->handle()) { initWaylandWindow(); onSurfaceCreated(); @@ -270,20 +281,28 @@ void DTreeLandPlatformWindowHelper::onSurfaceCreated() void DTreeLandPlatformWindowHelper::onSurfaceDestroyed() { - if (m_windowContext) { - delete m_windowContext; - m_windowContext = nullptr; + if (m_decorationContext) { + delete m_decorationContext; + m_decorationContext = nullptr; } + delete m_backgroundEffectSurface; + m_backgroundEffectSurface = nullptr; } -PersonalizationWindowContext *DTreeLandPlatformWindowHelper::windowContext() const +TreelandDecorationContext *DTreeLandPlatformWindowHelper::decorationContext() const { - if (m_windowContext) { - return m_windowContext; + if (m_decorationContext) { + return m_decorationContext; } + auto manager = TreelandDecorationManager::instance(); + if (!manager->isSupported() || !manager->isInitialized()) + return nullptr; + auto waylandWindow = dynamic_cast(window()->handle()); - if (!waylandWindow) + // Qt exposes the window after acknowledging the initial xdg_surface configure, + // including the xdg-decoration negotiation. Earlier decoration overrides are ignored. + if (!waylandWindow || !waylandWindow->isExposed()) return nullptr; if (!waylandWindow->waylandSurface()) { @@ -297,11 +316,33 @@ PersonalizationWindowContext *DTreeLandPlatformWindowHelper::windowContext() con return nullptr; } - if (!m_windowContext) { - const_cast(this)->m_windowContext = new PersonalizationWindowContext(PersonalizationManager::instance()->get_window_context(surface)); + if (!m_decorationContext) { + const_cast(this)->m_decorationContext = new TreelandDecorationContext(manager->get_decoration_context(surface)); } - return m_windowContext; + return m_decorationContext; +} + +BackgroundEffectSurface *DTreeLandPlatformWindowHelper::backgroundEffectSurface() const +{ + if (m_backgroundEffectSurface) + return m_backgroundEffectSurface; + + auto manager = BackgroundEffectManager::instance(); + if (!manager->isSupported() || !manager->hasBlurCapability() || !manager->isInitialized()) + return nullptr; + + auto waylandWindow = dynamic_cast(window()->handle()); + if (!waylandWindow || !waylandWindow->waylandSurface()) + return nullptr; + + auto surface = waylandWindow->waylandSurface()->object(); + if (!surface) + return nullptr; + + const_cast(this)->m_backgroundEffectSurface = + new BackgroundEffectSurface(manager->get_background_effect(surface)); + return m_backgroundEffectSurface; } void DTreeLandPlatformWindowHelper::setEnabledNoTitlebar(bool enable) @@ -339,11 +380,6 @@ void DTreeLandPlatformWindowHelper::setShadowColor(const QColor &shadowColor) updateFeature(m_shadowColor, shadowColor, Shadow); } -void DTreeLandPlatformWindowHelper::setEnableBlurWindow(bool enableBlurWindow) -{ - updateFeature(m_blur, enableBlurWindow, Blur); -} - void DTreeLandPlatformWindowHelper::setWindowEffect(DPlatformHandle::EffectScenes effectScene) { updateFeature(m_effectScene, effectScene, WindowEffect); @@ -354,30 +390,56 @@ void DTreeLandPlatformWindowHelper::setPlatformHandle(DPlatformHandle *handle) m_platformHandle = handle; } +void DTreeLandPlatformWindowHelper::setEnableBlurWindow(bool enableBlurWindow) +{ + updateFeature(m_blurWindowEnabled, enableBlurWindow, BlurWindow); +} + +void DTreeLandPlatformWindowHelper::setWindowBlurAreas(const QVector &areas) +{ + QRegion region; + for (const auto &area : areas) { + const QRect rect(area.x, area.y, area.width, area.height); + if (area.xRadius > 0 || area.yRaduis > 0) { + QPainterPath path; + path.addRoundedRect(rect, area.xRadius, area.yRaduis, Qt::AbsoluteSize); + region += QRegion(path.toFillPolygon().toPolygon()); + } else { + region += rect; + } + } + updateFeature(m_blurRegion, region, BlurRegion); +} + +void DTreeLandPlatformWindowHelper::setWindowBlurPaths(const QList &paths) +{ + QRegion region; + for (const auto &path : paths) { + region += QRegion(path.toFillPolygon().toPolygon(), path.fillRule()); + } + updateFeature(m_blurRegion, region, BlurRegion); +} + void DTreeLandPlatformWindowHelper::scheduleApply() { if (m_applyScheduled) return; m_applyScheduled = true; - QMetaObject::invokeMethod(this, &DTreeLandPlatformWindowHelper::applyPending); + QMetaObject::invokeMethod(this, &DTreeLandPlatformWindowHelper::applyPending, Qt::QueuedConnection); } void DTreeLandPlatformWindowHelper::applyPending() { m_applyScheduled = false; - if (auto context = windowContext()) { + if (auto context = decorationContext()) { 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 ? TreelandDecorationContext::titlebar_mode_hide : TreelandDecorationContext::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 +457,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 +467,32 @@ void DTreeLandPlatformWindowHelper::applyPending() } } } + + const auto blurFeatures = Features(BlurWindow) | BlurRegion; + if (m_dirty & blurFeatures) { + const QRegion region = m_blurWindowEnabled + ? QRegion(QRect(QPoint(0, 0), window()->size())) : m_blurRegion; + auto waylandWindow = dynamic_cast(window()->handle()); + bool changed = false; + if (region.isEmpty()) { + changed = m_backgroundEffectSurface != nullptr; + delete m_backgroundEffectSurface; + m_backgroundEffectSurface = nullptr; + m_dirty &= ~blurFeatures; + } else { + auto manager = BackgroundEffectManager::instance(); + if (manager->hasBlurCapability() && waylandWindow) { + if (auto effect = backgroundEffectSurface()) { + effect->setBlurRegion(region, waylandWindow->display()); + m_dirty &= ~blurFeatures; + changed = true; + } + } + } + // Unconfigured surfaces receive the pending blur state with their first frame. + if (changed && waylandWindow && waylandWindow->isExposed()) + waylandWindow->commit(); + } } DTreeLandPlatformWindowInterface::DTreeLandPlatformWindowInterface(QWindow *window, DPlatformHandle *platformHandle, QObject *parent) @@ -435,6 +523,8 @@ bool DTreeLandPlatformWindowInterface::isEnabled() const bool DTreeLandPlatformWindowInterface::isEnabledNoTitlebar() const { + if (!TreelandDecorationManager::instance()->isSupported()) + return false; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) return helper->isEnabledNoTitlebar(); return false; @@ -442,6 +532,8 @@ bool DTreeLandPlatformWindowInterface::isEnabledNoTitlebar() const bool DTreeLandPlatformWindowInterface::setEnabledNoTitlebar(bool enable) { + if (!TreelandDecorationManager::instance()->isSupported()) + return false; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { helper->setEnabledNoTitlebar(enable); return true; @@ -451,6 +543,8 @@ bool DTreeLandPlatformWindowInterface::setEnabledNoTitlebar(bool enable) int DTreeLandPlatformWindowInterface::windowRadius() const { + if (!TreelandDecorationManager::instance()->isSupported()) + return 0; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) return helper->windowRadius(); return 0; @@ -458,6 +552,8 @@ int DTreeLandPlatformWindowInterface::windowRadius() const void DTreeLandPlatformWindowInterface::setWindowRadius(int windowRadius) { + if (!TreelandDecorationManager::instance()->isSupported()) + return; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { helper->setWindowRadius(windowRadius); if (m_platformHandle) @@ -467,6 +563,8 @@ void DTreeLandPlatformWindowInterface::setWindowRadius(int windowRadius) int DTreeLandPlatformWindowInterface::borderWidth() const { + if (!TreelandDecorationManager::instance()->isSupported()) + return 0; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) return helper->borderWidth(); return 0; @@ -474,6 +572,8 @@ int DTreeLandPlatformWindowInterface::borderWidth() const void DTreeLandPlatformWindowInterface::setBorderWidth(int borderWidth) { + if (!TreelandDecorationManager::instance()->isSupported()) + return; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { helper->setBorderWidth(borderWidth); if (m_platformHandle) @@ -483,6 +583,8 @@ void DTreeLandPlatformWindowInterface::setBorderWidth(int borderWidth) QColor DTreeLandPlatformWindowInterface::borderColor() const { + if (!TreelandDecorationManager::instance()->isSupported()) + return {}; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) return helper->borderColor(); return {}; @@ -490,6 +592,8 @@ QColor DTreeLandPlatformWindowInterface::borderColor() const void DTreeLandPlatformWindowInterface::setBorderColor(const QColor &borderColor) { + if (!TreelandDecorationManager::instance()->isSupported()) + return; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { helper->setBorderColor(borderColor); if (m_platformHandle) @@ -499,6 +603,8 @@ void DTreeLandPlatformWindowInterface::setBorderColor(const QColor &borderColor) int DTreeLandPlatformWindowInterface::shadowRadius() const { + if (!TreelandDecorationManager::instance()->isSupported()) + return 0; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) return helper->shadowRadius(); return 0; @@ -506,6 +612,8 @@ int DTreeLandPlatformWindowInterface::shadowRadius() const void DTreeLandPlatformWindowInterface::setShadowRadius(int shadowRadius) { + if (!TreelandDecorationManager::instance()->isSupported()) + return; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { helper->setShadowRadius(shadowRadius); if (m_platformHandle) @@ -515,6 +623,8 @@ void DTreeLandPlatformWindowInterface::setShadowRadius(int shadowRadius) QPoint DTreeLandPlatformWindowInterface::shadowOffset() const { + if (!TreelandDecorationManager::instance()->isSupported()) + return {}; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) return helper->shadowOffset(); return {}; @@ -522,6 +632,8 @@ QPoint DTreeLandPlatformWindowInterface::shadowOffset() const void DTreeLandPlatformWindowInterface::setShadowOffset(const QPoint &shadowOffset) { + if (!TreelandDecorationManager::instance()->isSupported()) + return; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { helper->setShadowOffset(shadowOffset); if (m_platformHandle) @@ -531,6 +643,8 @@ void DTreeLandPlatformWindowInterface::setShadowOffset(const QPoint &shadowOffse QColor DTreeLandPlatformWindowInterface::shadowColor() const { + if (!TreelandDecorationManager::instance()->isSupported()) + return {}; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) return helper->shadowColor(); return {}; @@ -538,6 +652,8 @@ QColor DTreeLandPlatformWindowInterface::shadowColor() const void DTreeLandPlatformWindowInterface::setShadowColor(const QColor &shadowColor) { + if (!TreelandDecorationManager::instance()->isSupported()) + return; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { helper->setShadowColor(shadowColor); if (m_platformHandle) @@ -547,6 +663,8 @@ void DTreeLandPlatformWindowInterface::setShadowColor(const QColor &shadowColor) bool DTreeLandPlatformWindowInterface::enableBlurWindow() const { + if (!BackgroundEffectManager::instance()->isSupported()) + return false; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) return helper->enableBlurWindow(); return false; @@ -554,6 +672,8 @@ bool DTreeLandPlatformWindowInterface::enableBlurWindow() const void DTreeLandPlatformWindowInterface::setEnableBlurWindow(bool enable) { + if (!BackgroundEffectManager::instance()->isSupported()) + return; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { helper->setEnableBlurWindow(enable); if (m_platformHandle) @@ -563,6 +683,8 @@ void DTreeLandPlatformWindowInterface::setEnableBlurWindow(bool enable) DPlatformHandle::EffectScene DTreeLandPlatformWindowInterface::windowEffect() { + if (!TreelandDecorationManager::instance()->isSupported()) + return {}; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) return static_cast(static_cast(helper->windowEffect())); return {}; @@ -570,10 +692,31 @@ DPlatformHandle::EffectScene DTreeLandPlatformWindowInterface::windowEffect() void DTreeLandPlatformWindowInterface::setWindowEffect(DPlatformHandle::EffectScenes effectScene) { + if (!TreelandDecorationManager::instance()->isSupported()) + return; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { helper->setWindowEffect(effectScene); if (m_platformHandle) Q_EMIT m_platformHandle->windowEffectChanged(); } } + +void DTreeLandPlatformWindowInterface::setWindowBlurAreas(const QVector &areas) +{ + if (!BackgroundEffectManager::instance()->isSupported()) + return; + if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { + helper->setWindowBlurAreas(areas); + } +} + +void DTreeLandPlatformWindowInterface::setWindowBlurPaths(const QList &paths) +{ + if (!BackgroundEffectManager::instance()->isSupported()) + return; + 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..5c88a31b 100644 --- a/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h +++ b/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h @@ -8,11 +8,13 @@ #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 +24,17 @@ 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, + BlurWindow = 1 << 5, + BlurRegion = 1 << 6, }; Q_DECLARE_FLAGS(Features, Feature) QWindow *window() const { return qobject_cast(parent()); } - PersonalizationWindowContext *windowContext() const; + TreelandDecorationContext *decorationContext() const; + BackgroundEffectSurface *backgroundEffectSurface() const; void setEnabledNoTitlebar(bool enable); void setWindowRadius(int windowRadius); @@ -39,9 +43,12 @@ class DTreeLandPlatformWindowHelper : public QObject { void setShadowRadius(int shadowRadius); void setShadowOffset(const QPoint &shadowOffset); void setShadowColor(const QColor &shadowColor); - void setEnableBlurWindow(bool enableBlurWindow); void setWindowEffect(DPlatformHandle::EffectScenes effectScene); void setPlatformHandle(DPlatformHandle *handle); + void setEnableBlurWindow(bool enabled); + void setWindowBlurAreas(const QVector &areas); + void setWindowBlurPaths(const QList &paths); + bool enableBlurWindow() const { return m_blurWindowEnabled; } bool isEnabledNoTitlebar() const { return m_noTitlebar; } int windowRadius() const { return m_radius; } @@ -50,7 +57,6 @@ 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; } DPlatformHandle::EffectScenes windowEffect() const { return m_effectScene; } private slots: @@ -67,27 +73,33 @@ private slots: template void updateFeature(T &member, const T &value, Feature flag) { member = value; + updateFeature(flag); + } + + void updateFeature(Feature flag) { m_initialized |= flag; m_dirty |= flag; scheduleApply(); } private: - PersonalizationWindowContext *m_windowContext = nullptr; + TreelandDecorationContext *m_decorationContext = nullptr; + BackgroundEffectSurface *m_backgroundEffectSurface = nullptr; static QMap windowMap; DPlatformHandle *m_platformHandle = nullptr; bool m_noTitlebar = false; - bool m_blur = false; + bool m_blurWindowEnabled = false; + QRegion m_blurRegion; int m_radius = 0; int m_borderWidth = 0; QColor m_borderColor; 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; }; @@ -123,6 +135,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..ba14e169 --- /dev/null +++ b/src/plugins/platform/treeland/treelandappearanceclientextension.cpp @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "treelandappearanceclientextension.h" + +#include "dplatformtheme.h" + +DGUI_BEGIN_NAMESPACE + +TreelandAppearance::TreelandAppearance(DTreelandPlatformInterface *interface) + : QWaylandClientExtensionTemplate(treeland_appearance_v1_interface.version) + , m_interface(interface) +{ + setParent(interface); +} + +TreelandAppearance::~TreelandAppearance() +{ + if (isInitialized()) + destroy(); +} + +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) { + // Treeland stores the point size multiplied by 10 to preserve fractional sizes. + qreal pointSize = size / 10.0; + pointSize = qBound(8.25, pointSize, 15.00); + 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..321b6e92 --- /dev/null +++ b/src/plugins/platform/treeland/treelandappearanceclientextension.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 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 + +DGUI_BEGIN_NAMESPACE + +class DTreelandPlatformInterfacePrivate; + +class TreelandAppearance : public QWaylandClientExtensionTemplate, + public QtWayland::treeland_appearance_v1 +{ + Q_OBJECT +public: + explicit TreelandAppearance(DTreelandPlatformInterface *interface); + ~TreelandAppearance() override; + +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: + 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..7c5ce121 --- /dev/null +++ b/src/plugins/platform/treeland/treelandbackgroundeffectclientextension.cpp @@ -0,0 +1,94 @@ +// SPDX-FileCopyrightText: 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(); +} + +void BackgroundEffectSurface::setBlurRegion(const QRegion ®ion, QtWaylandClient::QWaylandDisplay *display) +{ + auto wlRegion = display->createRegion(region); + set_blur_region(wlRegion); + wl_region_destroy(wlRegion); +} + +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..aae47efc --- /dev/null +++ b/src/plugins/platform/treeland/treelandbackgroundeffectclientextension.h @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 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 +#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 = nullptr; + 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; + + void setBlurRegion(const QRegion ®ion, QtWaylandClient::QWaylandDisplay *display); +}; + +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..b95c8846 --- /dev/null +++ b/src/plugins/platform/treeland/treelanddecorationclientextension.cpp @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: 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..f732900e --- /dev/null +++ b/src/plugins/platform/treeland/treelanddecorationclientextension.h @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 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 = nullptr; + 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..f4e08b84 100644 --- a/src/plugins/plugins.cmake +++ b/src/plugins/plugins.cmake @@ -55,26 +55,37 @@ else() endif() if(NOT DTK_DISABLE_TREELAND) - find_package(TreelandProtocols) + find_package(TreelandProtocols 0.7.0 REQUIRED) 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 1.45 REQUIRED) 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}