feat: add dde-am tool to launch application
add dde-am tool.
This commit is contained in:
parent
b9d92f1254
commit
703a27c1ee
@ -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)
|
||||
|
@ -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)
|
||||
|
1
apps/dde-am/CMakeLists.txt
Normal file
1
apps/dde-am/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(src)
|
17
apps/dde-am/src/CMakeLists.txt
Normal file
17
apps/dde-am/src/CMakeLists.txt
Normal file
@ -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})
|
150
apps/dde-am/src/launcher.cpp
Normal file
150
apps/dde-am/src/launcher.cpp
Normal file
@ -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 <QDBusConnection>
|
||||
#include <QDBusMetaType>
|
||||
#include <DConfig>
|
||||
|
||||
DCORE_USE_NAMESPACE
|
||||
|
||||
namespace {
|
||||
void registerComplexDbusType()
|
||||
{
|
||||
qRegisterMetaType<ObjectInterfaceMap>();
|
||||
qDBusRegisterMetaType<ObjectInterfaceMap>();
|
||||
qRegisterMetaType<ObjectMap>();
|
||||
qDBusRegisterMetaType<ObjectMap>();
|
||||
qDBusRegisterMetaType<QStringMap>();
|
||||
qRegisterMetaType<QStringMap>();
|
||||
qRegisterMetaType<PropMap>();
|
||||
qDBusRegisterMetaType<PropMap>();
|
||||
qDBusRegisterMetaType<QDBusObjectPath>();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
DExpected<T> 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<T>{qdbus_cast<T>(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<ObjectMap>(arguments.first());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
DExpected<QStringList> 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<QString>(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<void> Launcher::run()
|
||||
{
|
||||
if (auto value = launch(); !value)
|
||||
return value;
|
||||
|
||||
if (m_launchedType == ByUser)
|
||||
if (auto ret = updateLaunchedTimes(); !ret)
|
||||
return ret;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
DExpected<void> Launcher::launch()
|
||||
{
|
||||
auto con = QDBusConnection::sessionBus();
|
||||
auto msg = QDBusMessage::createMethodCall(
|
||||
DDEApplicationManager1ServiceName, m_path, ApplicationInterface, "Launch");
|
||||
const QList<QVariant> 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<int>(reply.type()),
|
||||
QString("Failed to launch: %1, error: %2").arg(appId(), reply.errorMessage())};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
DExpected<void> Launcher::updateLaunchedTimes()
|
||||
{
|
||||
std::unique_ptr<DConfig> 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);
|
||||
}
|
30
apps/dde-am/src/launcher.h
Normal file
30
apps/dde-am/src/launcher.h
Normal file
@ -0,0 +1,30 @@
|
||||
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <DExpected>
|
||||
|
||||
class Launcher {
|
||||
public:
|
||||
enum LaunchedType{
|
||||
Unknown,
|
||||
ByUser,
|
||||
};
|
||||
void setPath(const QString &path);
|
||||
void setAction(const QString &action);
|
||||
void setLaunchedType(LaunchedType type);
|
||||
Dtk::Core::DExpected<void> run();
|
||||
|
||||
static Dtk::Core::DExpected<QStringList> appIds();
|
||||
private:
|
||||
Dtk::Core::DExpected<void> launch();
|
||||
Dtk::Core::DExpected<void> updateLaunchedTimes();
|
||||
QString appId() const;
|
||||
|
||||
QString m_path;
|
||||
QString m_action;
|
||||
LaunchedType m_launchedType = Unknown;
|
||||
};
|
64
apps/dde-am/src/main.cpp
Normal file
64
apps/dde-am/src/main.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QCommandLineOption>
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#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;
|
||||
}
|
2
debian/control
vendored
2
debian/control
vendored
@ -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
|
||||
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user