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..1791526a 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,18 @@ 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] { + if (m_initialized & Blur) { + m_dirty |= Blur; + scheduleApply(); + } + }); + + if (TreelandDecorationManager::instance()->isSupported() + && !TreelandDecorationManager::instance()->isActive()) { + qWarning() << "TreelandDecoration is not active" << window; + connect(TreelandDecorationManager::instance(), &TreelandDecorationManager::activeChanged, this, &DTreeLandPlatformWindowHelper::onActiveChanged, Qt::QueuedConnection); } if (window->handle()) { @@ -220,21 +223,25 @@ 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::Resize && m_blurEnabled && !m_blurRegionExplicit) { + m_dirty |= Blur; + 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 +261,7 @@ void DTreeLandPlatformWindowHelper::initWaylandWindow() void DTreeLandPlatformWindowHelper::onActiveChanged() { - if (PersonalizationManager::instance()->isActive()) { + if (TreelandDecorationManager::instance()->isActive()) { if (window()->handle()) { initWaylandWindow(); onSurfaceCreated(); @@ -270,18 +277,24 @@ 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) return nullptr; @@ -297,11 +310,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 +374,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,6 +384,45 @@ void DTreeLandPlatformWindowHelper::setPlatformHandle(DPlatformHandle *handle) m_platformHandle = handle; } +void DTreeLandPlatformWindowHelper::setEnableBlurWindow(bool enableBlurWindow) +{ + m_blurEnabled = enableBlurWindow; + m_blurRegionExplicit = false; + m_blurRegion = {}; + updateFeature(Blur); +} + +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; + } + } + m_blurRegion = region; + m_blurRegionExplicit = true; + m_blurEnabled = true; + updateFeature(Blur); +} + +void DTreeLandPlatformWindowHelper::setWindowBlurPaths(const QList &paths) +{ + QRegion region; + for (const auto &path : paths) { + region += QRegion(path.toFillPolygon().toPolygon(), path.fillRule()); + } + m_blurRegion = region; + m_blurRegionExplicit = true; + m_blurEnabled = true; + updateFeature(Blur); +} + void DTreeLandPlatformWindowHelper::scheduleApply() { if (m_applyScheduled) @@ -366,18 +435,14 @@ 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 +460,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 +470,33 @@ void DTreeLandPlatformWindowHelper::applyPending() } } } + + if (m_dirty & Blur) { + auto waylandWindow = dynamic_cast(window()->handle()); + bool changed = false; + if (!m_blurEnabled || (m_blurRegionExplicit && m_blurRegion.isEmpty())) { + changed = m_backgroundEffectSurface != nullptr; + delete m_backgroundEffectSurface; + m_backgroundEffectSurface = nullptr; + m_dirty &= ~Blur; + } else { + auto manager = BackgroundEffectManager::instance(); + if (manager->hasBlurCapability() && waylandWindow) { + const QRegion region = m_blurRegionExplicit + ? m_blurRegion : QRegion(QRect(QPoint(0, 0), window()->size())); + if (!region.isEmpty()) { + if (auto effect = backgroundEffectSurface()) { + effect->setBlurRegion(region, waylandWindow->display()); + m_dirty &= ~Blur; + 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 +527,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 +536,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 +547,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 +556,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 +567,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 +576,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 +587,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 +596,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 +607,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 +616,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 +627,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 +636,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 +647,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 +656,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 +667,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 +676,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 +687,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 +696,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..85ef6338 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,16 @@ 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, + Blur = 1 << 5, }; 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 +42,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_blurEnabled; } bool isEnabledNoTitlebar() const { return m_noTitlebar; } int windowRadius() const { return m_radius; } @@ -50,7 +56,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 +72,34 @@ 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_blurEnabled = false; + QRegion m_blurRegion; + bool m_blurRegionExplicit = false; 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..3c39c4d6 --- /dev/null +++ b/src/plugins/platform/treeland/treelandappearanceclientextension.cpp @@ -0,0 +1,113 @@ +// 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) { + // 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..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}