diff --git a/CMakeLists.txt b/CMakeLists.txt index b2061d8..8739711 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,8 @@ set(CMAKE_AUTORCC ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(THREADS_PREFER_PTHREAD_FLAG ON) +set(BUILD_EXAMPLES ON CACHE BOOL "Whether to build examples or not.") + find_package(Qt6 REQUIRED COMPONENTS Core DBus Concurrent) find_package(Threads REQUIRED) @@ -22,10 +24,13 @@ add_subdirectory(src) add_subdirectory(plugins) add_subdirectory(apps) -# add_subdirectory(docs) include(CTest) if(BUILD_TESTING) enable_testing() add_subdirectory(tests) endif() + +if(BUILD_EXAMPLES) + add_subdirectory(examples) +endif() diff --git a/apps/dde-application-manager/src/utils.cpp b/apps/dde-application-manager/src/utils.cpp index 8b241dc..716c332 100644 --- a/apps/dde-application-manager/src/utils.cpp +++ b/apps/dde-application-manager/src/utils.cpp @@ -7,7 +7,7 @@ bool registerObjectToDBus(QObject *o, const QString &path, const QString &interface) { auto &con = ApplicationManager1DBus::instance().globalServerBus(); - if (!con.registerObject(path, interface, o, QDBusConnection::RegisterOption::ExportAllContents)) { + if (!con.registerObject(path, interface, o, QDBusConnection::RegisterOption::ExportAdaptors)) { qFatal() << "register object failed:" << path << interface << con.lastError(); } else { qInfo() << "register object:" << path << interface; diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..3ac4d53 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(launchApp) diff --git a/examples/launchApp/CMakeLists.txt b/examples/launchApp/CMakeLists.txt new file mode 100644 index 0000000..b59d54d --- /dev/null +++ b/examples/launchApp/CMakeLists.txt @@ -0,0 +1,8 @@ +set(LAUNCHAPP_BIN launchApp) + +add_executable(${LAUNCHAPP_BIN} main.cpp) + +target_link_libraries(${LAUNCHAPP_BIN} PRIVATE + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::DBus +) diff --git a/examples/launchApp/main.cpp b/examples/launchApp/main.cpp new file mode 100644 index 0000000..524e68b --- /dev/null +++ b/examples/launchApp/main.cpp @@ -0,0 +1,76 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include +#include +#include +#include +#include + +class Demo : public QObject +{ + Q_OBJECT +public: + Demo() + : ApplicationManager(u8"org.deepin.dde.ApplicationManager1", + u8"/org/deepin/dde/ApplicationManager1", + u8"org.desktopspec.ApplicationManager1") + , JobManager(u8"org.deepin.dde.ApplicationManager1", + u8"/org/deepin/dde/ApplicationManager1/JobManager1", + u8"org.desktopspec.JobManager1") + { + auto con = JobManager.connection(); + if (!con.connect(JobManager.service(), + JobManager.path(), + JobManager.interface(), + u8"JobNew", + this, + SLOT(onJobNew(QDBusObjectPath, QDBusObjectPath)))) { + qFatal() << "connect JobNew failed."; + } + + if (!con.connect(JobManager.service(), + JobManager.path(), + JobManager.interface(), + u8"JobRemoved", + this, + SLOT(onJobRemoved(QDBusObjectPath, QString, QVariantList)))) { + qFatal() << "connect JobNew failed."; + } + } + + void launchApp(const QString &appId) + { + auto msg = + ApplicationManager.callWithArgumentList(QDBus::Block, "Launch", {appId, QString{""}, QStringList{}, QVariantMap{}}); + qInfo() << "reply message:" << msg; + } + +public Q_SLOTS: + void onJobNew(QDBusObjectPath job, QDBusObjectPath source) + { + qInfo() << "Job New [" + << "Job Path:" << job.path() << source.path() << "add this job]."; + } + + void onJobRemoved(QDBusObjectPath job, QString status, QVariantList result) + { + qInfo() << "Job Removed [" + << "Job Path:" << job.path() << "Job Status:" << status << "result:" << result; + } + +private: + QDBusInterface ApplicationManager; + QDBusInterface JobManager; +}; + +int main(int argc, char *argv[]) +{ + QCoreApplication app{argc, argv}; + Demo demo; + demo.launchApp("google-chrome"); + return QCoreApplication::exec(); +} + +#include "main.moc" diff --git a/src/dbus/applicationmanager1service.cpp b/src/dbus/applicationmanager1service.cpp index 2fc1ac2..10f433a 100644 --- a/src/dbus/applicationmanager1service.cpp +++ b/src/dbus/applicationmanager1service.cpp @@ -16,9 +16,9 @@ ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr())) { + new ApplicationManager1Adaptor{this}; + + if (!registerObjectToDBus(this, DDEApplicationManager1ObjectPath, getDBusInterface())) { std::terminate(); } @@ -106,7 +106,7 @@ QPair ApplicationManager1Service::processServiceName(const QSt instanceId = components.takeLast(); applicationId = components.takeLast(); } else { - qDebug() << "it's not service or slice or scope."; + qDebug() << "it's not service or scope:" << serviceName << "ignore."; return {}; } @@ -114,7 +114,7 @@ QPair ApplicationManager1Service::processServiceName(const QSt instanceId = QUuid::createUuid().toString(QUuid::Id128); } - return qMakePair(std::move(applicationId), std::move(instanceId)); + return qMakePair(unescapeApplicationId(applicationId), std::move(instanceId)); } QList ApplicationManager1Service::list() const diff --git a/src/dbus/applicationmanager1service.h b/src/dbus/applicationmanager1service.h index b77e082..cafde82 100644 --- a/src/dbus/applicationmanager1service.h +++ b/src/dbus/applicationmanager1service.h @@ -37,9 +37,9 @@ public: if (!application) { return false; } - if (!registerObjectToDBus(new ApplicationAdaptor{application.data()}, - application->m_applicationPath.path(), - getDBusInterface())) { + auto *ptr = application.data(); + new ApplicationAdaptor{ptr}; + if (!registerObjectToDBus(ptr, application->m_applicationPath.path(), getDBusInterface())) { return false; } m_applicationList.insert(application->m_applicationPath, application); diff --git a/src/dbus/applicationservice.cpp b/src/dbus/applicationservice.cpp index 686e2a0..1f67ce3 100644 --- a/src/dbus/applicationservice.cpp +++ b/src/dbus/applicationservice.cpp @@ -145,7 +145,7 @@ QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, Q if (resourceFile.isEmpty()) { auto instanceRandomUUID = QUuid::createUuid().toString(QUuid::Id128); commands.push_front(QString{R"(--unitName=app-DDE-%1@%2.service)"}.arg( - this->id(), instanceRandomUUID)); // launcher should use this instanceId + escapeApplicationId(this->id()), instanceRandomUUID)); // launcher should use this instanceId QProcess process; process.start(m_launcher, commands); process.waitForFinished(); @@ -255,7 +255,7 @@ bool ApplicationService::addOneInstance(const QString &instanceId, const QString auto adaptor = new InstanceAdaptor(service); QString objectPath{DDEApplicationManager1InstanceObjectPath + instanceId}; - if (registerObjectToDBus(adaptor, objectPath, getDBusInterface())) { + if (registerObjectToDBus(service, objectPath, getDBusInterface())) { m_Instances.insert(QDBusObjectPath{objectPath}, QSharedPointer{service}); service->moveToThread(this->thread()); adaptor->moveToThread(this->thread()); diff --git a/src/dbus/jobmanager1service.cpp b/src/dbus/jobmanager1service.cpp index ef3e7a2..2d7e72f 100644 --- a/src/dbus/jobmanager1service.cpp +++ b/src/dbus/jobmanager1service.cpp @@ -5,18 +5,14 @@ #include "dbus/jobmanager1service.h" #include "dbus/jobmanager1adaptor.h" -LaunchTask::LaunchTask() -{ - qRegisterMetaType(); -} - JobManager1Service::JobManager1Service(ApplicationManager1Service *parent) : m_parent(parent) { - if (!registerObjectToDBus( - new JobManager1Adaptor{this}, DDEApplicationManager1JobManagerObjectPath, getDBusInterface())) { + new JobManager1Adaptor{this}; + if (!registerObjectToDBus(this, DDEApplicationManager1JobManagerObjectPath, getDBusInterface())) { std::terminate(); } + qRegisterMetaType(); } JobManager1Service::~JobManager1Service() = default; diff --git a/src/dbus/jobmanager1service.h b/src/dbus/jobmanager1service.h index 9a31480..b64291e 100644 --- a/src/dbus/jobmanager1service.h +++ b/src/dbus/jobmanager1service.h @@ -22,7 +22,7 @@ class ApplicationManager1Service; struct LaunchTask { - LaunchTask(); + LaunchTask() = default; ~LaunchTask() = default; LaunchTask(const LaunchTask &) = default; LaunchTask(LaunchTask &&) = default; @@ -57,7 +57,10 @@ public: QVariantList{}, QtConcurrent::ReduceOption::OrderedReduce); QSharedPointer job{new JobService{future}}; - if (!registerObjectToDBus(new JobAdaptor(job.data()), objectPath, getDBusInterface())) { + + auto *ptr = job.data(); + new JobAdaptor(ptr); + if (!registerObjectToDBus(ptr, objectPath, getDBusInterface())) { qCritical() << "can't register job to dbus."; future.cancel(); return {}; diff --git a/src/global.h b/src/global.h index e2543c9..966b432 100644 --- a/src/global.h +++ b/src/global.h @@ -254,13 +254,46 @@ inline QString unescapeFromObjectPath(const QString &str) for (qsizetype i = 0; i < str.size(); ++i) { if (str[i] == '_' and i + 2 < str.size()) { auto hexStr = str.sliced(i + 1, 2); - ret.replace(hexStr, QChar::fromLatin1(hexStr.toUInt(nullptr, 16))); + ret.replace(QString{"_%1"}.arg(hexStr), QChar::fromLatin1(hexStr.toUInt(nullptr, 16))); i += 2; } } return ret; } +inline QString escapeApplicationId(const QString &id) +{ + if (id.isEmpty()) { + return id; + } + + auto ret = id; + QRegularExpression re{R"([^a-zA-Z0-9])"}; + auto matcher = re.globalMatch(ret); + while (matcher.hasNext()) { + auto replaceList = matcher.next().capturedTexts(); + replaceList.removeDuplicates(); + for (const auto &c : replaceList) { + auto hexStr = QString::number(static_cast(c.front().toLatin1()), 16); + ret.replace(c, QString{R"(\x%1)"}.arg(hexStr)); + } + } + return ret; +} + +inline QString unescapeApplicationId(const QString &id) +{ + auto ret = id; + for (qsizetype i = 0; i < id.size(); ++i) { + if (id[i] == '\\' and i + 3 < id.size()) { + auto hexStr = id.sliced(i + 2, 2); + ret.replace(QString{R"(\x%1)"}.arg(hexStr), QChar::fromLatin1(hexStr.toUInt(nullptr, 16))); + i += 3; + } + } + return ret; +} + inline QString getRelativePathFromAppId(const QString &id) { QString path;