2023-07-17 14:49:35 +08:00
|
|
|
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
|
|
|
|
|
|
#ifndef GLOBAL_H
|
|
|
|
#define GLOBAL_H
|
|
|
|
|
|
|
|
#include <QString>
|
|
|
|
#include <QMap>
|
|
|
|
#include <QDBusConnection>
|
|
|
|
#include <optional>
|
|
|
|
#include <QDBusError>
|
|
|
|
#include <QMetaType>
|
|
|
|
#include <QMetaClassInfo>
|
2023-07-24 14:12:59 +08:00
|
|
|
#include <QLocale>
|
2023-08-10 14:32:09 +08:00
|
|
|
#include <QDir>
|
2023-07-24 14:12:59 +08:00
|
|
|
#include <QRegularExpression>
|
|
|
|
#include <QDBusObjectPath>
|
2023-10-18 18:29:52 +08:00
|
|
|
#include <QDBusUnixFileDescriptor>
|
2023-08-28 17:57:21 +08:00
|
|
|
#include <QDBusArgument>
|
2023-09-12 09:58:14 +08:00
|
|
|
#include <QDBusMessage>
|
2023-07-24 14:12:59 +08:00
|
|
|
#include <unistd.h>
|
2023-08-15 14:43:34 +08:00
|
|
|
#include <QUuid>
|
2023-08-21 18:38:27 +08:00
|
|
|
#include <QLoggingCategory>
|
2023-08-21 16:02:26 +08:00
|
|
|
#include <sys/stat.h>
|
2023-08-08 15:10:32 +08:00
|
|
|
#include "constant.h"
|
2023-08-07 14:25:22 +08:00
|
|
|
#include "config.h"
|
|
|
|
|
2023-08-21 18:38:27 +08:00
|
|
|
Q_DECLARE_LOGGING_CATEGORY(DDEAMProf)
|
|
|
|
|
2023-08-25 10:47:17 +08:00
|
|
|
using ObjectInterfaceMap = QMap<QString, QVariantMap>;
|
|
|
|
using ObjectMap = QMap<QDBusObjectPath, ObjectInterfaceMap>;
|
2023-10-12 18:05:00 +08:00
|
|
|
using QStringMap = QMap<QString, QString>;
|
2023-10-16 14:39:20 +08:00
|
|
|
using PropMap = QMap<QString, QStringMap>;
|
2023-08-25 10:47:17 +08:00
|
|
|
|
|
|
|
Q_DECLARE_METATYPE(ObjectInterfaceMap)
|
|
|
|
Q_DECLARE_METATYPE(ObjectMap)
|
2023-10-12 18:05:00 +08:00
|
|
|
Q_DECLARE_METATYPE(QStringMap)
|
2023-08-25 10:47:17 +08:00
|
|
|
Q_DECLARE_METATYPE(PropMap)
|
2023-07-17 14:49:35 +08:00
|
|
|
|
2023-08-28 17:57:21 +08:00
|
|
|
struct SystemdUnitDBusMessage
|
|
|
|
{
|
|
|
|
QString name;
|
2023-08-29 11:13:03 +08:00
|
|
|
QString subState;
|
2023-08-28 17:57:21 +08:00
|
|
|
QDBusObjectPath objectPath;
|
|
|
|
};
|
|
|
|
|
2023-10-16 14:39:20 +08:00
|
|
|
inline const QDBusArgument &operator>>(const QDBusArgument &argument, QStringMap &map)
|
|
|
|
{
|
|
|
|
argument.beginMap();
|
|
|
|
while (!argument.atEnd()) {
|
|
|
|
QString key;
|
|
|
|
QString value;
|
|
|
|
argument.beginMapEntry();
|
|
|
|
argument >> key >> value;
|
|
|
|
argument.endMapEntry();
|
|
|
|
map.insert(key, value);
|
|
|
|
}
|
|
|
|
argument.endMap();
|
|
|
|
return argument;
|
|
|
|
}
|
|
|
|
|
2023-08-28 17:57:21 +08:00
|
|
|
inline const QDBusArgument &operator>>(const QDBusArgument &argument, QList<SystemdUnitDBusMessage> &units)
|
|
|
|
{
|
|
|
|
argument.beginArray();
|
|
|
|
while (!argument.atEnd()) {
|
|
|
|
argument.beginStructure();
|
|
|
|
QString _str;
|
|
|
|
uint32_t _uint;
|
|
|
|
QDBusObjectPath _path;
|
|
|
|
SystemdUnitDBusMessage unit;
|
2023-08-29 11:13:03 +08:00
|
|
|
argument >> unit.name >> _str >> _str >> _str >> unit.subState >> _str >> unit.objectPath >> _uint >> _str >> _path;
|
2023-08-28 17:57:21 +08:00
|
|
|
units.push_back(unit);
|
|
|
|
argument.endStructure();
|
|
|
|
}
|
|
|
|
argument.endArray();
|
|
|
|
|
|
|
|
return argument;
|
|
|
|
}
|
|
|
|
|
2023-08-07 14:25:22 +08:00
|
|
|
inline QString getApplicationLauncherBinary()
|
|
|
|
{
|
2023-08-11 17:46:46 +08:00
|
|
|
static const QString bin = []() {
|
2023-08-11 14:53:05 +08:00
|
|
|
auto value = qgetenv("DEEPIN_APPLICATION_MANAGER_APP_LAUNCH_HELPER_BIN");
|
|
|
|
if (value.isEmpty()) {
|
2023-08-11 17:46:46 +08:00
|
|
|
return QString::fromLocal8Bit(ApplicationLaunchHelperBinary);
|
2023-08-11 14:53:05 +08:00
|
|
|
}
|
2023-08-07 14:25:22 +08:00
|
|
|
qWarning() << "Using app launch helper defined in environment variable DEEPIN_APPLICATION_MANAGER_APP_LAUNCH_HELPER_BIN.";
|
2023-08-11 17:46:46 +08:00
|
|
|
return QString::fromLocal8Bit(value);
|
2023-08-11 14:53:05 +08:00
|
|
|
}();
|
|
|
|
return bin;
|
2023-08-07 14:25:22 +08:00
|
|
|
}
|
2023-07-24 14:12:59 +08:00
|
|
|
|
|
|
|
enum class DBusType { Session = QDBusConnection::SessionBus, System = QDBusConnection::SystemBus, Custom };
|
2023-07-17 14:49:35 +08:00
|
|
|
|
2023-08-10 14:32:09 +08:00
|
|
|
template <typename T>
|
|
|
|
using remove_cvr_t = std::remove_reference_t<std::remove_cv_t<T>>;
|
|
|
|
|
|
|
|
template <typename T>
|
2023-10-07 15:15:08 +08:00
|
|
|
void applyIteratively(QList<QDir> dirs,
|
|
|
|
T &&func,
|
|
|
|
QDir::Filters filter = QDir::NoFilter,
|
|
|
|
QStringList nameFilter = {},
|
|
|
|
QDir::SortFlags sortFlag = QDir::SortFlag::NoSort)
|
2023-08-10 14:32:09 +08:00
|
|
|
{
|
|
|
|
static_assert(std::is_invocable_v<T, const QFileInfo &>, "apply function should only accept one QFileInfo");
|
|
|
|
static_assert(std::is_same_v<decltype(func(QFileInfo{})), bool>,
|
|
|
|
"apply function should return a boolean to indicate when should return");
|
|
|
|
QList<QDir> dirList{std::move(dirs)};
|
|
|
|
|
|
|
|
while (!dirList.isEmpty()) {
|
2023-08-31 17:59:09 +08:00
|
|
|
const auto &dir = dirList.takeFirst();
|
2023-08-10 14:32:09 +08:00
|
|
|
|
|
|
|
if (!dir.exists()) {
|
|
|
|
qWarning() << "apply function to an non-existent directory:" << dir.absolutePath() << ", skip.";
|
|
|
|
continue;
|
|
|
|
}
|
2023-10-07 15:15:08 +08:00
|
|
|
const auto &infoList = dir.entryInfoList(nameFilter, filter, sortFlag);
|
2023-08-10 14:32:09 +08:00
|
|
|
|
|
|
|
for (const auto &info : infoList) {
|
|
|
|
if (info.isFile() and func(info)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info.isDir()) {
|
|
|
|
dirList.append(info.absoluteFilePath());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-17 14:49:35 +08:00
|
|
|
class ApplicationManager1DBus
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ApplicationManager1DBus(const ApplicationManager1DBus &) = delete;
|
|
|
|
ApplicationManager1DBus(ApplicationManager1DBus &&) = delete;
|
|
|
|
ApplicationManager1DBus &operator=(const ApplicationManager1DBus &) = delete;
|
2023-07-21 14:47:40 +08:00
|
|
|
ApplicationManager1DBus &operator=(ApplicationManager1DBus &&) = delete;
|
2023-08-10 14:32:09 +08:00
|
|
|
[[nodiscard]] const QString &globalDestBusAddress() const { return m_destBusAddress; }
|
|
|
|
[[nodiscard]] const QString &globalServerBusAddress() const { return m_serverBusAddress; }
|
2023-08-08 15:10:32 +08:00
|
|
|
void initGlobalServerBus(DBusType type, const QString &busAddress = "")
|
2023-07-17 14:49:35 +08:00
|
|
|
{
|
2023-07-24 14:12:59 +08:00
|
|
|
if (m_initFlag) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-08 15:10:32 +08:00
|
|
|
m_serverBusAddress = busAddress;
|
|
|
|
m_serverType = type;
|
2023-07-24 14:12:59 +08:00
|
|
|
m_initFlag = true;
|
|
|
|
}
|
|
|
|
|
2023-08-08 15:10:32 +08:00
|
|
|
QDBusConnection &globalServerBus()
|
2023-07-24 14:12:59 +08:00
|
|
|
{
|
2023-08-08 15:10:32 +08:00
|
|
|
if (m_serverConnection.has_value()) {
|
|
|
|
return m_serverConnection.value();
|
2023-07-24 14:12:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_initFlag) {
|
2023-08-21 16:02:26 +08:00
|
|
|
qFatal("invoke init at first.");
|
2023-07-17 14:49:35 +08:00
|
|
|
}
|
2023-07-24 14:12:59 +08:00
|
|
|
|
2023-08-08 15:10:32 +08:00
|
|
|
switch (m_serverType) {
|
2023-08-25 16:04:55 +08:00
|
|
|
case DBusType::Session:
|
|
|
|
[[fallthrough]];
|
|
|
|
case DBusType::System: {
|
|
|
|
m_serverConnection.emplace(QDBusConnection::connectToBus(static_cast<QDBusConnection::BusType>(m_serverType),
|
|
|
|
ApplicationManagerServerDBusName));
|
|
|
|
if (!m_serverConnection->isConnected()) {
|
|
|
|
qFatal("%s", m_serverConnection->lastError().message().toLocal8Bit().data());
|
2023-07-24 14:12:59 +08:00
|
|
|
}
|
2023-08-25 16:04:55 +08:00
|
|
|
return m_serverConnection.value();
|
|
|
|
}
|
|
|
|
case DBusType::Custom: {
|
|
|
|
if (m_serverBusAddress.isEmpty()) {
|
|
|
|
qFatal("connect to custom dbus must init this object by custom dbus address");
|
|
|
|
}
|
|
|
|
m_serverConnection.emplace(QDBusConnection::connectToBus(m_serverBusAddress, ApplicationManagerServerDBusName));
|
|
|
|
if (!m_serverConnection->isConnected()) {
|
|
|
|
qFatal("%s", m_serverConnection->lastError().message().toLocal8Bit().data());
|
2023-07-24 14:12:59 +08:00
|
|
|
}
|
2023-08-25 16:04:55 +08:00
|
|
|
return m_serverConnection.value();
|
|
|
|
}
|
2023-07-24 14:12:59 +08:00
|
|
|
}
|
2023-08-08 15:10:32 +08:00
|
|
|
|
2023-07-24 14:12:59 +08:00
|
|
|
Q_UNREACHABLE();
|
2023-07-17 14:49:35 +08:00
|
|
|
}
|
|
|
|
static ApplicationManager1DBus &instance()
|
|
|
|
{
|
|
|
|
static ApplicationManager1DBus dbus;
|
|
|
|
return dbus;
|
|
|
|
}
|
|
|
|
|
2023-08-08 15:10:32 +08:00
|
|
|
QDBusConnection &globalDestBus()
|
|
|
|
{
|
|
|
|
if (!m_destConnection) {
|
2023-08-21 16:02:26 +08:00
|
|
|
qFatal("please set which bus should application manager to use to invoke other D-Bus service's method.");
|
2023-08-08 15:10:32 +08:00
|
|
|
}
|
|
|
|
return m_destConnection.value();
|
|
|
|
}
|
|
|
|
|
2023-08-15 14:43:34 +08:00
|
|
|
void setDestBus(const QString &destAddress = "")
|
2023-08-08 15:10:32 +08:00
|
|
|
{
|
|
|
|
if (m_destConnection) {
|
|
|
|
m_destConnection->disconnectFromBus(ApplicationManagerDestDBusName);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_destBusAddress = destAddress;
|
|
|
|
|
|
|
|
if (m_destBusAddress.isEmpty()) {
|
|
|
|
m_destConnection.emplace(
|
|
|
|
QDBusConnection::connectToBus(QDBusConnection::BusType::SessionBus, ApplicationManagerDestDBusName));
|
|
|
|
if (!m_destConnection->isConnected()) {
|
2023-08-21 16:02:26 +08:00
|
|
|
qFatal("%s", m_destConnection->lastError().message().toLocal8Bit().data());
|
2023-08-08 15:10:32 +08:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-10 14:32:09 +08:00
|
|
|
if (m_destBusAddress.isEmpty()) {
|
2023-08-21 16:02:26 +08:00
|
|
|
qFatal("connect to custom dbus must init this object by custom dbus address");
|
2023-08-10 14:32:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
m_destConnection.emplace(QDBusConnection::connectToBus(m_destBusAddress, ApplicationManagerDestDBusName));
|
|
|
|
if (!m_destConnection->isConnected()) {
|
2023-08-21 16:02:26 +08:00
|
|
|
qFatal("%s", m_destConnection->lastError().message().toLocal8Bit().data());
|
2023-08-10 14:32:09 +08:00
|
|
|
}
|
2023-08-08 15:10:32 +08:00
|
|
|
}
|
|
|
|
|
2023-07-17 14:49:35 +08:00
|
|
|
private:
|
|
|
|
ApplicationManager1DBus() = default;
|
|
|
|
~ApplicationManager1DBus() = default;
|
2023-08-10 14:32:09 +08:00
|
|
|
bool m_initFlag{false};
|
|
|
|
DBusType m_serverType{};
|
2023-08-08 15:10:32 +08:00
|
|
|
QString m_serverBusAddress;
|
|
|
|
QString m_destBusAddress;
|
|
|
|
std::optional<QDBusConnection> m_destConnection{std::nullopt};
|
|
|
|
std::optional<QDBusConnection> m_serverConnection{std::nullopt};
|
2023-07-17 14:49:35 +08:00
|
|
|
};
|
|
|
|
|
2023-07-24 14:12:59 +08:00
|
|
|
bool registerObjectToDBus(QObject *o, const QString &path, const QString &interface);
|
|
|
|
void unregisterObjectFromDBus(const QString &path);
|
2023-07-17 14:49:35 +08:00
|
|
|
|
2023-08-18 10:01:52 +08:00
|
|
|
inline QString getDBusInterface(const QMetaType &meta)
|
2023-07-17 14:49:35 +08:00
|
|
|
{
|
2023-08-28 11:11:50 +08:00
|
|
|
auto name = QString{meta.name()};
|
|
|
|
if (name == "ApplicationAdaptor") {
|
|
|
|
return ApplicationInterface;
|
2023-07-17 14:49:35 +08:00
|
|
|
}
|
2023-08-28 11:11:50 +08:00
|
|
|
|
|
|
|
if (name == "InstanceAdaptor") {
|
|
|
|
return InstanceInterface;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name == "APPObjectManagerAdaptor" or name == "AMObjectManagerAdaptor") {
|
|
|
|
return ObjectManagerInterface;
|
|
|
|
}
|
2023-09-13 16:52:53 +08:00
|
|
|
|
|
|
|
if (name == "ApplicationManager1Service")
|
|
|
|
// const auto *infoObject = meta.metaObject();
|
|
|
|
// if (auto infoIndex = infoObject->indexOfClassInfo("D-Bus Interface"); infoIndex != -1) {
|
|
|
|
// return infoObject->classInfo(infoIndex).value();
|
|
|
|
// }
|
|
|
|
qWarning() << "couldn't found interface:" << name;
|
2023-08-28 11:11:50 +08:00
|
|
|
return "";
|
2023-07-17 14:49:35 +08:00
|
|
|
}
|
|
|
|
|
2023-08-25 10:47:17 +08:00
|
|
|
inline ObjectInterfaceMap getChildInterfacesAndPropertiesFromObject(QObject *o)
|
|
|
|
{
|
|
|
|
auto childs = o->children();
|
|
|
|
ObjectInterfaceMap ret;
|
|
|
|
|
|
|
|
std::for_each(childs.cbegin(), childs.cend(), [&ret](QObject *app) {
|
|
|
|
if (app->inherits("QDBusAbstractAdaptor")) {
|
|
|
|
auto interface = getDBusInterface(app->metaObject()->metaType());
|
|
|
|
QVariantMap properties;
|
|
|
|
const auto *mo = app->metaObject();
|
|
|
|
for (int i = mo->propertyOffset(); i < mo->propertyCount(); ++i) {
|
|
|
|
auto prop = mo->property(i);
|
|
|
|
properties.insert(prop.name(), prop.read(app));
|
|
|
|
}
|
|
|
|
ret.insert(interface, properties);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline QStringList getChildInterfacesFromObject(QObject *o)
|
2023-08-18 10:01:52 +08:00
|
|
|
{
|
|
|
|
auto childs = o->children();
|
2023-08-25 10:47:17 +08:00
|
|
|
QStringList ret;
|
|
|
|
|
|
|
|
std::for_each(childs.cbegin(), childs.cend(), [&ret](QObject *app) {
|
2023-08-18 10:01:52 +08:00
|
|
|
if (app->inherits("QDBusAbstractAdaptor")) {
|
2023-08-25 10:47:17 +08:00
|
|
|
ret.append(getDBusInterface(app->metaObject()->metaType()));
|
2023-08-18 10:01:52 +08:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-08-25 10:47:17 +08:00
|
|
|
return ret;
|
2023-08-18 10:01:52 +08:00
|
|
|
}
|
|
|
|
|
2023-07-24 14:12:59 +08:00
|
|
|
inline uid_t getCurrentUID()
|
|
|
|
{
|
|
|
|
return getuid(); // current use linux getuid
|
|
|
|
}
|
|
|
|
|
|
|
|
inline QLocale getUserLocale()
|
|
|
|
{
|
|
|
|
return QLocale::system(); // current use env
|
|
|
|
}
|
|
|
|
|
|
|
|
inline QString escapeToObjectPath(const QString &str)
|
|
|
|
{
|
|
|
|
if (str.isEmpty()) {
|
|
|
|
return "_";
|
|
|
|
}
|
|
|
|
|
|
|
|
auto ret = str;
|
|
|
|
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<uint>(c.front().toLatin1()), 16);
|
|
|
|
ret.replace(c, QString{R"(_%1)"}.arg(hexStr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline QString unescapeFromObjectPath(const QString &str)
|
|
|
|
{
|
|
|
|
auto ret = str;
|
|
|
|
for (qsizetype i = 0; i < str.size(); ++i) {
|
|
|
|
if (str[i] == '_' and i + 2 < str.size()) {
|
|
|
|
auto hexStr = str.sliced(i + 1, 2);
|
2023-08-11 10:12:46 +08:00
|
|
|
ret.replace(QString{"_%1"}.arg(hexStr), QChar::fromLatin1(hexStr.toUInt(nullptr, 16)));
|
2023-07-24 14:12:59 +08:00
|
|
|
i += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-08-11 10:12:46 +08:00
|
|
|
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<uint>(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;
|
|
|
|
}
|
|
|
|
|
2023-08-10 14:32:09 +08:00
|
|
|
inline QString getRelativePathFromAppId(const QString &id)
|
|
|
|
{
|
|
|
|
QString path;
|
|
|
|
auto components = id.split('-', Qt::SkipEmptyParts);
|
|
|
|
for (qsizetype i = 0; i < components.size() - 1; ++i) {
|
|
|
|
path += QString{"/%1"}.arg(components[i]);
|
|
|
|
}
|
|
|
|
path += QString{R"(-%1.desktop)"}.arg(components.last());
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2023-09-13 11:47:04 +08:00
|
|
|
inline QString getXDGDataHome()
|
|
|
|
{
|
|
|
|
auto XDGDataHome = QString::fromLocal8Bit(qgetenv("XDG_DATA_HOME"));
|
|
|
|
if (XDGDataHome.isEmpty()) {
|
|
|
|
XDGDataHome = QString::fromLocal8Bit(qgetenv("HOME")) + QDir::separator() + ".local" + QDir::separator() + "share";
|
|
|
|
}
|
|
|
|
return XDGDataHome;
|
|
|
|
}
|
|
|
|
|
2023-10-07 15:15:08 +08:00
|
|
|
inline QStringList getXDGDataDirs()
|
2023-08-11 17:46:46 +08:00
|
|
|
{
|
2023-08-29 18:22:47 +08:00
|
|
|
auto XDGDataDirs = QString::fromLocal8Bit(qgetenv("XDG_DATA_DIRS")).split(':', Qt::SkipEmptyParts);
|
2023-08-11 17:46:46 +08:00
|
|
|
|
2023-08-29 18:22:47 +08:00
|
|
|
if (XDGDataDirs.isEmpty()) {
|
|
|
|
XDGDataDirs.append("/usr/local/share");
|
|
|
|
XDGDataDirs.append("/usr/share");
|
|
|
|
}
|
2023-08-11 17:46:46 +08:00
|
|
|
|
2023-11-08 18:21:09 +08:00
|
|
|
auto XDGDataHome = getXDGDataHome();
|
|
|
|
if (XDGDataDirs.contains(XDGDataHome)) {
|
|
|
|
XDGDataDirs.removeAll(XDGDataHome);
|
|
|
|
}
|
|
|
|
|
|
|
|
XDGDataDirs.push_front(XDGDataHome);
|
2023-10-07 15:15:08 +08:00
|
|
|
return XDGDataDirs;
|
|
|
|
}
|
2023-08-14 11:56:47 +08:00
|
|
|
|
2023-10-07 15:15:08 +08:00
|
|
|
inline QStringList getDesktopFileDirs()
|
|
|
|
{
|
|
|
|
auto XDGDataDirs = getXDGDataDirs();
|
2023-08-29 18:22:47 +08:00
|
|
|
std::for_each(XDGDataDirs.begin(), XDGDataDirs.end(), [](QString &str) {
|
|
|
|
if (!str.endsWith(QDir::separator())) {
|
|
|
|
str.append(QDir::separator());
|
|
|
|
}
|
|
|
|
str.append("applications");
|
|
|
|
});
|
2023-11-08 18:21:09 +08:00
|
|
|
|
2023-08-11 17:46:46 +08:00
|
|
|
return XDGDataDirs;
|
|
|
|
}
|
|
|
|
|
2023-09-20 18:29:42 +08:00
|
|
|
inline QString getXDGConfigHome()
|
|
|
|
{
|
|
|
|
auto XDGConfigHome = QString::fromLocal8Bit(qgetenv("XDG_CONFIG_HOME"));
|
|
|
|
if (XDGConfigHome.isEmpty()) {
|
|
|
|
XDGConfigHome = QString::fromLocal8Bit(qgetenv("HOME")) + QDir::separator() + ".config";
|
|
|
|
}
|
|
|
|
|
|
|
|
return XDGConfigHome;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline QStringList getXDGConfigDirs()
|
2023-08-23 17:20:47 +08:00
|
|
|
{
|
2023-08-29 18:22:47 +08:00
|
|
|
auto XDGConfigDirs = QString::fromLocal8Bit(qgetenv("XDG_CONFIG_DIRS")).split(':', Qt::SkipEmptyParts);
|
|
|
|
if (XDGConfigDirs.isEmpty()) {
|
|
|
|
XDGConfigDirs.append("/etc/xdg");
|
|
|
|
}
|
2023-08-23 17:20:47 +08:00
|
|
|
|
2023-09-20 18:29:42 +08:00
|
|
|
auto XDGConfigHome = getXDGConfigHome();
|
2023-08-23 17:20:47 +08:00
|
|
|
|
2023-09-11 13:09:37 +08:00
|
|
|
if (XDGConfigDirs.constFirst() != XDGConfigHome) {
|
|
|
|
XDGConfigDirs.removeAll(XDGConfigHome);
|
|
|
|
XDGConfigDirs.push_front(std::move(XDGConfigHome)); // guarantee XDG_CONFIG_HOME is first element.
|
|
|
|
}
|
2023-08-23 17:20:47 +08:00
|
|
|
|
2023-09-20 18:29:42 +08:00
|
|
|
return XDGConfigDirs;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline QStringList getAutoStartDirs()
|
|
|
|
{
|
|
|
|
auto XDGConfigDirs = getXDGConfigDirs();
|
2023-08-29 18:22:47 +08:00
|
|
|
std::for_each(XDGConfigDirs.begin(), XDGConfigDirs.end(), [](QString &str) {
|
|
|
|
if (!str.endsWith(QDir::separator())) {
|
|
|
|
str.append(QDir::separator());
|
|
|
|
}
|
|
|
|
str.append("autostart");
|
|
|
|
});
|
2023-08-23 17:20:47 +08:00
|
|
|
|
|
|
|
return XDGConfigDirs;
|
|
|
|
}
|
|
|
|
|
2023-09-20 18:29:42 +08:00
|
|
|
inline QString getCurrentDesktop()
|
|
|
|
{
|
|
|
|
auto desktops = QString::fromLocal8Bit(qgetenv("XDG_CURRENT_DESKTOP")).split(';', Qt::SkipEmptyParts);
|
|
|
|
|
|
|
|
if (desktops.size() > 1) {
|
|
|
|
qWarning() << "multi-DE is detected, use first value.";
|
|
|
|
}
|
|
|
|
|
|
|
|
return desktops.first();
|
|
|
|
}
|
|
|
|
|
2023-08-29 11:13:03 +08:00
|
|
|
inline bool isApplication(const QDBusObjectPath &path)
|
|
|
|
{
|
|
|
|
return path.path().split('/').last().startsWith("app");
|
|
|
|
}
|
|
|
|
|
2023-09-13 16:52:53 +08:00
|
|
|
struct unitInfo
|
|
|
|
{
|
|
|
|
QString applicationID;
|
|
|
|
QString Launcher;
|
|
|
|
QString instanceID;
|
|
|
|
};
|
|
|
|
|
|
|
|
inline unitInfo processUnitName(const QString &unitName)
|
2023-08-15 14:43:34 +08:00
|
|
|
{
|
|
|
|
QString instanceId;
|
2023-09-13 16:52:53 +08:00
|
|
|
QString launcher;
|
2023-08-15 14:43:34 +08:00
|
|
|
QString applicationId;
|
|
|
|
|
2023-09-13 16:52:53 +08:00
|
|
|
decltype(auto) appPrefix = u8"app-";
|
|
|
|
auto unit = unitName.sliced(sizeof(appPrefix) - 1);
|
|
|
|
|
|
|
|
if (unit.endsWith(".service")) {
|
|
|
|
auto lastDotIndex = unit.lastIndexOf('.');
|
|
|
|
auto app = unit.sliced(0, lastDotIndex); // remove suffix
|
2023-08-15 14:43:34 +08:00
|
|
|
|
|
|
|
if (app.contains('@')) {
|
|
|
|
auto atIndex = app.indexOf('@');
|
|
|
|
instanceId = app.sliced(atIndex + 1);
|
|
|
|
app.remove(atIndex, instanceId.length() + 1);
|
|
|
|
}
|
2023-09-13 16:52:53 +08:00
|
|
|
auto rest = app.split('-', Qt::SkipEmptyParts);
|
|
|
|
if (rest.size() == 2) {
|
|
|
|
launcher = rest.takeFirst();
|
|
|
|
}
|
|
|
|
applicationId = rest.takeFirst();
|
|
|
|
} else if (unit.endsWith(".scope")) {
|
|
|
|
auto lastDotIndex = unit.lastIndexOf('.');
|
|
|
|
auto app = unit.sliced(0, lastDotIndex);
|
2023-08-15 14:43:34 +08:00
|
|
|
|
|
|
|
auto components = app.split('-');
|
|
|
|
instanceId = components.takeLast();
|
|
|
|
applicationId = components.takeLast();
|
2023-09-13 16:52:53 +08:00
|
|
|
if (!components.isEmpty()) {
|
|
|
|
launcher = components.takeLast();
|
|
|
|
}
|
2023-08-15 14:43:34 +08:00
|
|
|
} else {
|
2023-09-13 16:52:53 +08:00
|
|
|
qDebug() << "it's not service or scope:" << unit << "ignore";
|
2023-08-15 14:43:34 +08:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (instanceId.isEmpty()) {
|
|
|
|
instanceId = QUuid::createUuid().toString(QUuid::Id128);
|
|
|
|
}
|
|
|
|
|
2023-09-13 16:52:53 +08:00
|
|
|
return {unescapeApplicationId(applicationId), std::move(launcher), std::move(instanceId)};
|
2023-08-15 14:43:34 +08:00
|
|
|
}
|
|
|
|
|
2023-08-18 17:22:38 +08:00
|
|
|
template <typename T>
|
|
|
|
ObjectMap dumpDBusObject(const QMap<QDBusObjectPath, QSharedPointer<T>> &map)
|
|
|
|
{
|
|
|
|
ObjectMap objs;
|
|
|
|
|
2023-09-06 16:49:47 +08:00
|
|
|
for (auto it = map.constKeyValueBegin(); it != map.constKeyValueEnd(); ++it) {
|
|
|
|
const auto &[key, value] = *it;
|
2023-08-25 10:47:17 +08:00
|
|
|
auto interAndProps = getChildInterfacesAndPropertiesFromObject(value.data());
|
|
|
|
objs.insert(key, interAndProps);
|
2023-08-18 17:22:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return objs;
|
|
|
|
}
|
|
|
|
|
2023-09-11 13:01:20 +08:00
|
|
|
struct FileTimeInfo
|
2023-08-21 16:02:26 +08:00
|
|
|
{
|
2023-09-11 13:01:20 +08:00
|
|
|
qint64 mtime;
|
|
|
|
qint64 ctime;
|
|
|
|
qint64 atime;
|
|
|
|
};
|
2023-08-31 16:40:29 +08:00
|
|
|
|
2023-09-11 13:01:20 +08:00
|
|
|
inline FileTimeInfo getFileTimeInfo(const QFileInfo &file)
|
|
|
|
{
|
|
|
|
auto mtime = file.lastModified().toMSecsSinceEpoch();
|
|
|
|
auto atime = file.lastRead().toMSecsSinceEpoch();
|
|
|
|
auto ctime = file.birthTime().toMSecsSinceEpoch();
|
|
|
|
return {mtime, ctime, atime};
|
2023-08-21 16:02:26 +08:00
|
|
|
}
|
|
|
|
|
2023-09-12 09:58:14 +08:00
|
|
|
inline QByteArray getCurrentSessionId()
|
|
|
|
{
|
|
|
|
constexpr auto graphicalTarget = u8"graphical-session.target";
|
|
|
|
|
|
|
|
auto msg = QDBusMessage::createMethodCall("org.freedesktop.systemd1",
|
|
|
|
"/org/freedesktop/systemd1/unit/" + escapeToObjectPath(graphicalTarget),
|
|
|
|
"org.freedesktop.DBus.Properties",
|
|
|
|
"Get");
|
|
|
|
msg << QString{"org.freedesktop.systemd1.Unit"};
|
|
|
|
msg << QString{"InvocationID"};
|
|
|
|
auto bus = QDBusConnection::sessionBus();
|
|
|
|
auto ret = bus.call(msg);
|
|
|
|
if (ret.type() != QDBusMessage::ReplyMessage) {
|
|
|
|
qWarning() << "get graphical session Id failed:" << ret.errorMessage();
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
auto id = ret.arguments().first();
|
|
|
|
return id.value<QDBusVariant>().variant().toByteArray();
|
|
|
|
}
|
|
|
|
|
2023-10-18 18:29:52 +08:00
|
|
|
inline uint getPidFromPidFd(const QDBusUnixFileDescriptor &pidfd) noexcept
|
|
|
|
{
|
|
|
|
QString fdFilePath = QString{"/proc/self/fdinfo/%1"}.arg(pidfd.fileDescriptor());
|
|
|
|
QFile fdFile{fdFilePath};
|
|
|
|
if (!fdFile.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) {
|
|
|
|
qWarning() << "open " << fdFilePath << "failed: " << fdFile.errorString();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto content = fdFile.readAll();
|
|
|
|
QTextStream stream{content};
|
|
|
|
QString appPid;
|
|
|
|
while (!stream.atEnd()) {
|
|
|
|
auto line = stream.readLine();
|
|
|
|
if (line.startsWith("Pid")) {
|
|
|
|
appPid = line.split(":").last().trimmed();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (appPid.isEmpty()) {
|
|
|
|
qWarning() << "can't find pid which corresponding with the instance of this application.";
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
bool ok{false};
|
|
|
|
auto pid = appPid.toUInt(&ok);
|
|
|
|
if (!ok) {
|
|
|
|
qWarning() << "AppId is failed to convert to uint.";
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pid;
|
|
|
|
}
|
|
|
|
|
2023-07-17 14:49:35 +08:00
|
|
|
#endif
|