diff --git a/example/applet-example-data/exampleapplet.cpp b/example/applet-example-data/exampleapplet.cpp index 28e080e93..2944450a4 100644 --- a/example/applet-example-data/exampleapplet.cpp +++ b/example/applet-example-data/exampleapplet.cpp @@ -25,7 +25,7 @@ bool ExampleApplet::load() { DCORE_USE_NAMESPACE; std::unique_ptr config(DConfig::create("org.deepin.dde.shell", "org.deepin.ds.example")); - return config->value("loadAppletExampleData").toBool(); + return config->value("loadAppletExampleData", true).toBool(); } bool ExampleApplet::init() @@ -56,6 +56,11 @@ void ExampleApplet::setUserData(bool newUserData) emit userDataChanged(); } +QString ExampleApplet::call(const QString &id) +{ + return id + QString("-done"); +} + D_APPLET_CLASS(ExampleApplet) #include "exampleapplet.moc" diff --git a/example/applet-example-data/exampleapplet.h b/example/applet-example-data/exampleapplet.h index a2f2bf3ed..f091ef17d 100644 --- a/example/applet-example-data/exampleapplet.h +++ b/example/applet-example-data/exampleapplet.h @@ -25,9 +25,12 @@ class ExampleApplet : public DApplet bool userData() const; void setUserData(bool newUserData); + Q_INVOKABLE QString call(const QString &id); + Q_SIGNALS: void mainTextChanged(); void userDataChanged(); + void sendSignal(const QString &id); private: QString m_mainText; bool m_userData; diff --git a/example/containment-example/examplecontainment.cpp b/example/containment-example/examplecontainment.cpp index 9df2c7372..4df4d0cd5 100644 --- a/example/containment-example/examplecontainment.cpp +++ b/example/containment-example/examplecontainment.cpp @@ -6,6 +6,7 @@ #include "pluginfactory.h" #include "pluginloader.h" +#include "appletproxy.h" #include #include #include @@ -67,6 +68,11 @@ bool ExampleContainment::load() return DApplet::load(); } +QObject *ExampleContainment::createProxyMeta() +{ + return new ExampleAppletProxy(this); +} + DPluginMetaData ExampleContainment::targetPlugin() const { auto children = DPluginLoader::instance()->childrenPlugin(pluginId()); diff --git a/example/containment-example/examplecontainment.h b/example/containment-example/examplecontainment.h index ad7b0b2d5..111938134 100644 --- a/example/containment-example/examplecontainment.h +++ b/example/containment-example/examplecontainment.h @@ -8,6 +8,21 @@ DS_USE_NAMESPACE +class ExampleAppletProxy : public QObject +{ + Q_OBJECT +public: + ExampleAppletProxy(QObject *parent = nullptr) + : QObject(parent) + { + + } + Q_INVOKABLE QString call(const QString &id) + { + return id + QString("-done"); + } +}; + class ExampleContainment : public DContainment { Q_OBJECT @@ -16,6 +31,8 @@ class ExampleContainment : public DContainment ~ExampleContainment(); virtual bool load() override; +protected: + virtual QObject *createProxyMeta() override; private: DPluginMetaData targetPlugin() const; }; diff --git a/example/panel-example/examplepanel.cpp b/example/panel-example/examplepanel.cpp index f1ade548e..e9822e9df 100644 --- a/example/panel-example/examplepanel.cpp +++ b/example/panel-example/examplepanel.cpp @@ -5,6 +5,7 @@ #include "examplepanel.h" #include "pluginfactory.h" +#include "appletbridge.h" ExamplePanel::ExamplePanel(QObject *parent) : DPanel(parent) @@ -19,6 +20,35 @@ bool ExamplePanel::load() bool ExamplePanel::init() { DPanel::init(); + + DAppletBridge bridge("org.deepin.ds.example.applet-data"); + + qDebug() << "It's state of the bridge:" << bridge.isValid(); + if (auto applet = bridge.applet()) { + qDebug() << "Get property:" << applet->property("mainText"); + QString id("call"); + qDebug() << "Invoke argument:" << id; + qDebug() << "Invoke method staus:" << QMetaObject::invokeMethod(applet, "call", Qt::DirectConnection, + Q_RETURN_ARG(QString, id), Q_ARG(const QString&, id)); + qDebug() << "Invoked returd value:" << id; + + QObject::connect(applet, SIGNAL(sendSignal(const QString &)), SLOT(onReceivedSignal(const QString &))); + + QMetaObject::invokeMethod(applet, "sendSignal", Qt::DirectConnection, Q_ARG(const QString&, id)); + } + + { + DAppletBridge bridge("org.deepin.ds.example.containment"); + qDebug() << "Customize MetaObject of the applet:" << bridge.isValid(); + if (auto applet = bridge.applet()) { + QString id("call"); + qDebug() << "Invoke argument:" << id; + qDebug() << "Invoke method staus:" << QMetaObject::invokeMethod(applet, "call", Qt::DirectConnection, + Q_RETURN_ARG(QString, id), Q_ARG(const QString&, id)); + qDebug() << "Invoked returd value:" << id; + } + } + QObject::connect(this, &DApplet::rootObjectChanged, this, [this]() { Q_ASSERT(rootObject()); Q_ASSERT(window()); @@ -27,6 +57,11 @@ bool ExamplePanel::init() return true; } +void ExamplePanel::onReceivedSignal(const QString &id) +{ + qDebug() << "Received signal:" << id; +} + D_APPLET_CLASS(ExamplePanel) #include "examplepanel.moc" diff --git a/example/panel-example/examplepanel.h b/example/panel-example/examplepanel.h index 0e6a5ec92..d46a98416 100644 --- a/example/panel-example/examplepanel.h +++ b/example/panel-example/examplepanel.h @@ -17,4 +17,8 @@ class ExamplePanel : public DPanel virtual bool load() override; virtual bool init() override; + +private slots: + void onReceivedSignal(const QString &id); + }; diff --git a/frame/CMakeLists.txt b/frame/CMakeLists.txt index e3f0f5ba5..b89d1ecf2 100644 --- a/frame/CMakeLists.txt +++ b/frame/CMakeLists.txt @@ -11,6 +11,8 @@ set(PUBLIC_HEADERS appletdata.h containment.h panel.h + appletproxy.h + appletbridge.h qmlengine.h layershell/dlayershellwindow.h dsutility.h @@ -21,6 +23,8 @@ set(PRIVATE_HEADERS private/containment_p.h private/panel_p.h private/appletitem_p.h + private/appletproxy_p.h + private/appletbridge_p.h private/dsqmlglobal_p.h layershell/qwaylandlayershellsurface_p.h layershell/qwaylandlayershellintegration_p.h @@ -50,6 +54,8 @@ add_library(dde-shell-frame SHARED applet.cpp containment.cpp panel.cpp + appletproxy.cpp + appletbridge.cpp appletitem.cpp containmentitem.cpp qmlengine.cpp diff --git a/frame/applet.cpp b/frame/applet.cpp index 4d72d618c..ec21be704 100644 --- a/frame/applet.cpp +++ b/frame/applet.cpp @@ -4,6 +4,7 @@ #include "applet.h" #include "private/applet_p.h" +#include "private/appletproxy_p.h" #include #include @@ -26,6 +27,16 @@ DAppletPrivate::~DAppletPrivate() } } +DAppletProxy *DAppletPrivate::appletProxy() const +{ + if (!m_proxy) { + auto meta = const_cast(this)->q_func()->createProxyMeta(); + const_cast(this)->m_proxy = + new DAppletMetaProxy(meta, const_cast(this)->q_func()); + } + return m_proxy; +} + DApplet::DApplet(QObject *parent) : DApplet(*new DAppletPrivate(this), parent) { @@ -109,4 +120,10 @@ bool DApplet::init() return true; } +QObject *DApplet::createProxyMeta() +{ + D_DC(DApplet); + return this; +} + DS_END_NAMESPACE diff --git a/frame/applet.h b/frame/applet.h index 2195f4c8b..fc63f235f 100644 --- a/frame/applet.h +++ b/frame/applet.h @@ -17,6 +17,7 @@ DS_BEGIN_NAMESPACE */ class DAppletPrivate; class DPluginLoader; +class DAppletBridge; class DS_SHARE DApplet : public QObject, public DTK_CORE_NAMESPACE::DObject { Q_OBJECT @@ -26,6 +27,7 @@ class DS_SHARE DApplet : public QObject, public DTK_CORE_NAMESPACE::DObject Q_PROPERTY(QObject *rootObject READ rootObject NOTIFY rootObjectChanged) D_DECLARE_PRIVATE(DApplet) friend class DPluginLoader; + friend class DAppletBridge; public: explicit DApplet(QObject *parent = nullptr); virtual ~DApplet() override; @@ -48,6 +50,7 @@ class DS_SHARE DApplet : public QObject, public DTK_CORE_NAMESPACE::DObject protected: explicit DApplet(DAppletPrivate &dd, QObject *parent = nullptr); + virtual QObject *createProxyMeta(); private: void setMetaData(const DPluginMetaData &metaData); diff --git a/frame/appletbridge.cpp b/frame/appletbridge.cpp new file mode 100644 index 000000000..dd0aabb53 --- /dev/null +++ b/frame/appletbridge.cpp @@ -0,0 +1,95 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "appletbridge.h" +#include "containment.h" +#include "private/appletbridge_p.h" +#include "private/applet_p.h" + +#include "pluginloader.h" +#include + +DS_BEGIN_NAMESPACE + +DAppletBridgePrivate::DAppletBridgePrivate(DAppletBridge *qq) + : DTK_CORE_NAMESPACE::DObjectPrivate(qq) +{ +} + +DAppletBridgePrivate::~DAppletBridgePrivate() +{ +} + +QList DAppletBridgePrivate::applets() const +{ + QList applets; + auto rootApplet = DPluginLoader::instance()->rootApplet(); + auto root = qobject_cast(rootApplet); + + QQueue containments; + containments.enqueue(root); + while (!containments.isEmpty()) { + DContainment *containment = containments.dequeue(); + for (const auto applet : containment->applets()) { + if (auto item = qobject_cast(applet)) { + containments.enqueue(item); + } + if (applet->pluginId() == m_pluginId) + applets << applet; + } + } + return applets; +} + +DAppletBridge::DAppletBridge(const QString &pluginId, QObject *parent) + : DAppletBridge(*new DAppletBridgePrivate(this), parent) +{ + d_func()->m_pluginId = pluginId; +} + +DAppletBridge::DAppletBridge(DAppletBridgePrivate &dd, QObject *parent) + : QObject(parent) + , DObject(dd) +{ +} + +DAppletBridge::~DAppletBridge() +{ +} + +bool DAppletBridge::isValid() const +{ + D_DC(DAppletBridge); + const auto plugin = DPluginLoader::instance()->plugin(d->m_pluginId); + return plugin.isValid(); +} + +QList DAppletBridge::applets() const +{ + D_DC(DAppletBridge); + if (!isValid()) + return {}; + QList ret; + for (const auto item : d->applets()) { + if (auto proxy = item->d_func()->appletProxy()) { + ret << proxy; + } + } + return ret; +} + +DAppletProxy *DAppletBridge::applet() const +{ + D_DC(DAppletBridge); + if (!isValid()) + return {}; + for (const auto item : d->applets()) { + if (auto proxy = item->d_func()->appletProxy()) { + return proxy; + } + } + return nullptr; +} + +DS_END_NAMESPACE diff --git a/frame/appletbridge.h b/frame/appletbridge.h new file mode 100644 index 000000000..d6c42aeb7 --- /dev/null +++ b/frame/appletbridge.h @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "dsglobal.h" +#include "appletproxy.h" + +#include +#include + +DS_BEGIN_NAMESPACE +/** + * @brief Interacting with other applets + */ +class DAppletBridgePrivate; +class DS_SHARE DAppletBridge : public QObject, public DTK_CORE_NAMESPACE::DObject +{ + Q_OBJECT + D_DECLARE_PRIVATE(DAppletBridge) +public: + explicit DAppletBridge(const QString &pluginId, QObject *parent = nullptr); + virtual ~DAppletBridge() override; + + bool isValid() const; + + QList applets() const; + DAppletProxy *applet() const; + +protected: + explicit DAppletBridge(DAppletBridgePrivate &dd, QObject *parent = nullptr); +}; + +DS_END_NAMESPACE diff --git a/frame/appletproxy.cpp b/frame/appletproxy.cpp new file mode 100644 index 000000000..9e091285e --- /dev/null +++ b/frame/appletproxy.cpp @@ -0,0 +1,82 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "appletproxy.h" +#include "private/appletproxy_p.h" +#include "applet.h" + +#include + +DS_BEGIN_NAMESPACE + +DAppletProxyPrivate::DAppletProxyPrivate(DAppletProxy *qq) + : DTK_CORE_NAMESPACE::DObjectPrivate(qq) +{ +} + +DAppletProxyPrivate::~DAppletProxyPrivate() +{ +} + +DAppletProxy::DAppletProxy(QObject *parent) + : DAppletProxy(*new DAppletProxyPrivate(this), parent) +{ +} + +DAppletProxy::DAppletProxy(DAppletProxyPrivate &dd, QObject *parent) + : QObject(parent) + , DObject(dd) +{ + +} + +DAppletProxy::~DAppletProxy() +{ +} + +class DAppletMetaProxyPrivate : public DAppletProxyPrivate +{ +public: + DAppletMetaProxyPrivate(DAppletMetaProxy *qq) + : DAppletProxyPrivate(qq) + { + } + QPointer meta; +}; + +DAppletMetaProxy::DAppletMetaProxy(QObject *meta, QObject *parent) + : DAppletProxy(*new DAppletMetaProxyPrivate(this), parent) +{ + d_func()->meta = meta; +} + +const QMetaObject *DAppletMetaProxy::metaObject() const +{ + D_DC(DAppletMetaProxy); + if (d->meta) + return d->meta->metaObject(); + return &DAppletProxy::staticMetaObject; +} + +void *DAppletMetaProxy::qt_metacast(const char *clname) +{ + D_D(DAppletMetaProxy); + if (d->meta) + return static_cast(const_cast(d->meta.data())); + if (!clname) return nullptr; + return DAppletProxy::qt_metacast(clname); +} + +int DAppletMetaProxy::qt_metacall(QMetaObject::Call c, int id, void **argv) +{ + D_D(DAppletMetaProxy); + if (d->meta) { + auto _id = d->meta->qt_metacall(c, id, argv); + if (_id >= 0) + return _id; + } + return DAppletProxy::qt_metacall(c, id, argv); +} + +DS_END_NAMESPACE diff --git a/frame/appletproxy.h b/frame/appletproxy.h new file mode 100644 index 000000000..cfeb1d4cb --- /dev/null +++ b/frame/appletproxy.h @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "dsglobal.h" + +#include +#include + +DS_BEGIN_NAMESPACE +/** + * @brief Expose own interfaces for other applets. + */ +class DAppletProxyPrivate; +class DS_SHARE DAppletProxy : public QObject, public DTK_CORE_NAMESPACE::DObject +{ + D_DECLARE_PRIVATE(DAppletProxy) +public: + ~DAppletProxy() override; + +protected: + explicit DAppletProxy(QObject *parent = nullptr); + explicit DAppletProxy(DAppletProxyPrivate &dd, QObject *parent = nullptr); +}; + +DS_END_NAMESPACE diff --git a/frame/private/applet_p.h b/frame/private/applet_p.h index d06ec9bac..c9a75b6bf 100644 --- a/frame/private/applet_p.h +++ b/frame/private/applet_p.h @@ -5,6 +5,7 @@ #pragma once #include "applet.h" +#include "appletproxy.h" #include #include @@ -20,9 +21,12 @@ class DAppletPrivate : public DTK_CORE_NAMESPACE::DObjectPrivate explicit DAppletPrivate(DApplet *qq); ~DAppletPrivate() override; + DAppletProxy *appletProxy() const; + DPluginMetaData m_metaData; DAppletData m_data; QPointer m_rootObject; + DAppletProxy *m_proxy = nullptr; D_DECLARE_PUBLIC(DApplet); }; diff --git a/frame/private/appletbridge_p.h b/frame/private/appletbridge_p.h new file mode 100644 index 000000000..ccba20cfd --- /dev/null +++ b/frame/private/appletbridge_p.h @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "appletbridge.h" +#include "applet.h" + +#include +#include + +DS_BEGIN_NAMESPACE +/** + * @brief + */ +class DAppletBridgePrivate : public DTK_CORE_NAMESPACE::DObjectPrivate +{ +public: + explicit DAppletBridgePrivate(DAppletBridge *qq); + ~DAppletBridgePrivate() override; + + QList applets() const; + + QString m_pluginId; + + D_DECLARE_PUBLIC(DAppletBridge); +}; + +DS_END_NAMESPACE diff --git a/frame/private/appletproxy_p.h b/frame/private/appletproxy_p.h new file mode 100644 index 000000000..e34ecd3e9 --- /dev/null +++ b/frame/private/appletproxy_p.h @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "appletproxy.h" + +#include +#include +#include + +DS_BEGIN_NAMESPACE +/** + * @brief + */ +class DAppletProxyPrivate : public DTK_CORE_NAMESPACE::DObjectPrivate +{ +public: + DAppletProxyPrivate(DAppletProxy *qq); + ~DAppletProxyPrivate() override; + + D_DECLARE_PUBLIC(DAppletProxy); +}; + +class DAppletMetaProxyPrivate; +class DAppletMetaProxy : public DAppletProxy +{ + D_DECLARE_PRIVATE(DAppletMetaProxy) +public: + explicit DAppletMetaProxy(QObject *meta, QObject *parent); + + virtual const QMetaObject *metaObject() const override; + virtual void *qt_metacast(const char *clname) override; + virtual int qt_metacall(QMetaObject::Call c, int id, void **argv) override; +}; + +DS_END_NAMESPACE