diff --git a/include/kernel/dguiapplicationhelper.h b/include/kernel/dguiapplicationhelper.h index 5b82017..72b6fcc 100644 --- a/include/kernel/dguiapplicationhelper.h +++ b/include/kernel/dguiapplicationhelper.h @@ -59,7 +59,8 @@ class DGuiApplicationHelper : public QObject, public DCORE_NAMESPACE::DObject IsXWindowPlatform = ReadOnlyLimit << 2, IsTableEnvironment = ReadOnlyLimit << 3, IsDeepinEnvironment = ReadOnlyLimit << 4, - IsSpecialEffectsEnvironment = ReadOnlyLimit << 5 + IsSpecialEffectsEnvironment = ReadOnlyLimit << 5, + IsTreelandPlatform = ReadOnlyLimit << 6 }; Q_ENUM(Attribute) Q_DECLARE_FLAGS(Attributes, Attribute) diff --git a/include/kernel/dplatformtheme.h b/include/kernel/dplatformtheme.h index d3e5edb..d55245d 100644 --- a/include/kernel/dplatformtheme.h +++ b/include/kernel/dplatformtheme.h @@ -28,6 +28,7 @@ class DPlatformTheme : public DNativeSettings Q_PROPERTY(QByteArray themeName READ themeName WRITE setThemeName NOTIFY themeNameChanged) Q_PROPERTY(QByteArray iconThemeName READ iconThemeName WRITE setIconThemeName NOTIFY iconThemeNameChanged) Q_PROPERTY(QByteArray soundThemeName READ soundThemeName WRITE setSoundThemeName NOTIFY soundThemeNameChanged) + Q_PROPERTY(QByteArray cursorThemeName READ cursorThemeName WRITE setCursorThemeName NOTIFY cursorThemeNameChanged) // Font Q_PROPERTY(QByteArray fontName READ fontName WRITE setFontName NOTIFY fontNameChanged) Q_PROPERTY(QByteArray monoFontName READ monoFontName WRITE setMonoFontName NOTIFY monoFontNameChanged) @@ -94,6 +95,7 @@ class DPlatformTheme : public DNativeSettings QByteArray themeName() const; QByteArray iconThemeName() const; QByteArray soundThemeName() const; + QByteArray cursorThemeName() const; QByteArray fontName() const; QByteArray monoFontName() const; @@ -147,6 +149,7 @@ public Q_SLOTS: void setThemeName(const QByteArray &themeName); void setIconThemeName(const QByteArray &iconThemeName); void setSoundThemeName(const QByteArray &soundThemeName); + void setCursorThemeName(const QByteArray &cursorThemeName); void setFontName(const QByteArray &fontName); void setMonoFontName(const QByteArray &monoFontName); void setFontPointSize(qreal fontPointSize); @@ -196,6 +199,7 @@ public Q_SLOTS: void themeNameChanged(QByteArray themeName); void iconThemeNameChanged(QByteArray iconThemeName); void soundThemeNameChanged(QByteArray soundThemeName); + void cursorThemeNameChanged(QByteArray cursorThemeName); void fontNameChanged(QByteArray fontName); void monoFontNameChanged(QByteArray monoFontName); void fontPointSizeChanged(qreal fontPointSize); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0524e98..71086b0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,30 +11,7 @@ include(filedrag/dfiledrag.cmake) include(kernel/kernel.cmake) include(private/private.cmake) include(util/util.cmake) - -if("${QT_VERSION_MAJOR}" STREQUAL "6") - qt6_generate_wayland_protocol_client_sources(${LIB_NAME} FILES - ${CMAKE_CURRENT_SOURCE_DIR}/wayland/protocol/treeland-personalization-manager-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(${LIB_NAME} - PROTOCOL ${CMAKE_CURRENT_SOURCE_DIR}/wayland/protocol/treeland-personalization-manager-v1.xml - BASENAME treeland-personalization-manager-v1 - ) - target_sources(${LIB_NAME} PRIVATE - ${CLIENT_LIB_SRCS} - ) -endif() - -include(wayland/wayland.cmake) -target_sources(${LIB_NAME} PRIVATE - ${wayland_SRC} -) +include(plugins/plugins.cmake) target_sources(${LIB_NAME} PRIVATE ${dbus_SRC} diff --git a/src/kernel/dguiapplicationhelper.cpp b/src/kernel/dguiapplicationhelper.cpp index 88ee575..692a569 100644 --- a/src/kernel/dguiapplicationhelper.cpp +++ b/src/kernel/dguiapplicationhelper.cpp @@ -1739,6 +1739,9 @@ bool DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::Attribute attri case IsSpecialEffectsEnvironment: { return qgetenv("DTK_DISABLED_SPECIAL_EFFECTS").toInt() != 1; } + case IsTreelandPlatform: { + return qgetenv("DDE_CURRENT_COMPOSITOR") == "TreeLand"; + } default: return DGuiApplicationHelperPrivate::attributes.testFlag(attribute); } diff --git a/src/kernel/dplatformhandle.cpp b/src/kernel/dplatformhandle.cpp index 280a929..ef63eb0 100644 --- a/src/kernel/dplatformhandle.cpp +++ b/src/kernel/dplatformhandle.cpp @@ -6,7 +6,7 @@ #include "dplatformhandle.h" #include "dplatformtheme.h" #include "dwindowmanagerhelper.h" -#include "wayland/dcontextshellwindow.h" +#include "plugins/dplatforminterface.h" #include #include @@ -97,11 +97,6 @@ static void setWindowProperty(QWindow *window, const char *name, const QVariant reinterpret_cast(setWindowProperty)(window, name, value); } -static bool isTreeLand() -{ - return qEnvironmentVariable("DDE_CURRENT_COMPOSITOR") == "TreeLand"; -}; - /*! \class Dtk::Gui::DPlatformHandle \inmodule dtkgui @@ -628,32 +623,30 @@ class Q_DECL_HIDDEN CreatorWindowEventFile : public QObject { } } - if (auto *w = qobject_cast(watched); w && isTreeLand()) { - if(DContextShellWindow *window = DContextShellWindow::get(qobject_cast(watched))) { - bool is_mouse_move = event->type() == QEvent::MouseMove && static_cast(event)->buttons() == Qt::LeftButton; + if (auto *w = qobject_cast(watched); w && DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsTreelandPlatform)) { + bool is_mouse_move = event->type() == QEvent::MouseMove && static_cast(event)->buttons() == Qt::LeftButton; - if (event->type() == QEvent::MouseButtonRelease) { - m_windowMoving = false; - } + if (event->type() == QEvent::MouseButtonRelease) { + m_windowMoving = false; + } - // workaround for kwin: Qt receives no release event when kwin finishes MOVE operation, - // which makes app hang in windowMoving state. when a press happens, there's no sense of - // keeping the moving state, we can just reset ti back to normal. - if (event->type() == QEvent::MouseButtonPress) { - m_windowMoving = false; - } + // workaround for kwin: Qt receives no release event when kwin finishes MOVE operation, + // which makes app hang in windowMoving state. when a press happens, there's no sense of + // keeping the moving state, we can just reset ti back to normal. + if (event->type() == QEvent::MouseButtonPress) { + m_windowMoving = false; + } + + // FIXME: We need to check whether the event is accepted. + // Only when the upper control does not accept the event, + // the window should be moved through the window. + // But every event here has been accepted. I don't know what happened. + if (is_mouse_move && w->geometry().contains(static_cast(event)->globalPos())) { + if (!m_windowMoving) { + m_windowMoving = true; - // FIXME: We need to check whether the event is accepted. - // Only when the upper control does not accept the event, - // the window should be moved through the window. - // But every event here has been accepted. I don't know what happened. - if (is_mouse_move && w->geometry().contains(static_cast(event)->globalPos())) { - if (!m_windowMoving && window->noTitlebar()) { - m_windowMoving = true; - - event->accept(); - static_cast(w->handle())->startSystemMove(); - } + event->accept(); + static_cast(w->handle())->startSystemMove(); } } } @@ -679,41 +672,10 @@ bool DPlatformHandle::setEnabledNoTitlebarForWindow(QWindow *window, bool enable auto isDWaylandPlatform = [] { return qApp->platformName() == "dwayland" || qApp->property("_d_isDwayland").toBool(); }; - if (!(isDXcbPlatform() || isDWaylandPlatform() || isTreeLand())) + if (!(isDXcbPlatform() || isDWaylandPlatform() || DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsTreelandPlatform))) return false; - if (window && isTreeLand()) { - DContextShellWindow *contextWindow = DContextShellWindow::get(window); - if (contextWindow->noTitlebar() == enable) - return true; - contextWindow->setNoTitlebar(enable); - window->installEventFilter(new CreatorWindowEventFile(window)); - return true; - } - - if (isEnabledNoTitlebar(window) == enable) - return true; - - QFunctionPointer enable_no_titlear = nullptr; - -#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) - enable_no_titlear = qApp->platformFunction(_setEnableNoTitlebar); -#endif - - if (enable_no_titlear) { - bool ok = (*reinterpret_cast(enable_no_titlear))(window, enable); - if (ok && enable) { - if (window->handle()) { - initWindowRadius(window); - } else { - window->installEventFilter(new CreatorWindowEventFile(window)); - } - } - - return ok; - } - - return false; + return DPlatformInterface::self(window)->setEnabledNoTitlebar(window, enable); } /*! @@ -724,17 +686,8 @@ bool DPlatformHandle::setEnabledNoTitlebarForWindow(QWindow *window, bool enable */ bool DPlatformHandle::isEnabledNoTitlebar(const QWindow *window) { - QFunctionPointer is_enable_no_titlebar = nullptr; - -#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) - is_enable_no_titlebar = qApp->platformFunction(_isEnableNoTitlebar); -#endif - - if (is_enable_no_titlebar) { - return (*reinterpret_cast(is_enable_no_titlebar))(window); - } - - return false; + QWindow *w = const_cast(window); + return DPlatformInterface::self(w)->isEnabledNoTitlebar(w); } inline DPlatformHandle::WMBlurArea operator *(const DPlatformHandle::WMBlurArea &area, qreal scale) diff --git a/src/kernel/dplatformtheme.cpp b/src/kernel/dplatformtheme.cpp index 10a1787..d3b1b3e 100644 --- a/src/kernel/dplatformtheme.cpp +++ b/src/kernel/dplatformtheme.cpp @@ -3,7 +3,17 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "dplatformtheme.h" +#include "plugins/dplatforminterface.h" #include "private/dplatformtheme_p.h" +#include "dguiapplicationhelper.h" + +#ifndef DTK_DISABLE_XCB +#include "plugins/platform/xcb/dxcbplatforminterface.h" +#endif + +#ifndef DTK_DISABLE_TREELAND +#include "plugins/platform/treeland/dtreelandplatforminterface.h" +#endif #include #include @@ -19,7 +29,6 @@ DGUI_BEGIN_NAMESPACE DPlatformThemePrivate::DPlatformThemePrivate(Dtk::Gui::DPlatformTheme *qq) : DNativeSettingsPrivate(qq, QByteArrayLiteral("/deepin/palette")) { - } void DPlatformThemePrivate::_q_onThemePropertyChanged(const QByteArray &name, const QVariant &value) @@ -142,6 +151,8 @@ DPlatformTheme::DPlatformTheme(quint32 window, QObject *parent) { D_D(DPlatformTheme); + d->platformInterface = DPlatformInterface::self(this); + d->theme = new DNativeSettings(window, QByteArray(), this); #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) connect(this, &DPlatformTheme::windowChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::Window, std::placeholders::_1)); @@ -387,7 +398,8 @@ int DPlatformTheme::dndDragThreshold() const int DPlatformTheme::windowRadius() const { - return windowRadius(-1); + Q_D(const DPlatformTheme); + return d->platformInterface->windowRadius(); } int DPlatformTheme::windowRadius(int defaultValue) const @@ -414,9 +426,9 @@ QByteArray DPlatformTheme::themeName() const QByteArray DPlatformTheme::iconThemeName() const { - FETCH_PROPERTY("Net/IconThemeName", iconThemeName) + Q_D(const DPlatformTheme); - return value.toByteArray(); + return d->platformInterface->iconThemeName(); } QByteArray DPlatformTheme::soundThemeName() const @@ -426,18 +438,22 @@ QByteArray DPlatformTheme::soundThemeName() const return value.toByteArray(); } -QByteArray DPlatformTheme::fontName() const +QByteArray DPlatformTheme::cursorThemeName() const { - FETCH_PROPERTY("Qt/FontName", fontName) + Q_D(const DPlatformTheme); + return d->platformInterface->cursorThemeName(); +} - return value.toByteArray(); +QByteArray DPlatformTheme::fontName() const +{ + Q_D(const DPlatformTheme); + return d->platformInterface->fontName(); } QByteArray DPlatformTheme::monoFontName() const { - FETCH_PROPERTY("Qt/MonoFontName", monoFontName) - - return value.toByteArray(); + Q_D(const DPlatformTheme); + return d->platformInterface->monoFontName(); } qreal DPlatformTheme::fontPointSize() const @@ -699,7 +715,7 @@ void DPlatformTheme::setIconThemeName(const QByteArray &iconThemeName) { D_D(DPlatformTheme); - d->theme->setSetting("Net/IconThemeName", iconThemeName); + d->platformInterface->setIconThemeName(iconThemeName); } void DPlatformTheme::setSoundThemeName(const QByteArray &soundThemeName) @@ -709,18 +725,25 @@ void DPlatformTheme::setSoundThemeName(const QByteArray &soundThemeName) d->theme->setSetting("Net/SoundThemeName", soundThemeName); } +void DPlatformTheme::setCursorThemeName(const QByteArray &cursorThemeName) +{ + D_D(DPlatformTheme); + + d->platformInterface->setCursorThemeName(cursorThemeName); +} + void DPlatformTheme::setFontName(const QByteArray &fontName) { D_D(DPlatformTheme); - d->theme->setSetting("Qt/FontName", fontName); + d->platformInterface->setFontName(fontName); } void DPlatformTheme::setMonoFontName(const QByteArray &monoFontName) { D_D(DPlatformTheme); - d->theme->setSetting("Qt/MonoFontName", monoFontName); + d->platformInterface->setMonoFontName(monoFontName); } void DPlatformTheme::setFontPointSize(qreal fontPointSize) @@ -896,8 +919,7 @@ void DPlatformTheme::setDotsPerInch(const QString &screenName, int dpi) void DPlatformTheme::setWindowRadius(int windowRadius) { D_D(DPlatformTheme); - - d->theme->setSetting("DTK/WindowRadius", windowRadius); + d->platformInterface->setWindowRadius(windowRadius); } DGUI_END_NAMESPACE diff --git a/src/plugins/dplatforminterface.cpp b/src/plugins/dplatforminterface.cpp new file mode 100644 index 0000000..a0e3265 --- /dev/null +++ b/src/plugins/dplatforminterface.cpp @@ -0,0 +1,121 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "dplatforminterface.h" +#include "dplatforminterface_p.h" + +#include + +#ifndef DTK_DISABLE_XCB +#include "platform/xcb/dxcbplatforminterface.h" +#endif + +#ifndef DTK_DISABLE_TREELAND +#include "platform/treeland/dtreelandplatforminterface.h" +#endif + + +DGUI_BEGIN_NAMESPACE +DPlatformInterfacePrivate::DPlatformInterfacePrivate(DPlatformInterface *qq) + : DObjectPrivate(qq) + +{ +} + +DPlatformInterfacePrivate::~DPlatformInterfacePrivate() +{ +} + +DPlatformInterface::DPlatformInterface(QObject *parent) + : DPlatformInterface(*new DPlatformInterfacePrivate(this), parent) +{ +} + +DPlatformInterface::~DPlatformInterface() +{ +} + +DPlatformInterface::DPlatformInterface(DPlatformInterfacePrivate &dd, QObject *parent) + : QObject(parent) + , DObject(dd) +{ +} + +bool DPlatformInterface::isEnabledNoTitlebar(QWindow *window) const +{ + return true; +} + +bool DPlatformInterface::setEnabledNoTitlebar(QWindow *window, bool enable) +{ + return true; +} + +int DPlatformInterface::windowRadius() const +{ + return 0; +} + +void DPlatformInterface::setWindowRadius(int windowRadius) +{ +} + +QByteArray DPlatformInterface::fontName() const +{ + return ""; +} + +void DPlatformInterface::setFontName(const QByteArray &fontName) +{ +} + +QByteArray DPlatformInterface::monoFontName() const +{ + return ""; +} + +void DPlatformInterface::setMonoFontName(const QByteArray &monoFontName) +{ +} + +QByteArray DPlatformInterface::iconThemeName() const +{ + return ""; +} + +void DPlatformInterface::setIconThemeName(const QByteArray &iconThemeName) +{ +} + +QByteArray DPlatformInterface::cursorThemeName() const +{ + return ""; +} + +void DPlatformInterface::setCursorThemeName(const QByteArray &cursorThemeName) +{ +} + +DPlatformInterface* DPlatformInterface::self(QObject *parent) +{ + +#ifndef DTK_DISABLE_XCB + if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsXWindowPlatform)) { + return new DXCBPlatformInterface(0, parent); + } +#endif + +#ifndef DTK_DISABLE_TREELAND + if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsTreelandPlatform)) { + return new DTreelandPlatformInterface(parent); + } +#endif + + return new DPlatformInterface(parent); +} + + +DGUI_END_NAMESPACE + + diff --git a/src/plugins/dplatforminterface.h b/src/plugins/dplatforminterface.h new file mode 100644 index 0000000..2b8d046 --- /dev/null +++ b/src/plugins/dplatforminterface.h @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DPLATFORMINTERFACE_H +#define DPLATFORMINTERFACE_H + +#include +#include +#include + +#include "dtkgui_global.h" +#include + +DGUI_BEGIN_NAMESPACE + +class DPlatformInterfacePrivate; +class DPlatformInterface : public QObject, public DCORE_NAMESPACE::DObject +{ + Q_OBJECT + D_DECLARE_PRIVATE(DPlatformInterface) +public: + explicit DPlatformInterface(QObject *parent); + virtual ~DPlatformInterface(); + + virtual bool isEnabledNoTitlebar(QWindow *window) const; + virtual bool setEnabledNoTitlebar(QWindow *window, bool enable); + + virtual int windowRadius() const; + virtual void setWindowRadius(int windowRadius); + + virtual QByteArray fontName() const; + virtual void setFontName(const QByteArray &fontName); + + virtual QByteArray monoFontName() const; + virtual void setMonoFontName(const QByteArray &monoFontName); + + virtual QByteArray iconThemeName() const; + virtual void setIconThemeName(const QByteArray &iconThemeName); + + virtual QByteArray cursorThemeName() const; + virtual void setCursorThemeName(const QByteArray &cursorThemeName); + + static DPlatformInterface* self(QObject *parent); + +protected: + DPlatformInterface(DPlatformInterfacePrivate &dd, QObject *parent); +}; + +DGUI_END_NAMESPACE +#endif diff --git a/src/plugins/dplatforminterface.h;plugins/platform/xcb/dxcbplatforminterface.h b/src/plugins/dplatforminterface.h;plugins/platform/xcb/dxcbplatforminterface.h new file mode 100644 index 0000000..1787295 --- /dev/null +++ b/src/plugins/dplatforminterface.h;plugins/platform/xcb/dxcbplatforminterface.h @@ -0,0 +1 @@ +plugins/platform/treeland/dtreelandplatforminterface.h \ No newline at end of file diff --git a/src/plugins/dplatforminterface_p.h b/src/plugins/dplatforminterface_p.h new file mode 100644 index 0000000..ec2b8c7 --- /dev/null +++ b/src/plugins/dplatforminterface_p.h @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DPLATFORMINTERFACE_P_H +#define DPLATFORMINTERFACE_P_H + +#include "dplatforminterface.h" +#include + +DGUI_BEGIN_NAMESPACE + +class DPlatformInterfacePrivate : public DCORE_NAMESPACE::DObjectPrivate +{ + D_DECLARE_PUBLIC(DPlatformInterface) +public: + DPlatformInterfacePrivate(DPlatformInterface *qq); + ~DPlatformInterfacePrivate(); +}; + +DGUI_END_NAMESPACE + +#endif // DNATIVESETTINGS_P_H diff --git a/src/plugins/platform/treeland/dtreelandplatforminterface.cpp b/src/plugins/platform/treeland/dtreelandplatforminterface.cpp new file mode 100644 index 0000000..c4fe849 --- /dev/null +++ b/src/plugins/platform/treeland/dtreelandplatforminterface.cpp @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "dtreelandplatforminterface.h" +#include "dtreelandplatforminterface_p.h" +#include "personalizationwaylandclientextension.h" + +DGUI_BEGIN_NAMESPACE +DTreelandPlatformInterfacePrivate::DTreelandPlatformInterfacePrivate(DTreelandPlatformInterface *qq) + : DPlatformInterfacePrivate(qq) +{ +} + +DTreelandPlatformInterface::DTreelandPlatformInterface(QObject *parent) + : DPlatformInterface(*new DTreelandPlatformInterfacePrivate(this), parent) +{ + D_D(DTreelandPlatformInterface); +} + +bool DTreelandPlatformInterface::isEnabledNoTitlebar(QWindow *window) const +{ + return PersonalizationManager::instance()->isEnabledNoTitlebar(window); +} + +bool DTreelandPlatformInterface::setEnabledNoTitlebar(QWindow *window, bool enable) +{ + return PersonalizationManager::instance()->setEnabledNoTitlebar(window, enable); +} + +int DTreelandPlatformInterface::windowRadius() const +{ + return PersonalizationManager::instance()->windowRadius(); +} + +void DTreelandPlatformInterface::setWindowRadius(int windowRadius) +{ + PersonalizationManager::instance()->setWindowRadius(windowRadius); +} + +QByteArray DTreelandPlatformInterface::fontName() const +{ + return PersonalizationManager::instance()->fontName().toUtf8(); +} + +void DTreelandPlatformInterface::setFontName(const QByteArray &fontName) +{ + PersonalizationManager::instance()->setFontName(fontName); +} + +QByteArray DTreelandPlatformInterface::monoFontName() const +{ + return PersonalizationManager::instance()->monoFontName().toUtf8(); +} + +void DTreelandPlatformInterface::setMonoFontName(const QByteArray &monoFontName) +{ + PersonalizationManager::instance()->setMonoFontName(monoFontName); +} + +QByteArray DTreelandPlatformInterface::iconThemeName() const +{ + return PersonalizationManager::instance()->iconThemeName().toUtf8(); +} + +void DTreelandPlatformInterface::setIconThemeName(const QByteArray &iconThemeName) +{ + PersonalizationManager::instance()->setIconThemeName(iconThemeName); +} + +QByteArray DTreelandPlatformInterface::cursorThemeName() const +{ + return PersonalizationManager::instance()->cursorThemeName().toUtf8(); +} + +void DTreelandPlatformInterface::setCursorThemeName(const QByteArray &cursorThemeName) +{ + PersonalizationManager::instance()->setCursorThemeName(cursorThemeName); +} + +DGUI_END_NAMESPACE diff --git a/src/plugins/platform/treeland/dtreelandplatforminterface.h b/src/plugins/platform/treeland/dtreelandplatforminterface.h new file mode 100644 index 0000000..6578925 --- /dev/null +++ b/src/plugins/platform/treeland/dtreelandplatforminterface.h @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DTREELANDPLATFORMINTERFACE_H +#define DTREELANDPLATFORMINTERFACE_H + +#include "plugins/dplatforminterface.h" + +DGUI_BEGIN_NAMESPACE + +class DTreelandPlatformInterfacePrivate; +class DTreelandPlatformInterface : public DPlatformInterface +{ + Q_OBJECT + D_DECLARE_PRIVATE(DTreelandPlatformInterface) +public: + explicit DTreelandPlatformInterface(QObject *parent); + + bool isEnabledNoTitlebar(QWindow *window) const override; + bool setEnabledNoTitlebar(QWindow *window, bool enable) override; + + int windowRadius() const override; + void setWindowRadius(int windowRadius) override; + + QByteArray fontName() const override; + void setFontName(const QByteArray &fontName) override; + + QByteArray monoFontName() const override; + void setMonoFontName(const QByteArray &monoFontName) override; + + QByteArray iconThemeName() const override; + void setIconThemeName(const QByteArray &iconThemeName) override; + + QByteArray cursorThemeName() const override; + void setCursorThemeName(const QByteArray &cursorThemeName) override; +}; + +DGUI_END_NAMESPACE +#endif diff --git a/src/plugins/platform/treeland/dtreelandplatforminterface_p.h b/src/plugins/platform/treeland/dtreelandplatforminterface_p.h new file mode 100644 index 0000000..891c944 --- /dev/null +++ b/src/plugins/platform/treeland/dtreelandplatforminterface_p.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DTREELANDPLATFORMINTERFACE_P_H +#define DTREELANDPLATFORMINTERFACE_P_H + +#include "dtreelandplatforminterface.h" +#include "plugins/dplatforminterface_p.h" + +DGUI_BEGIN_NAMESPACE + +class DTreelandPlatformInterfacePrivate : public DPlatformInterfacePrivate +{ + D_DECLARE_PUBLIC(DTreelandPlatformInterface) +public: + DTreelandPlatformInterfacePrivate(DTreelandPlatformInterface *qq); + +public: +}; + +DGUI_END_NAMESPACE + +#endif // DNATIVESETTINGS_P_H diff --git a/src/plugins/platform/treeland/personalizationwaylandclientextension.cpp b/src/plugins/platform/treeland/personalizationwaylandclientextension.cpp new file mode 100644 index 0000000..1e7e7f9 --- /dev/null +++ b/src/plugins/platform/treeland/personalizationwaylandclientextension.cpp @@ -0,0 +1,355 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "personalizationwaylandclientextension.h" + +#include +#include +#include +#include +#include +#include +#include + +DGUI_BEGIN_NAMESPACE + +class PersonalizationManager_: public PersonalizationManager {}; +Q_GLOBAL_STATIC(PersonalizationManager_, personalizationManager) + +PersonalizationManager::PersonalizationManager() + : QWaylandClientExtensionTemplate(1) +{ + if (QGuiApplication::platformName() == QLatin1String("wayland")) { + QtWaylandClient::QWaylandIntegration *waylandIntegration = static_cast(QGuiApplicationPrivate::platformIntegration()); + if (!waylandIntegration) { + qWarning() << "waylandIntegration is nullptr!!!"; + return; + } + m_waylandDisplay.reset(waylandIntegration->display()); + if (m_waylandDisplay.isNull()) { + qWarning() << "waylandDisplay is nullptr!!!"; + return; + } + addListener(); + } + + auto appearanceContext = get_appearance_context(); + if (!appearanceContext) { + qWarning() << "appearanceContext is nullptr!!!"; + return; + } + m_appearanceContext.reset(new PersonalizationAppearanceContext(appearanceContext)); +} + +PersonalizationManager *PersonalizationManager::instance() +{ + return personalizationManager; +} + +int PersonalizationManager::windowRadius() const +{ + if (m_appearanceContext.isNull()) { + return 0; + } + return m_appearanceContext->windowRadius(); +} + +void PersonalizationManager::setWindowRadius(int radius) +{ + if (m_appearanceContext.isNull()) { + return; + } + m_appearanceContext->setWindowRadius(radius); +} + +QString PersonalizationManager::fontName() const +{ + if (m_appearanceContext.isNull()) { + return QString(); + } + return m_appearanceContext->fontName(); +} + +void PersonalizationManager::setFontName(const QString& fontName) +{ + if (m_appearanceContext.isNull()) { + return; + } + m_appearanceContext->setFontName(fontName); +} + +QString PersonalizationManager::monoFontName() const +{ + if (m_appearanceContext.isNull()) { + return QString(); + } + return m_appearanceContext->monoFontName(); +} + +void PersonalizationManager::setMonoFontName(const QString& monoFontName) +{ + if (m_appearanceContext.isNull()) { + return; + } + m_appearanceContext->setMonoFontName(monoFontName); +} + +QString PersonalizationManager::cursorThemeName() const +{ + if (m_appearanceContext.isNull()) { + return QString(); + } + return m_appearanceContext->cursorTheme(); +} + +void PersonalizationManager::setCursorThemeName(const QString& cursorTheme) +{ + if (m_appearanceContext.isNull()) { + return; + } + m_appearanceContext->setCursorTheme(cursorTheme); +} + +QString PersonalizationManager::iconThemeName() const +{ + if (m_appearanceContext.isNull()) { + return QString(); + } + return m_appearanceContext->iconTheme(); +} + +void PersonalizationManager::setIconThemeName(const QString& iconTheme) +{ + if (m_appearanceContext.isNull()) { + return; + } + m_appearanceContext->setIconTheme(iconTheme); +} + +PersonalizationWindowContext *PersonalizationManager::getWindowContext(QWindow *window) +{ + if (!window) { + qWarning() << "window is nullptr!!!"; + return nullptr; + } + auto waylandWindow = dynamic_cast(window->handle()); + if (!waylandWindow) { + qWarning() << "waylandWindow is nullptr!!!"; + return nullptr; + } + auto surface = waylandWindow->waylandSurface()->object(); + if (!surface) { + qWarning() << "waylandSurface is nullptr!!!"; + return nullptr; + } + auto context = get_window_context(surface); + if (m_windowContext.isNull()) { + m_windowContext.reset(new PersonalizationWindowContext(context)); + } + return m_windowContext.data(); +} + +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); + } +} + +bool PersonalizationManager::isEnabledNoTitlebar(QWindow *window) +{ + return m_isNoTitlebarMap.value(window); +} + +bool PersonalizationManager::setEnabledNoTitlebar(QWindow *window, bool enable) +{ + auto windowContext = this->getWindowContext(window); + if (!windowContext) { + qWarning() << "windowContext is nullptr!"; + return false; + } + windowContext->setNoTitlebar(enable); + m_isNoTitlebarMap.insert(window, enable); + return true; +} + +void PersonalizationManager::setWindowRadius(QWindow *window, int radius) +{ + auto windowContext = this->getWindowContext(window); + if (!windowContext) { + return; + } + windowContext->setWindowRadius(radius); +} + +PersonalizationWindowContext::PersonalizationWindowContext(struct ::treeland_personalization_window_context_v1 *context) + : QWaylandClientExtensionTemplate(1) + , QtWayland::treeland_personalization_window_context_v1(context) +{ +} + +void PersonalizationWindowContext::setNoTitlebar(bool enable) +{ + if (m_noTitlebar == enable) { + return; + } + + m_noTitlebar = enable; + set_no_titlebar(m_noTitlebar ? enable_mode::enable_mode_enable : enable_mode::enable_mode_disable); +} + +int PersonalizationWindowContext::windowRadius() +{ + return m_windowRadius; +} + +void PersonalizationWindowContext::setWindowRadius(int radius) +{ + if (m_windowRadius == radius) { + return; + } + + m_windowRadius = radius; + set_round_corner_radius(radius); +} + +PersonalizationAppearanceContext::PersonalizationAppearanceContext(struct ::treeland_personalization_appearance_context_v1 *context) + : QWaylandClientExtensionTemplate(1) + , QtWayland::treeland_personalization_appearance_context_v1(context) +{ + get_round_corner_radius(); + get_font(); + get_monospace_font(); + get_cursor_theme(); + get_icon_theme(); +} + +int PersonalizationAppearanceContext::windowRadius() const +{ + return m_windowRadius; +} + +void PersonalizationAppearanceContext::setWindowRadius(int radius) +{ + if (m_windowRadius == radius) { + return; + } + + m_windowRadius = radius; + set_round_corner_radius(radius); +} + +QString PersonalizationAppearanceContext::fontName() const +{ + return m_fontName; +} + +void PersonalizationAppearanceContext::setFontName(const QString& fontName) +{ + if (m_fontName == fontName) { + return; + } + + m_fontName = fontName; + set_font(fontName); +} + +QString PersonalizationAppearanceContext::monoFontName() const +{ + return m_monoFontName; +} + +void PersonalizationAppearanceContext::setMonoFontName(const QString& fontName) +{ + if (m_monoFontName == fontName) { + return; + } + + m_monoFontName = fontName; + set_monospace_font(fontName); +} + +QString PersonalizationAppearanceContext::cursorTheme() const +{ + return m_cursorTheme; +} + +void PersonalizationAppearanceContext::setCursorTheme(const QString& cursorTheme) +{ + if (m_cursorTheme == cursorTheme) { + return; + } + + m_cursorTheme = cursorTheme; + set_cursor_theme(cursorTheme); +} + +QString PersonalizationAppearanceContext::iconTheme() const +{ + return m_iconTheme; +} + +void PersonalizationAppearanceContext::setIconTheme(const QString& iconTheme) +{ + if (m_iconTheme == iconTheme) { + return; + } + + m_iconTheme = iconTheme; + set_cursor_theme(iconTheme); +} + +void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_round_corner_radius(int32_t radius) +{ + m_windowRadius = radius; +} + +void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_font(const QString &font_name) +{ + m_fontName = font_name; +} + +void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_monospace_font(const QString &font_name) +{ + m_monoFontName = font_name; +} + +void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_cursor_theme(const QString &theme_name) +{ + m_cursorTheme = theme_name; +} + +void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_icon_theme(const QString &theme_name) +{ + m_iconTheme = theme_name; +} + +PersonalizationWallpaperContext::PersonalizationWallpaperContext(struct ::treeland_personalization_wallpaper_context_v1 *context) + : QWaylandClientExtensionTemplate(1) + , QtWayland::treeland_personalization_wallpaper_context_v1(context) +{ +} + +PersonalizationCursorContext::PersonalizationCursorContext(struct ::treeland_personalization_cursor_context_v1 *context) + : QWaylandClientExtensionTemplate(1) + , QtWayland::treeland_personalization_cursor_context_v1(context) +{ +} +DGUI_END_NAMESPACE diff --git a/src/plugins/platform/treeland/personalizationwaylandclientextension.h b/src/plugins/platform/treeland/personalizationwaylandclientextension.h new file mode 100644 index 0000000..56514cb --- /dev/null +++ b/src/plugins/platform/treeland/personalizationwaylandclientextension.h @@ -0,0 +1,144 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include "qwayland-treeland-personalization-manager-v1.h" + +#include +#include +#include +#include +#include + +DGUI_BEGIN_NAMESPACE +class PersonalizationWindowContext; +class PersonalizationAppearanceContext; + +class PersonalizationManager: public QWaylandClientExtensionTemplate, + public QtWayland::treeland_personalization_manager_v1 +{ + Q_OBJECT +public: + static PersonalizationManager *instance(); + + bool isEnabledNoTitlebar(QWindow *window); + bool setEnabledNoTitlebar(QWindow *window, bool enable); + + void setWindowRadius(QWindow *window, int radius); + + int windowRadius() const; + void setWindowRadius(int radius); + + QString fontName() const; + void setFontName(const QString& fontName); + + QString monoFontName() const; + void setMonoFontName(const QString& monoFontName); + + QString cursorThemeName() const; + void setCursorThemeName(const QString& cursorTheme); + + QString iconThemeName() const; + void setIconThemeName(const QString& iconTheme); + +protected: + explicit PersonalizationManager(); + +private: + void addListener(); + void removeListener(); + PersonalizationWindowContext *getWindowContext(QWindow *window); + + static void handleListenerGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version); + +private: + QScopedPointer m_windowContext; + QScopedPointer m_appearanceContext; + QScopedPointer m_waylandDisplay; + QHash m_isNoTitlebarMap; +}; + +class PersonalizationWindowContext : public QWaylandClientExtensionTemplate, + public QtWayland::treeland_personalization_window_context_v1 +{ + Q_OBJECT +public: + explicit PersonalizationWindowContext(struct ::treeland_personalization_window_context_v1 *context); + + bool noTitlebar() const; + void setNoTitlebar(bool enable); + + int windowRadius(); + void setWindowRadius(int radius); + +private: + bool m_noTitlebar; + int m_windowRadius; +}; + +class PersonalizationAppearanceContext : public QWaylandClientExtensionTemplate, + public QtWayland::treeland_personalization_appearance_context_v1 +{ + Q_OBJECT + Q_PROPERTY(int windowRadius READ windowRadius WRITE setWindowRadius) + Q_PROPERTY(QString fontName READ fontName WRITE setFontName) + Q_PROPERTY(QString monoFontName READ monoFontName WRITE setMonoFontName) + Q_PROPERTY(QString cursorTheme READ cursorTheme WRITE setCursorTheme) + Q_PROPERTY(QString iconTheme READ iconTheme WRITE setIconTheme) + +public: + explicit PersonalizationAppearanceContext(struct ::treeland_personalization_appearance_context_v1 *context); + + int windowRadius() const; + void setWindowRadius(int radius); + + QString fontName() const; + void setFontName(const QString& fontName); + + QString monoFontName() const; + void setMonoFontName(const QString& monoFontName); + + QString cursorTheme() const; + void setCursorTheme(const QString& cursorTheme); + + QString iconTheme() const; + void setIconTheme(const QString& iconTheme); + +protected: + virtual void treeland_personalization_appearance_context_v1_round_corner_radius(int32_t radius); + virtual void treeland_personalization_appearance_context_v1_font(const QString &font_name); + virtual void treeland_personalization_appearance_context_v1_monospace_font(const QString &font_name); + virtual void treeland_personalization_appearance_context_v1_cursor_theme(const QString &theme_name); + virtual void treeland_personalization_appearance_context_v1_icon_theme(const QString &theme_name); + +private: + int m_windowRadius; + QString m_fontName; + QString m_monoFontName; + QString m_cursorTheme; + QString m_iconTheme; +}; + +class PersonalizationWallpaperContext : public QWaylandClientExtensionTemplate, + public QtWayland::treeland_personalization_wallpaper_context_v1 +{ + Q_OBJECT +public: + explicit PersonalizationWallpaperContext(struct ::treeland_personalization_wallpaper_context_v1 *context); + + +}; + +class PersonalizationCursorContext : public QWaylandClientExtensionTemplate, + public QtWayland::treeland_personalization_cursor_context_v1 +{ + Q_OBJECT +public: + explicit PersonalizationCursorContext(struct ::treeland_personalization_cursor_context_v1 *context); + +}; + +DGUI_END_NAMESPACE diff --git a/src/plugins/platform/treeland/treeland.cmake b/src/plugins/platform/treeland/treeland.cmake new file mode 100644 index 0000000..3ed4545 --- /dev/null +++ b/src/plugins/platform/treeland/treeland.cmake @@ -0,0 +1,10 @@ +file(GLOB TREELAND_HEADER + ${CMAKE_CURRENT_LIST_DIR}/*.h +) +file(GLOB TREELAND_SOURCE + ${CMAKE_CURRENT_LIST_DIR}/*.cpp +) +set(treeland_SRC + ${TREELAND_HEADER} + ${TREELAND_SOURCE} +) diff --git a/src/plugins/platform/xcb/dxcbplatforminterface.cpp b/src/plugins/platform/xcb/dxcbplatforminterface.cpp new file mode 100644 index 0000000..20e95a8 --- /dev/null +++ b/src/plugins/platform/xcb/dxcbplatforminterface.cpp @@ -0,0 +1,251 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "dxcbplatforminterface.h" +#include "dxcbplatforminterface_p.h" + +#include + +#include +#include +#include + +#include "dplatformtheme.h" +#include "dguiapplicationhelper.h" + +DGUI_BEGIN_NAMESPACE + +#define DEFINE_CONST_CHAR(Name) const char _##Name[] = "_d_" #Name + +DEFINE_CONST_CHAR(setEnableNoTitlebar); +DEFINE_CONST_CHAR(isEnableNoTitlebar); +DEFINE_CONST_CHAR(windowRadius); +DEFINE_CONST_CHAR(setWindowProperty); +DEFINE_CONST_CHAR(resolve_mask); + +enum PropRole { + WindowRadius, + + // TO BE CONTINUE +}; + +#define FETCH_PROPERTY(Name, Function) \ + D_DC(DXCBPlatformInterface); \ + QVariant value = d->m_nativeSettings->getSetting(QByteArrayLiteral(Name)); \ + if (d->fallbackProperty && !value.isValid() && d->parent) \ + return d->parent->Function(); \ + +static bool resolved(QObject *obj, PropRole role) +{ + int mask = obj->property(_resolve_mask).toInt(); + return mask & (1 << role); +} + +static void setWindowProperty(QWindow *window, const char *name, const QVariant &value) +{ + if (!window) + return; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + static QFunctionPointer setWindowProperty = qApp->platformFunction(_setWindowProperty); +#else + constexpr QFunctionPointer setWindowProperty = nullptr; +#endif + + if (!setWindowProperty) { + window->setProperty(name, value); + + return; + } + + reinterpret_cast(setWindowProperty)(window, name, value); +} + +static void initWindowRadius(QWindow *window) +{ + if (window->property(_windowRadius).isValid()) + return; + + auto theme = DGuiApplicationHelper::instance()->systemTheme(); + int radius = theme->windowRadius(18); //###(zccrs): 暂时在此处给窗口默认设置为18px的圆角 + + setWindowProperty(window, _windowRadius, radius); + // Qt::UniqueConnection will report a warning + // to `unique connections require a pointer to member function of a QObject subclass`. + const char *uniqueueConnectionFlag("_d_uniqueueConnectionFlag"); + bool connected = window->property(uniqueueConnectionFlag).toBool(); + if (!connected) { + window->setProperty(uniqueueConnectionFlag, true); + window->connect(theme, &DPlatformTheme::windowRadiusChanged, window, [window] (int radius) { + if (!resolved(window, PropRole::WindowRadius)) + setWindowProperty(window, _windowRadius, radius); + }); + } +} + +class Q_DECL_HIDDEN CreatorWindowEventFile : public QObject +{ + bool m_windowMoving = false; +public: + CreatorWindowEventFile(QObject *par= nullptr): QObject(par){} + +public: + bool eventFilter(QObject *watched, QEvent *event) override { + if (event->type() == QEvent::PlatformSurface) { + QPlatformSurfaceEvent *se = static_cast(event); + if (se->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) { // 若收到此信号, 则 WinID 已被创建 + initWindowRadius(qobject_cast(watched)); + deleteLater(); + } + } + + if (auto *w = qobject_cast(watched); w && DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsTreelandPlatform)) { + bool is_mouse_move = event->type() == QEvent::MouseMove && static_cast(event)->buttons() == Qt::LeftButton; + + if (event->type() == QEvent::MouseButtonRelease) { + m_windowMoving = false; + } + + // workaround for kwin: Qt receives no release event when kwin finishes MOVE operation, + // which makes app hang in windowMoving state. when a press happens, there's no sense of + // keeping the moving state, we can just reset ti back to normal. + if (event->type() == QEvent::MouseButtonPress) { + m_windowMoving = false; + } + + // FIXME: We need to check whether the event is accepted. + // Only when the upper control does not accept the event, + // the window should be moved through the window. + // But every event here has been accepted. I don't know what happened. + if (is_mouse_move && w->geometry().contains(static_cast(event)->globalPos())) { + if (!m_windowMoving) { + m_windowMoving = true; + + event->accept(); + static_cast(w->handle())->startSystemMove(); + } + } + } + + return QObject::eventFilter(watched, event); + } +}; + +DXCBPlatformInterfacePrivate::DXCBPlatformInterfacePrivate(DXCBPlatformInterface *qq) + : DPlatformInterfacePrivate(qq) +{ +} + +DXCBPlatformInterface::DXCBPlatformInterface(quint32 window, QObject *parent) + : DPlatformInterface(*new DXCBPlatformInterfacePrivate(this), parent) +{ + D_D(DXCBPlatformInterface); + + d->m_nativeSettings = new DNativeSettings(window, QByteArray(), this); +} + +bool DXCBPlatformInterface::isEnabledNoTitlebar(QWindow *window) const +{ + QFunctionPointer is_enable_no_titlebar = nullptr; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + is_enable_no_titlebar = qApp->platformFunction(_isEnableNoTitlebar); +#endif + + if (is_enable_no_titlebar) { + return (*reinterpret_cast(is_enable_no_titlebar))(window); + } + + return false; +} + +bool DXCBPlatformInterface::setEnabledNoTitlebar(QWindow *window, bool enable) +{ + if (isEnabledNoTitlebar(window) == enable) + return true; + + QFunctionPointer enable_no_titlear = nullptr; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + enable_no_titlear = qApp->platformFunction(_setEnableNoTitlebar); +#endif + + if (enable_no_titlear) { + bool ok = (*reinterpret_cast(enable_no_titlear))(window, enable); + if (ok && enable) { + if (window->handle()) { + initWindowRadius(window); + } else { + window->installEventFilter(new CreatorWindowEventFile(window)); + } + } + + return ok; + } + + return false; + +} + +int DXCBPlatformInterface::windowRadius() const +{ + FETCH_PROPERTY("DTK/WindowRadius", windowRadius); + return value.toInt(); +} + +void DXCBPlatformInterface::setWindowRadius(int windowRadius) +{ + D_D(DXCBPlatformInterface); + d->m_nativeSettings->setSetting("DTK/WindowRadius", windowRadius); +} + +QByteArray DXCBPlatformInterface::fontName() const +{ + FETCH_PROPERTY("Qt/FontName", fontName) + return value.toByteArray(); +} + +void DXCBPlatformInterface::setFontName(const QByteArray &fontName) +{ + D_D(DXCBPlatformInterface); + d->m_nativeSettings->setSetting("Qt/FontName", fontName); +} + +QByteArray DXCBPlatformInterface::monoFontName() const +{ + FETCH_PROPERTY("Qt/MonoFontName", monoFontName) + return value.toByteArray(); +} + +void DXCBPlatformInterface::setMonoFontName(const QByteArray &monoFontName) +{ + D_D(DXCBPlatformInterface); + d->m_nativeSettings->setSetting("Qt/MonoFontName", monoFontName); +} + +QByteArray DXCBPlatformInterface::iconThemeName() const +{ + FETCH_PROPERTY("Net/IconThemeName", iconThemeName) + return value.toByteArray(); +} + +void DXCBPlatformInterface::setIconThemeName(const QByteArray &iconThemeName) +{ + D_D(DXCBPlatformInterface); + d->m_nativeSettings->setSetting("Net/IconThemeName", iconThemeName); +} + +QByteArray DXCBPlatformInterface::cursorThemeName() const +{ + FETCH_PROPERTY("Gtk/CursorThemeName", cursorThemeName) + return value.toByteArray(); +} + +void DXCBPlatformInterface::setCursorThemeName(const QByteArray &cursorThemeName) +{ + D_D(DXCBPlatformInterface); + d->m_nativeSettings->setSetting("Gtk/CursorThemeName", cursorThemeName); +} + +DGUI_END_NAMESPACE diff --git a/src/plugins/platform/xcb/dxcbplatforminterface.h b/src/plugins/platform/xcb/dxcbplatforminterface.h new file mode 100644 index 0000000..7778563 --- /dev/null +++ b/src/plugins/platform/xcb/dxcbplatforminterface.h @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DXCBPLATFORMINTERFACE_H +#define DXCBPLATFORMINTERFACE_H + +#include "plugins/dplatforminterface.h" + +DGUI_BEGIN_NAMESPACE + +class DXCBPlatformInterfacePrivate; +class DXCBPlatformInterface : public DPlatformInterface +{ + Q_OBJECT + D_DECLARE_PRIVATE(DXCBPlatformInterface) +public: + explicit DXCBPlatformInterface(quint32 window, QObject *parent); + + bool isEnabledNoTitlebar(QWindow *window) const override; + bool setEnabledNoTitlebar(QWindow *window, bool enable) override; + + int windowRadius() const override; + void setWindowRadius(int windowRadius) override; + + QByteArray fontName() const override; + void setFontName(const QByteArray &fontName) override; + + QByteArray monoFontName() const override; + void setMonoFontName(const QByteArray &monoFontName) override; + + QByteArray iconThemeName() const override; + void setIconThemeName(const QByteArray &iconThemeName) override; + + QByteArray cursorThemeName() const override; + void setCursorThemeName(const QByteArray &cursorThemeName) override; +}; + +DGUI_END_NAMESPACE +#endif diff --git a/src/plugins/platform/xcb/dxcbplatforminterface_p.h b/src/plugins/platform/xcb/dxcbplatforminterface_p.h new file mode 100644 index 0000000..7fee250 --- /dev/null +++ b/src/plugins/platform/xcb/dxcbplatforminterface_p.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DXCBPLATFORMINTERFACE_P_H +#define DXCBPLATFORMINTERFACE_P_H + +#include "dxcbplatforminterface.h" +#include "plugins/dplatforminterface_p.h" + +DGUI_BEGIN_NAMESPACE + +class DNativeSettings; +class DPlatformTheme; + +class DXCBPlatformInterfacePrivate : public DPlatformInterfacePrivate +{ + D_DECLARE_PUBLIC(DXCBPlatformInterface) +public: + DXCBPlatformInterfacePrivate(DXCBPlatformInterface *qq); + +public: + DPlatformTheme *parent = nullptr; + bool fallbackProperty = true; + DNativeSettings *m_nativeSettings; + QHash m_properties; +}; + +DGUI_END_NAMESPACE + +#endif // DNATIVESETTINGS_P_H diff --git a/src/plugins/platform/xcb/xcb.cmake b/src/plugins/platform/xcb/xcb.cmake new file mode 100644 index 0000000..9bbc49e --- /dev/null +++ b/src/plugins/platform/xcb/xcb.cmake @@ -0,0 +1,10 @@ +file(GLOB XCB_HEADER + ${CMAKE_CURRENT_LIST_DIR}/*.h +) +file(GLOB XCB_SOURCE + ${CMAKE_CURRENT_LIST_DIR}/*.cpp +) +set(xcb_SRC + ${XCB_HEADER} + ${XCB_SOURCE} +) diff --git a/src/plugins/plugins.cmake b/src/plugins/plugins.cmake new file mode 100644 index 0000000..2f92c2b --- /dev/null +++ b/src/plugins/plugins.cmake @@ -0,0 +1,66 @@ +option(DTK_DISABLE_XCB "Disable XCB Protocols" OFF) +option(DTK_DISABLE_TREELAND "Disable TreeLand Protocols" OFF) + +file(GLOB PLATFORM_INTERFACE_HEADER + ${CMAKE_CURRENT_LIST_DIR}/*.h +) +file(GLOB PLATFORM_INTERFACE_SOURCE + ${CMAKE_CURRENT_LIST_DIR}/*.cpp +) +set(platform_interface_SRC + ${PLATFORM_INTERFACE_HEADER} + ${PLATFORM_INTERFACE_SOURCE} +) +target_sources(${LIB_NAME} PRIVATE + ${platform_interface_SRC} +) + +set(PRIVATE_HEADER_FILES plugins/dplatforminterface.h) +set(PRIVATE_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}/dtk${PROJECT_VERSION_MAJOR}/DGui/Private") + +# XCB +if(NOT DTK_DISABLE_XCB) + message("Support XCB!") + include(plugins/platform/xcb/xcb.cmake) + target_sources(${LIB_NAME} PRIVATE + ${xcb_SRC} + ) + list(APPEND PRIVATE_HEADER_FILES "plugins/platform/xcb/dxcbplatforminterface.h") +else() + target_compile_definitions(${LIB_NAME} PRIVATE DTK_DISABLE_XCB) +endif() + +# Treeland +find_package(TreeLandProtocols) +set(TreeLandProtocols_FOUND ${TreeLandProtocols_FOUND}) +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 + ) + 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(${LIB_NAME} + PROTOCOL ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-personalization-manager-v1.xml + BASENAME treeland-personalization-manager-v1 + ) + target_sources(${LIB_NAME} PRIVATE + ${CLIENT_LIB_SRCS} + ) + endif() + include(plugins/platform/treeland/treeland.cmake) + target_sources(${LIB_NAME} PRIVATE + ${treeland_SRC} + ) + list(APPEND PRIVATE_HEADER_FILES "plugins/platform/treeland/dtreelandplatforminterface.h") +else() + target_compile_definitions(${LIB_NAME} PRIVATE DTK_DISABLE_TREELAND) +endif() + +message(${PRIVATE_HEADER_FILES}) +install(FILES ${PRIVATE_HEADER_FILES} DESTINATION "${PRIVATE_INCLUDE_INSTALL_DIR}") diff --git a/src/private/dplatformtheme_p.h b/src/private/dplatformtheme_p.h index 0349cba..57e483a 100644 --- a/src/private/dplatformtheme_p.h +++ b/src/private/dplatformtheme_p.h @@ -5,6 +5,7 @@ #ifndef DPLATFORMTHEME_P_H #define DPLATFORMTHEME_P_H +#include "plugins/dplatforminterface.h" #include "dplatformtheme.h" #include "dnativesettings_p.h" @@ -34,6 +35,8 @@ class DPlatformThemePrivate : public DNativeSettingsPrivate DPalette *palette = nullptr; // 减少调色板changed信号的通知频率 QTimer *notifyPaletteChangeTimer = nullptr; + + DPlatformInterface *platformInterface = nullptr; }; DGUI_END_NAMESPACE diff --git a/src/wayland/dcontextshellwindow.cpp b/src/wayland/dcontextshellwindow.cpp deleted file mode 100644 index e22bf9e..0000000 --- a/src/wayland/dcontextshellwindow.cpp +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#include "dcontextshellwindow.h" - -#include "qwaylandpersonalizationshellintegration_p.h" - -#include - -DGUI_BEGIN_NAMESPACE -class DContextShellWindowPrivate -{ -public: - explicit DContextShellWindowPrivate(QWindow *window) - : parentWindow(window) - { - } - - QWindow *parentWindow = nullptr; - bool noTitlebar = false; -}; - -bool DContextShellWindow::noTitlebar() -{ - return d->noTitlebar; -} - -void DContextShellWindow::setNoTitlebar(bool value) -{ - if (value == d->noTitlebar) { - return; - } - d->noTitlebar = value; - Q_EMIT noTitlebarChanged(); -} - -static QMap s_map; - -DContextShellWindow::~DContextShellWindow() -{ - s_map.remove(d->parentWindow); -} - -DContextShellWindow::DContextShellWindow(QWindow *window) - : QObject(window) - , d(new DContextShellWindowPrivate(window)) -{ - s_map.insert(window, this); - window->create(); - auto waylandWindow = dynamic_cast(window->handle()); - if (waylandWindow) { - static QWaylandPersonalizationShellIntegration *shellIntegration = nullptr; - if (!shellIntegration) { - shellIntegration = new QWaylandPersonalizationShellIntegration(); - if (!shellIntegration->initialize(waylandWindow->display())) { - delete shellIntegration; - shellIntegration = nullptr; - qWarning() << "failed to init dlayershell intergration"; - return; - } - } -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - shellIntegration->createShellSurface(waylandWindow); -#else - waylandWindow->setShellIntegration(shellIntegration); -#endif - } else { - qWarning() << "not a wayland window, will not create zwlr_layer_surface"; - } -} - -DContextShellWindow *DContextShellWindow::get(QWindow *window) -{ - auto dlayerShellWindow = s_map.value(window); - if (dlayerShellWindow) { - return dlayerShellWindow; - } - return new DContextShellWindow(window); -} - -DContextShellWindow *DContextShellWindow::qmlAttachedProperties(QObject *object) -{ - auto window = qobject_cast(object); - if (window) - return get(window); - qWarning() << "not a qwindow unable to create DContextShellWindow"; - return nullptr; -} -DGUI_END_NAMESPACE diff --git a/src/wayland/dcontextshellwindow.h b/src/wayland/dcontextshellwindow.h deleted file mode 100644 index 8cb8bc7..0000000 --- a/src/wayland/dcontextshellwindow.h +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#pragma once - -#include -#include - -DGUI_BEGIN_NAMESPACE -class DContextShellWindowPrivate; - -class DContextShellWindow : public QObject -{ - Q_OBJECT - Q_PROPERTY(int noTitlebar READ noTitlebar WRITE setNoTitlebar NOTIFY noTitlebarChanged) - -public: - ~DContextShellWindow() override; - - bool noTitlebar(); - void setNoTitlebar(bool value); - - static DContextShellWindow *get(QWindow *window); - static DContextShellWindow *qmlAttachedProperties(QObject *object); - -Q_SIGNALS: - void noTitlebarChanged(); - -private: - DContextShellWindow(QWindow *window); - QScopedPointer d; -}; -DGUI_END_NAMESPACE diff --git a/src/wayland/protocol/treeland-personalization-manager-v1.xml b/src/wayland/protocol/treeland-personalization-manager-v1.xml deleted file mode 100644 index 8d754ef..0000000 --- a/src/wayland/protocol/treeland-personalization-manager-v1.xml +++ /dev/null @@ -1,218 +0,0 @@ - - - - SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. - - SPDX-License-Identifier: LGPL-3.0-or-later - - - - This interface allows a client to customized display effects. - - Warning! The protocol described in this file is currently in the testing - phase. Backward compatible changes may be added together with the - corresponding interface version bump. Backward incompatible changes can - only be done by creating a new major version of the extension. - - - - set window background, shadow based on context - - - - - - - custom user wallpaper - - - - - - custom user cursor - - - - - - - This interface allows a client personalization wallpaper. - - Warning! The protocol described in this file is currently in the testing - phase. Backward compatible changes may be added together with the - corresponding interface version bump. Backward incompatible changes can - only be done by creating a new major version of the extension. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - get the current user's wallpaper - - - - - Destroy the context object. - - - - - Send this signal after getting the user's wallpaper. - - - - - - - This interface allows a client personalization cursor. - - Warning! The protocol described in this file is currently in the testing - phase. Backward compatible changes may be added together with the - corresponding interface version bump. Backward incompatible changes can - only be done by creating a new major version of the extension. - - - - - - - - - - - - - - - - - - if only one commit fails validation, the commit will fail - - - - - Destroy the context object. - - - - - Send this signal after commit cursor configure. - - - - - - Send this signal after system cursor theme changed. - - - - - - Send this signal after system cursor size changed. - - - - - - - This interface allows a client personalization window. - - Warning! The protocol described in this file is currently in the testing - phase. Backward compatible changes may be added together with the - corresponding interface version bump. Backward incompatible changes can - only be done by creating a new major version of the extension. - - - - Window blend mode defines how compositor composite window's surface over other surfaces. - - - - - - - - Set window background blend mode - - - - - - This request will set window round corner radius, invoking this request means user want to - manage window round corner radius by itself. If not invoked, window round corner radius will - be decided by compositor. - - - - - - Set window shadow's radius, offset and color, invoking this request indicates that client want to manage - the window shadow by itself. If not invoked, window shadow will be decided by the compositor - - - - - - - - - - - - Set window border width and color - - - - - - - - - - Set window enable mode - - - - - - - Set if system titlebar is enabled - - - - - - Destroy the context object. - - - - diff --git a/src/wayland/qwaylandpersonalizationshellintegration.cpp b/src/wayland/qwaylandpersonalizationshellintegration.cpp deleted file mode 100644 index b0d2655..0000000 --- a/src/wayland/qwaylandpersonalizationshellintegration.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#include "qwaylandpersonalizationshellintegration_p.h" -#include "qwaylandwindowcontextshellsurface_p.h" -#include "wayland-treeland-personalization-manager-v1-client-protocol.h" - -DGUI_BEGIN_NAMESPACE -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -QWaylandPersonalizationShellIntegration::QWaylandPersonalizationShellIntegration() - : QWaylandShellIntegration() - -#else -QWaylandPersonalizationShellIntegration::QWaylandPersonalizationShellIntegration() - : QWaylandShellIntegrationTemplate(4) -#endif -{ -} - -QWaylandPersonalizationShellIntegration::~QWaylandPersonalizationShellIntegration() -{ - if (object() - && treeland_personalization_manager_v1_get_version(object()) - >= TREELAND_PERSONALIZATION_MANAGER_V1_GET_WINDOW_CONTEXT_SINCE_VERSION) { - treeland_personalization_manager_v1_destroy(object()); - } -} - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -bool QWaylandPersonalizationShellIntegration::initialize(QtWaylandClient::QWaylandDisplay *display) -{ - QWaylandShellIntegration::initialize(display); - display->addRegistryListener(registryPluginManager, this); - return m_manager != nullptr; -} - -struct personalization_window_context_v1 * -QWaylandPersonalizationShellIntegration::get_window_context(struct ::wl_surface *surface) -{ - return m_manager->get_window_context(surface); -} -#endif - -QtWaylandClient::QWaylandShellSurface *QWaylandPersonalizationShellIntegration::createShellSurface( - QtWaylandClient::QWaylandWindow *window) -{ - return new QWaylandWindowContextSurface(this, window); -} - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -void QWaylandPersonalizationShellIntegration::registryPluginManager(void *data, - struct wl_registry *registry, - uint32_t id, - const QString &interface, - uint32_t version) -{ - QWaylandPersonalizationShellIntegration *shell = - static_cast(data); - if (interface == treeland_personalization_manager_v1_interface.name) { - shell->m_manager.reset( - new QtWayland::treeland_personalization_manager_v1(registry, id, version)); - } -} -#endif -DGUI_END_NAMESPACE diff --git a/src/wayland/qwaylandpersonalizationshellintegration_p.h b/src/wayland/qwaylandpersonalizationshellintegration_p.h deleted file mode 100644 index 83cc6a9..0000000 --- a/src/wayland/qwaylandpersonalizationshellintegration_p.h +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#pragma once - -#include -#include -#include - -DGUI_BEGIN_NAMESPACE -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -class QWaylandWindowContextSurface; -class QWaylandPersonalizationShellIntegration : public QtWaylandClient::QWaylandShellIntegration -#else -class QWaylandPersonalizationShellIntegration - : public QtWaylandClient::QWaylandShellIntegrationTemplate< - QWaylandPersonalizationShellIntegration>, - public QtWayland::treeland_personalization_manager_v1 -#endif -{ -public: - QWaylandPersonalizationShellIntegration(); - ~QWaylandPersonalizationShellIntegration() override; - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - bool initialize(QtWaylandClient::QWaylandDisplay *display) override; - struct personalization_window_context_v1 *get_window_context(struct ::wl_surface *surface); - - struct treeland_personalization_manager_v1 *object() { return m_manager->object(); } -#endif - - QtWaylandClient::QWaylandShellSurface *createShellSurface( - QtWaylandClient::QWaylandWindow *window) override; - -private: -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - static void registryPluginManager(void *data, - struct wl_registry *registry, - uint32_t id, - const QString &interface, - uint32_t version); - QScopedPointer m_manager; -#endif -}; -DGUI_END_NAMESPACE diff --git a/src/wayland/qwaylandwindowcontextshellsurface.cpp b/src/wayland/qwaylandwindowcontextshellsurface.cpp deleted file mode 100644 index d29aa05..0000000 --- a/src/wayland/qwaylandwindowcontextshellsurface.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#include "dcontextshellwindow.h" -#include "qwaylandwindowcontextshellsurface_p.h" -#include "wayland/qwaylandpersonalizationshellintegration_p.h" - -#include -#include - -Q_LOGGING_CATEGORY(layershellsurface, "dde.shell.layershell.surface") - -DGUI_BEGIN_NAMESPACE -QWaylandWindowContextSurface::QWaylandWindowContextSurface( - QWaylandPersonalizationShellIntegration *shell, QtWaylandClient::QWaylandWindow *window) - : QtWaylandClient::QWaylandShellSurface(window) - , QtWayland::personalization_window_context_v1() - , m_dcontextShellWindow(DContextShellWindow::get(window->window())) -{ - init(shell->get_window_context(window->waylandSurface()->object())); - auto onNoTitlebarChanged = [this, window] { - if (m_dcontextShellWindow->noTitlebar()) { - set_no_titlebar(PERSONALIZATION_WINDOW_CONTEXT_V1_ENABLE_MODE_ENABLE); - } else { - set_no_titlebar(PERSONALIZATION_WINDOW_CONTEXT_V1_ENABLE_MODE_DISABLE); - } - window->waylandSurface()->commit(); - }; - - connect(m_dcontextShellWindow, - &DContextShellWindow::noTitlebarChanged, - this, - onNoTitlebarChanged); - - onNoTitlebarChanged(); -} - -QWaylandWindowContextSurface::~QWaylandWindowContextSurface() -{ - destroy(); -} -DGUI_END_NAMESPACE diff --git a/src/wayland/qwaylandwindowcontextshellsurface_p.h b/src/wayland/qwaylandwindowcontextshellsurface_p.h deleted file mode 100644 index 109e511..0000000 --- a/src/wayland/qwaylandwindowcontextshellsurface_p.h +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#pragma once - -#include "dcontextshellwindow.h" - -#include -#include -#include - -#include - -DGUI_BEGIN_NAMESPACE -class QWaylandPersonalizationShellIntegration; -class QWaylandWindowContextSurface : public QtWaylandClient::QWaylandShellSurface, - public QtWayland::personalization_window_context_v1 -{ - Q_OBJECT -public: - QWaylandWindowContextSurface(QWaylandPersonalizationShellIntegration *shell, - QtWaylandClient::QWaylandWindow *window); - ~QWaylandWindowContextSurface() override; - -private: - DContextShellWindow *m_dcontextShellWindow; -}; -DGUI_END_NAMESPACE diff --git a/src/wayland/wayland.cmake b/src/wayland/wayland.cmake deleted file mode 100644 index 08663d3..0000000 --- a/src/wayland/wayland.cmake +++ /dev/null @@ -1,10 +0,0 @@ -file(GLOB WAYLAND_HEADER - ${CMAKE_CURRENT_LIST_DIR}/*.h -) -file(GLOB WAYLAND_SOURCE - ${CMAKE_CURRENT_LIST_DIR}/*.cpp -) -set(wayland_SRC - ${WAYLAND_HEADER} - ${WAYLAND_SOURCE} -) diff --git a/tests/src/ut_dplatformtheme.cpp b/tests/src/ut_dplatformtheme.cpp index 07cd234..e0d2f5b 100644 --- a/tests/src/ut_dplatformtheme.cpp +++ b/tests/src/ut_dplatformtheme.cpp @@ -87,6 +87,7 @@ TEST_F(TDPlatformTheme, testSetFunction) ASSERT_EQ_BY_VALUE(setDndDragThreshold, dndDragThreshold, TEST_DATA); ASSERT_EQ_BY_NAME(setThemeName, themeName, "Theme"); ASSERT_EQ_BY_NAME(setIconThemeName, iconThemeName, "Icon"); + ASSERT_EQ_BY_NAME(setCursorThemeName, cursorThemeName, "Cursor"); ASSERT_EQ_BY_NAME(setSoundThemeName, soundThemeName, "Sound"); ASSERT_EQ_BY_NAME(setFontName, fontName, "Font"); ASSERT_EQ_BY_NAME(setMonoFontName, monoFontName, "MonoFont");