From 703a27c1ee0c3b093b5dec6e14a7cbd3a2941097 Mon Sep 17 00:00:00 2001 From: Ye ShanShan Date: Fri, 22 Mar 2024 16:29:33 +0800 Subject: [PATCH] feat: add dde-am tool to launch application add dde-am tool. --- CMakeLists.txt | 2 + apps/CMakeLists.txt | 1 + apps/dde-am/CMakeLists.txt | 1 + apps/dde-am/src/CMakeLists.txt | 17 ++ apps/dde-am/src/launcher.cpp | 150 ++++++++++++++++++ apps/dde-am/src/launcher.h | 30 ++++ apps/dde-am/src/main.cpp | 64 ++++++++ debian/control | 2 + misc/CMakeLists.txt | 4 + .../org.deepin.dde.am.json | 16 ++ src/config.h.in | 3 + src/constant.h | 2 + 12 files changed, 292 insertions(+) create mode 100644 apps/dde-am/CMakeLists.txt create mode 100644 apps/dde-am/src/CMakeLists.txt create mode 100644 apps/dde-am/src/launcher.cpp create mode 100644 apps/dde-am/src/launcher.h create mode 100644 apps/dde-am/src/main.cpp create mode 100644 misc/dsg/configs/dde-application-manager/org.deepin.dde.am.json diff --git a/CMakeLists.txt b/CMakeLists.txt index e58fa05..3d4f708 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,11 +23,13 @@ set(DDE_AM_USE_DEBUG_DBUS_NAME OFF CACHE BOOL "build a dbus service using a diff set(PROFILING_MODE OFF CACHE BOOL "run a valgrind performance profiling.") find_package(Qt6 REQUIRED COMPONENTS Core DBus Concurrent) +find_package(Dtk6 REQUIRED COMPONENTS Core) find_package(Threads REQUIRED) set(APP_LAUNCH_HELPER_BIN app-launch-helper) set(APP_UPDATE_NOTIFIER_BIN app-update-notifier) set(AM_LIBEXEC_DIR ${CMAKE_INSTALL_LIBEXECDIR}/deepin/application-manager) +set(APPLICATION_SERVICEID "org.deepin.dde.application-manager") if(DDE_AM_USE_DEBUG_DBUS_NAME) add_compile_definitions(-DDDE_AM_USE_DEBUG_DBUS_NAME) diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 07bcfea..ceb21c4 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(dde-application-manager) add_subdirectory(app-launch-helper) add_subdirectory(app-update-notifier) add_subdirectory(app-identifier) +add_subdirectory(dde-am) diff --git a/apps/dde-am/CMakeLists.txt b/apps/dde-am/CMakeLists.txt new file mode 100644 index 0000000..febd4f0 --- /dev/null +++ b/apps/dde-am/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(src) diff --git a/apps/dde-am/src/CMakeLists.txt b/apps/dde-am/src/CMakeLists.txt new file mode 100644 index 0000000..4190c82 --- /dev/null +++ b/apps/dde-am/src/CMakeLists.txt @@ -0,0 +1,17 @@ +set(BIN_NAME dde-am) + +add_executable(${BIN_NAME} main.cpp + launcher.h launcher.cpp +) + +target_link_libraries(${BIN_NAME} PRIVATE + dde_am_static + Dtk6::Core +) + +target_include_directories(${BIN_NAME} PRIVATE + ${PROJECT_SOURCE_DIR}/src + ${PROJECT_BINARY_DIR}/src +) + +install(TARGETS ${BIN_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/apps/dde-am/src/launcher.cpp b/apps/dde-am/src/launcher.cpp new file mode 100644 index 0000000..3fbfb0d --- /dev/null +++ b/apps/dde-am/src/launcher.cpp @@ -0,0 +1,150 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "launcher.h" +#include "global.h" + +#include +#include +#include + +DCORE_USE_NAMESPACE + +namespace { +void registerComplexDbusType() +{ + qRegisterMetaType(); + qDBusRegisterMetaType(); + qRegisterMetaType(); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); +} + +template +DExpected parseDBusField(const QVariantMap &map, const QString &key) +{ + if (!map.contains(key)) + return DUnexpected{emplace_tag::USE_EMPLACE, -1, QString("%1 doesn't exist.").arg(key)}; + const auto value = map.value(key); + return DExpected{qdbus_cast(value)}; +} + +ObjectMap getManagedObjects() +{ + registerComplexDbusType(); + + auto con = QDBusConnection::sessionBus(); + auto msg = QDBusMessage::createMethodCall( + DDEApplicationManager1ServiceName, DDEApplicationManager1ObjectPath, ObjectManagerInterface, "GetManagedObjects"); + + auto reply = con.call(msg); + + if (reply.type() != QDBusMessage::ReplyMessage) { + qFatal() << "Failed to fetch application infos" << reply.errorMessage(); + } + const auto &arguments = reply.arguments(); + Q_ASSERT_X(!arguments.isEmpty(), "", "Incorrect reply argument for GetManagedObjects call."); + + return qdbus_cast(arguments.first()); +} +} // namespace + +DExpected Launcher::appIds() +{ + QStringList appIds; + const auto objects = getManagedObjects(); + for (auto iter = objects.cbegin(); iter != objects.cend(); ++iter) { + const auto &objPath = iter.key().path(); + const ObjectInterfaceMap &objs = iter.value(); + const QVariantMap appInfo = objs.value("org.desktopspec.ApplicationManager1.Application"); + if (appInfo.isEmpty()) + continue; + if (auto value = parseDBusField(appInfo, u8"ID")) { + appIds.append(value.value()); + } else { + qFatal() << "Failed to parse application ID"; + } + } + return appIds; +} + +void Launcher::setPath(const QString &path) +{ + m_path = path; +} + +void Launcher::setAction(const QString &action) +{ + m_action = action; +} + +void Launcher::setLaunchedType(LaunchedType type) +{ + m_launchedType = type; +} + +DExpected Launcher::run() +{ + if (auto value = launch(); !value) + return value; + + if (m_launchedType == ByUser) + if (auto ret = updateLaunchedTimes(); !ret) + return ret; + + return {}; +} + +DExpected Launcher::launch() +{ + auto con = QDBusConnection::sessionBus(); + auto msg = QDBusMessage::createMethodCall( + DDEApplicationManager1ServiceName, m_path, ApplicationInterface, "Launch"); + const QList arguments { + m_action, + QStringList{}, + QVariantMap{} + }; + msg.setArguments(arguments); + auto reply = con.call(msg); + + if (reply.type() != QDBusMessage::ReplyMessage) { + return DUnexpected{emplace_tag::USE_EMPLACE, + static_cast(reply.type()), + QString("Failed to launch: %1, error: %2").arg(appId(), reply.errorMessage())}; + } + return {}; +} + +DExpected Launcher::updateLaunchedTimes() +{ + std::unique_ptr config(DConfig::create(ApplicationServiceID, ApplicationManagerToolsConfig)); + if (!config->isValid()) + return DUnexpected{emplace_tag::USE_EMPLACE, -1, + "DConfig is invalid when updating launched times."}; + + const QString AppsLaunchedTimes(u8"appsLaunchedTimes"); + QVariantMap launchedTimes = config->value(AppsLaunchedTimes).toMap(); + const auto appKey = appId(); + if (appKey.isEmpty()) + return DUnexpected{emplace_tag::USE_EMPLACE, -1, QString("Empty appId for the path: %1").arg(m_path)}; + + launchedTimes[appKey] = launchedTimes[appKey].toLongLong() + 1; + config->setValue(AppsLaunchedTimes, launchedTimes); + return {}; +} + +QString Launcher::appId() const +{ + if (m_path.isEmpty()) return {}; + const auto startIndex = QString(DDEApplicationManager1ObjectPath).size(); + auto endIndex = m_path.indexOf("/", startIndex + 1); + const auto id = endIndex <= -1 ? m_path.mid(startIndex + 1) : + m_path.sliced(startIndex + 1, endIndex - (startIndex + 1)); + return unescapeFromObjectPath(id); +} diff --git a/apps/dde-am/src/launcher.h b/apps/dde-am/src/launcher.h new file mode 100644 index 0000000..0540ae3 --- /dev/null +++ b/apps/dde-am/src/launcher.h @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include +#include + +class Launcher { +public: + enum LaunchedType{ + Unknown, + ByUser, + }; + void setPath(const QString &path); + void setAction(const QString &action); + void setLaunchedType(LaunchedType type); + Dtk::Core::DExpected run(); + + static Dtk::Core::DExpected appIds(); +private: + Dtk::Core::DExpected launch(); + Dtk::Core::DExpected updateLaunchedTimes(); + QString appId() const; + + QString m_path; + QString m_action; + LaunchedType m_launchedType = Unknown; +}; diff --git a/apps/dde-am/src/main.cpp b/apps/dde-am/src/main.cpp new file mode 100644 index 0000000..042beaf --- /dev/null +++ b/apps/dde-am/src/main.cpp @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include +#include +#include + +#include "launcher.h" +#include "global.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication app{argc, argv}; + + QCommandLineParser parser; + parser.addHelpOption(); + parser.addVersionOption(); + + QCommandLineOption listOption("list", "List all appId."); + parser.addOption(listOption); + QCommandLineOption launchedByUserOption("by-user", + "Launched by user, it's useful for counting launched times."); + parser.addOption(launchedByUserOption); + parser.addPositionalArgument("appId", "Application's ID."); + parser.addPositionalArgument("action", "Name of the action identifiers for the application, optionally."); + + parser.process(app); + if (parser.isSet(listOption)) { + const auto apps = Launcher::appIds(); + if (!apps) { + qWarning() << apps.error(); + return apps.error().getErrorCode(); + } + for (const auto &item :apps.value()) { + qDebug() << qPrintable(item); + } + return 0; + } + + auto arguments = parser.positionalArguments(); + if (arguments.size() < 1) + parser.showHelp(); + + Launcher launcher; + if (parser.isSet(launchedByUserOption)) + launcher.setLaunchedType(Launcher::ByUser); + + const auto pos1 = arguments.takeFirst(); + QString appPath = pos1.startsWith("/") ? pos1 : + QString("%1/%2").arg(DDEApplicationManager1ObjectPath, escapeToObjectPath(pos1)); + launcher.setPath(appPath); + if (arguments.size() >= 1) { + const auto action = arguments.takeFirst(); + launcher.setAction(action); + } + + auto ret = launcher.run(); + if (!ret) { + qWarning() << ret.error(); + return ret.error().getErrorCode(); + } + return 0; +} diff --git a/debian/control b/debian/control index 206f9a4..7af4914 100644 --- a/debian/control +++ b/debian/control @@ -7,6 +7,8 @@ Build-Depends: debhelper-compat ( =12), cmake, libsystemd-dev, pkg-config, qt6-base-dev, + libdtkcommon-dev, + libdtk6core-dev, Standards-Version: 4.5.0 Homepage: https://github.com/linuxdeepin/dde-application-manager diff --git a/misc/CMakeLists.txt b/misc/CMakeLists.txt index 98a85c0..25303d1 100644 --- a/misc/CMakeLists.txt +++ b/misc/CMakeLists.txt @@ -74,3 +74,7 @@ set(DCONFIG_FILES ) install(FILES ${DCONFIG_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/dsg/configs/dde-application-manager) + +dtk_add_config_meta_files(APPID ${APPLICATION_SERVICEID} + FILES ${CMAKE_CURRENT_LIST_DIR}/dsg/configs/dde-application-manager/org.deepin.dde.am.json +) diff --git a/misc/dsg/configs/dde-application-manager/org.deepin.dde.am.json b/misc/dsg/configs/dde-application-manager/org.deepin.dde.am.json new file mode 100644 index 0000000..d9d6595 --- /dev/null +++ b/misc/dsg/configs/dde-application-manager/org.deepin.dde.am.json @@ -0,0 +1,16 @@ +{ + "magic": "dsg.config.meta", + "version": "1.0", + "contents": { + "appsLaunchedTimes": { + "value": {}, + "serial": 0, + "flags": [], + "name": "launched times of all apps", + "name[zh_CN]": "所有应用的启动次数", + "description": "launched times of all apps", + "permissions": "readwrite", + "visibility": "public" + } + } +} diff --git a/src/config.h.in b/src/config.h.in index 18f08fa..c3c467f 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -8,4 +8,7 @@ constexpr auto ApplicationLaunchHelperBinary = u8"@CMAKE_INSTALL_FULL_LIBEXECDIR@/deepin/application-manager/@APP_LAUNCH_HELPER_BIN@"; +const auto ApplicationServiceID = + u8"@APPLICATION_SERVICEID@"; + #endif diff --git a/src/constant.h b/src/constant.h index ae30094..41a26a6 100644 --- a/src/constant.h +++ b/src/constant.h @@ -63,4 +63,6 @@ constexpr auto InstalledTime = u8"InstalledTime"; constexpr auto ApplicationManagerHookDir = u8"/deepin/dde-application-manager/hooks.d"; +constexpr auto ApplicationManagerToolsConfig = u8"org.deepin.dde.am"; + #endif