Skip to content

Commit

Permalink
feat: add dde-am tool to launch application
Browse files Browse the repository at this point in the history
  add dde-am tool.
  • Loading branch information
18202781743 committed Mar 26, 2024
1 parent b504363 commit d5f4315
Show file tree
Hide file tree
Showing 12 changed files with 275 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.applicationmanager1")

if(DDE_AM_USE_DEBUG_DBUS_NAME)
add_compile_definitions(-DDDE_AM_USE_DEBUG_DBUS_NAME)
Expand Down
1 change: 1 addition & 0 deletions apps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 change: 1 addition & 0 deletions apps/dde-am/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_subdirectory(src)
17 changes: 17 additions & 0 deletions apps/dde-am/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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})
147 changes: 147 additions & 0 deletions apps/dde-am/src/launcher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// 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()
{
static ObjectMap objects;
static bool initialized = false;
if (initialized)
return objects;

initialized = true;

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.");

objects = qdbus_cast<ObjectMap>(arguments.first());
return objects;
}
} // namespace

Dtk::Core::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;
}

Dtk::Core::DExpected<void> Launcher::run()
{
if (auto value = launch(); !value)
return value;

updateLaunchedTimes();
return {};
}

Dtk::Core::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 {};
}

void Launcher::updateLaunchedTimes()
{
std::unique_ptr<DConfig> config(DConfig::create(ApplicationServiceID, ApplicationManager1ToolsConfig));
if (!config->isValid())
return;

const QString AppsLaunchedTimes(u8"appsLaunchedTimes");
QVariantMap launchedTimes = config->value(AppsLaunchedTimes).toMap();
const auto appKey = appId();
if (appKey.isEmpty())
return;
launchedTimes[appKey] = launchedTimes[appKey].toLongLong() + 1;
config->setValue(AppsLaunchedTimes, launchedTimes);
}

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);
}
24 changes: 24 additions & 0 deletions apps/dde-am/src/launcher.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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:
void setPath(const QString &path);
void setAction(const QString &action);
Dtk::Core::DExpected<void> run();

static Dtk::Core::DExpected<QStringList> appIds();
private:
Dtk::Core::DExpected<void> launch();
void updateLaunchedTimes();
QString appId() const;

QString m_path;
QString m_action;
};
56 changes: 56 additions & 0 deletions apps/dde-am/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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();
parser.process(app);

auto arguments = parser.positionalArguments();
if (arguments.size() < 1)
parser.showHelp();

const auto pos1 = arguments.takeFirst();
if (pos1 == u8"list") {
const auto apps = Launcher::appIds();
if (!apps) {
qWarning() << apps.error();
}
for (const auto &item :apps.value()) {
qDebug() << qPrintable(item);
}
return 0;
}

std::unique_ptr<Launcher> launcher = std::make_unique<Launcher>();
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);
}

QMetaObject::invokeMethod(&app, [launcher = std::move(launcher)]() {
auto ret = launcher->run();
if (!ret) {
qWarning() << ret.error();
qApp->exit(ret.error().getErrorCode());
}
qApp->exit();
}, Qt::QueuedConnection);

return app.exec();
}
2 changes: 2 additions & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions misc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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/applicationmanager1/org.deepin.applicationmanager1.tools.json
)
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
3 changes: 3 additions & 0 deletions src/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions src/constant.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,6 @@ constexpr auto InstalledTime = u8"InstalledTime";

constexpr auto ApplicationManagerHookDir = u8"/deepin/dde-application-manager/hooks.d";

constexpr auto ApplicationManager1ToolsConfig = u8"org.deepin.applicationmanager1.tools";

#endif

0 comments on commit d5f4315

Please sign in to comment.