Compare commits
10 Commits
006f80d681
...
0695c9784c
Author | SHA1 | Date | |
---|---|---|---|
|
0695c9784c | ||
|
538cfb48d4 | ||
|
230636f2e1 | ||
|
5b99e9e4b9 | ||
|
18a176c223 | ||
|
0e6c21360c | ||
|
57fbf5f681 | ||
|
7939cd568a | ||
|
88b0159cc3 | ||
|
50a0ad53ec |
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,10 +1,13 @@
|
|||||||
|
.cache
|
||||||
build*
|
build*
|
||||||
.vscode
|
.vscode
|
||||||
/debian/.debhelper
|
/debian/.debhelper
|
||||||
/debian/dde-application-manager
|
/debian/dde-application-manager
|
||||||
/debian/dde-application-manager.substvars
|
/debian/dde-application-manager-api
|
||||||
/debian/dde-application-manager.debhelper.log
|
/debian/*.substvars
|
||||||
|
/debian/*.debhelper
|
||||||
/debian/debhelper-build-stamp
|
/debian/debhelper-build-stamp
|
||||||
/debian/files
|
/debian/files
|
||||||
/obj-x86_64-linux-gnu
|
/debian/tmp
|
||||||
|
/obj-*-linux-gnu
|
||||||
*.user
|
*.user
|
@ -23,6 +23,11 @@ Files: .gitignore
|
|||||||
Copyright: None
|
Copyright: None
|
||||||
License: CC0-1.0
|
License: CC0-1.0
|
||||||
|
|
||||||
|
# cmake
|
||||||
|
Files: api/*.cmake.in
|
||||||
|
Copyright: None
|
||||||
|
License: CC0-1.0
|
||||||
|
|
||||||
# DBus API
|
# DBus API
|
||||||
Files: api/dbus/*.xml apps/app-update-notifier/api/dbus/*.xml
|
Files: api/dbus/*.xml apps/app-update-notifier/api/dbus/*.xml
|
||||||
Copyright: None
|
Copyright: None
|
||||||
|
@ -2,5 +2,13 @@ include(GNUInstallDirs)
|
|||||||
|
|
||||||
file(GLOB DBusAPI ${CMAKE_CURRENT_LIST_DIR}/dbus/*.xml)
|
file(GLOB DBusAPI ${CMAKE_CURRENT_LIST_DIR}/dbus/*.xml)
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_SOURCE_DIR}/api/DDEApplicationManagerConfig.cmake.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/DDEApplicationManagerConfig.cmake
|
||||||
|
@ONLY)
|
||||||
|
|
||||||
install(FILES ${DBusAPI}
|
install(FILES ${DBusAPI}
|
||||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/dde-application-manager/)
|
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/dde-application-manager/)
|
||||||
|
|
||||||
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/DDEApplicationManagerConfig.cmake
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/DDEApplicationManager/)
|
||||||
|
1
api/DDEApplicationManagerConfig.cmake.in
Normal file
1
api/DDEApplicationManagerConfig.cmake.in
Normal file
@ -0,0 +1 @@
|
|||||||
|
set(DDE_APPLICATION_MANAGER_DBUS_API_DIR @CMAKE_INSTALL_FULL_DATAROOTDIR@/dde-application-manager/)
|
@ -117,6 +117,14 @@
|
|||||||
<annotation name="org.qtproject.QtDBus.QtTypeName" value="QStringMap"/>
|
<annotation name="org.qtproject.QtDBus.QtTypeName" value="QStringMap"/>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
|
<property name="StartupWMClass" type="s" access="read">
|
||||||
|
<annotation
|
||||||
|
name="org.freedesktop.DBus.Description"
|
||||||
|
value="The meaning of this property's type is same as which in StartupWMClass."
|
||||||
|
/>
|
||||||
|
<annotation name="org.qtproject.QtDBus.QtTypeName" value="QStringMap"/>
|
||||||
|
</property>
|
||||||
|
|
||||||
<method name="Launch">
|
<method name="Launch">
|
||||||
<arg type="s" name="action" direction="in" />
|
<arg type="s" name="action" direction="in" />
|
||||||
<arg type="as" name="fields" direction="in" />
|
<arg type="as" name="fields" direction="in" />
|
||||||
@ -138,10 +146,13 @@
|
|||||||
1. `uid` (type u):
|
1. `uid` (type u):
|
||||||
The user id as who is that application will be run.
|
The user id as who is that application will be run.
|
||||||
This option might request a polikit authentication.
|
This option might request a polikit authentication.
|
||||||
2. `env` (type s):
|
2. `env` (type as):
|
||||||
passing some specific environment variables to Launch
|
passing some specific environment variables to Launch
|
||||||
this application, eg. 'LANG=en_US;PATH=xxx:yyy;'
|
this application without them, eg. '[LANG=en_US, PATH=xxx:yyy]'
|
||||||
3. `path` (type s):
|
3. `unsetEnv` (type as):
|
||||||
|
passed environment variables will be ignored when
|
||||||
|
launching this application, eg. '[LANG, PATH]'
|
||||||
|
4. `path` (type s):
|
||||||
set this application's working directory, please pass
|
set this application's working directory, please pass
|
||||||
absolute directory path.
|
absolute directory path.
|
||||||
NOTE:
|
NOTE:
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <list>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "constant.h"
|
#include "constant.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
@ -140,6 +141,7 @@ int processExecStart(msg_ptr &msg, const std::deque<std::string_view> &execArgs)
|
|||||||
DBusValueType getPropType(std::string_view key)
|
DBusValueType getPropType(std::string_view key)
|
||||||
{
|
{
|
||||||
static std::unordered_map<std::string_view, DBusValueType> map{{"Environment", DBusValueType::ArrayOfString},
|
static std::unordered_map<std::string_view, DBusValueType> map{{"Environment", DBusValueType::ArrayOfString},
|
||||||
|
{"UnsetEnvironment", DBusValueType::ArrayOfString},
|
||||||
{"WorkingDirectory", DBusValueType::String},
|
{"WorkingDirectory", DBusValueType::String},
|
||||||
{"ExecSearchPath", DBusValueType::ArrayOfString}};
|
{"ExecSearchPath", DBusValueType::ArrayOfString}};
|
||||||
|
|
||||||
@ -150,7 +152,7 @@ DBusValueType getPropType(std::string_view key)
|
|||||||
return DBusValueType::String; // fallback to string
|
return DBusValueType::String; // fallback to string
|
||||||
}
|
}
|
||||||
|
|
||||||
int appendPropValue(msg_ptr &msg, DBusValueType type, std::string_view value)
|
int appendPropValue(msg_ptr &msg, DBusValueType type, const std::list<std::string_view> &value)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -165,10 +167,12 @@ int appendPropValue(msg_ptr &msg, DBusValueType type, std::string_view value)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret = handler->appendValue(std::string{value}); ret < 0) {
|
for (const auto &v : value) {
|
||||||
|
if (ret = handler->appendValue(std::string{v}); ret < 0) {
|
||||||
sd_journal_perror("append property's variant value failed.");
|
sd_journal_perror("append property's variant value failed.");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ret = handler->closeVariant(); ret < 0) {
|
if (ret = handler->closeVariant(); ret < 0) {
|
||||||
sd_journal_perror("close property's variant value failed.");
|
sd_journal_perror("close property's variant value failed.");
|
||||||
@ -178,13 +182,12 @@ int appendPropValue(msg_ptr &msg, DBusValueType type, std::string_view value)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int processKVPair(msg_ptr &msg, const std::map<std::string_view, std::string_view> &props)
|
int processKVPair(msg_ptr &msg, const std::map<std::string_view, std::list<std::string_view>> &props)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
if (!props.empty()) {
|
if (!props.empty()) {
|
||||||
for (auto [key, value] : props) {
|
for (auto [key, value] : props) {
|
||||||
std::string keyStr{key};
|
std::string keyStr{key};
|
||||||
std::string valueStr{value};
|
|
||||||
if (ret = sd_bus_message_open_container(msg, SD_BUS_TYPE_STRUCT, "sv"); ret < 0) {
|
if (ret = sd_bus_message_open_container(msg, SD_BUS_TYPE_STRUCT, "sv"); ret < 0) {
|
||||||
sd_journal_perror("open struct of properties failed.");
|
sd_journal_perror("open struct of properties failed.");
|
||||||
return ret;
|
return ret;
|
||||||
@ -195,7 +198,7 @@ int processKVPair(msg_ptr &msg, const std::map<std::string_view, std::string_vie
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret = appendPropValue(msg, getPropType(key), valueStr); ret < 0) {
|
if (ret = appendPropValue(msg, getPropType(key), value); ret < 0) {
|
||||||
sd_journal_perror("append value of property failed.");
|
sd_journal_perror("append value of property failed.");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -212,7 +215,7 @@ int processKVPair(msg_ptr &msg, const std::map<std::string_view, std::string_vie
|
|||||||
std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> cmdLines)
|
std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> cmdLines)
|
||||||
{
|
{
|
||||||
std::string serviceName{"internalError"};
|
std::string serviceName{"internalError"};
|
||||||
std::map<std::string_view, std::string_view> props;
|
std::map<std::string_view, std::list<std::string_view>> props;
|
||||||
while (!cmdLines.empty()) { // NOTE: avoid stl exception
|
while (!cmdLines.empty()) { // NOTE: avoid stl exception
|
||||||
auto str = cmdLines.front();
|
auto str = cmdLines.front();
|
||||||
if (str.size() < 2) {
|
if (str.size() < 2) {
|
||||||
@ -249,7 +252,7 @@ std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> cmdLines)
|
|||||||
cmdLines.pop_front();
|
cmdLines.pop_front();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
props[key] = kvStr.substr(splitIndex + 1);
|
props[key].push_back(kvStr.substr(splitIndex + 1));
|
||||||
cmdLines.pop_front();
|
cmdLines.pop_front();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -265,18 +268,19 @@ std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> cmdLines)
|
|||||||
serviceName = "invalidInput";
|
serviceName = "invalidInput";
|
||||||
return serviceName;
|
return serviceName;
|
||||||
}
|
}
|
||||||
int ret;
|
|
||||||
if (props.find("unitName") == props.cend()) {
|
if (props.find("unitName") == props.cend()) {
|
||||||
sd_journal_perror("unitName doesn't exists.");
|
sd_journal_perror("unitName doesn't exists.");
|
||||||
serviceName = "invalidInput";
|
serviceName = "invalidInput";
|
||||||
return serviceName;
|
return serviceName;
|
||||||
}
|
}
|
||||||
if (ret = sd_bus_message_append(msg, "s", props["unitName"].data()); ret < 0) { // unitName
|
|
||||||
|
int ret;
|
||||||
|
if (ret = sd_bus_message_append(msg, "s", props["unitName"].front().data()); ret < 0) { // unitName
|
||||||
sd_journal_perror("append unitName failed.");
|
sd_journal_perror("append unitName failed.");
|
||||||
return serviceName;
|
return serviceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceName = props["unitName"];
|
serviceName = props["unitName"].front();
|
||||||
props.erase("unitName");
|
props.erase("unitName");
|
||||||
|
|
||||||
if (ret = sd_bus_message_append(msg, "s", "replace"); ret < 0) { // start mode
|
if (ret = sd_bus_message_append(msg, "s", "replace"); ret < 0) { // start mode
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
#include "variantValue.h"
|
#include "variantValue.h"
|
||||||
|
#include "constant.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
std::unique_ptr<VariantValue> creatValueHandler(msg_ptr &msg, DBusValueType type)
|
std::unique_ptr<VariantValue> creatValueHandler(msg_ptr &msg, DBusValueType type)
|
||||||
@ -34,29 +35,21 @@ int StringValue::appendValue(std::string &&value) noexcept
|
|||||||
|
|
||||||
int ASValue::openVariant() noexcept
|
int ASValue::openVariant() noexcept
|
||||||
{
|
{
|
||||||
return sd_bus_message_open_container(msgRef(), SD_BUS_TYPE_VARIANT, "as");
|
if (int ret = sd_bus_message_open_container(msgRef(), SD_BUS_TYPE_VARIANT, "as"); ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return sd_bus_message_open_container(msgRef(), SD_BUS_TYPE_ARRAY, "s");
|
||||||
}
|
}
|
||||||
|
|
||||||
int ASValue::closeVariant() noexcept
|
int ASValue::closeVariant() noexcept
|
||||||
{
|
{
|
||||||
|
if (int ret = sd_bus_message_close_container(msgRef()); ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
return sd_bus_message_close_container(msgRef());
|
return sd_bus_message_close_container(msgRef());
|
||||||
}
|
}
|
||||||
|
|
||||||
int ASValue::appendValue(std::string &&value) noexcept
|
int ASValue::appendValue(std::string &&value) noexcept
|
||||||
{
|
{
|
||||||
std::string envs{std::move(value)};
|
return sd_bus_message_append(msgRef(), "s", value.data());
|
||||||
std::istringstream stream{envs};
|
|
||||||
int ret{0};
|
|
||||||
|
|
||||||
if (ret = sd_bus_message_open_container(msgRef(), SD_BUS_TYPE_ARRAY, "s"); ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::string line; std::getline(stream, line, ';');) {
|
|
||||||
if (ret = sd_bus_message_append(msgRef(), "s", line.data()); ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sd_bus_message_close_container(msgRef());
|
|
||||||
}
|
}
|
||||||
|
12
debian/changelog
vendored
12
debian/changelog
vendored
@ -1,3 +1,15 @@
|
|||||||
|
dde-application-manager (1.2.16) unstable; urgency=medium
|
||||||
|
|
||||||
|
* release 1.2.16
|
||||||
|
|
||||||
|
-- tsic404 <liuheng@deepin.org> Thu, 10 Oct 2024 15:34:38 +0800
|
||||||
|
|
||||||
|
dde-application-manager (1.2.15) unstable; urgency=medium
|
||||||
|
|
||||||
|
* release 1.2.15
|
||||||
|
|
||||||
|
-- Mike Chen <chenke@deepin.org> Wed, 10 Jul 2024 13:09:51 +0800
|
||||||
|
|
||||||
dde-application-manager (1.2.14) unstable; urgency=medium
|
dde-application-manager (1.2.14) unstable; urgency=medium
|
||||||
|
|
||||||
* release 1.2.14
|
* release 1.2.14
|
||||||
|
1
debian/dde-application-manager-api.install
vendored
1
debian/dde-application-manager-api.install
vendored
@ -1 +1,2 @@
|
|||||||
usr/share/dde-application-manager/*.xml
|
usr/share/dde-application-manager/*.xml
|
||||||
|
usr/lib/*/cmake/DDEApplicationManager/*
|
||||||
|
2
debian/dde-application-manager.install
vendored
2
debian/dde-application-manager.install
vendored
@ -1,6 +1,6 @@
|
|||||||
etc/dpkg/*
|
etc/dpkg/*
|
||||||
usr/bin/*
|
usr/bin/*
|
||||||
usr/lib/*
|
usr/lib/systemd/*
|
||||||
usr/libexec/*
|
usr/libexec/*
|
||||||
usr/share/dbus-1/*
|
usr/share/dbus-1/*
|
||||||
usr/share/dsg/*
|
usr/share/dsg/*
|
||||||
|
@ -70,5 +70,7 @@ install(FILES ${CMAKE_CURRENT_LIST_DIR}/hooks.d/debFix.sh
|
|||||||
)
|
)
|
||||||
|
|
||||||
dtk_add_config_meta_files(APPID ${APPLICATION_SERVICEID}
|
dtk_add_config_meta_files(APPID ${APPLICATION_SERVICEID}
|
||||||
FILES ${CMAKE_CURRENT_LIST_DIR}/dsg/configs/dde-application-manager/org.deepin.dde.am.json
|
FILES
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/dsg/configs/dde-application-manager/org.deepin.dde.am.json
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/dsg/configs/dde-application-manager/org.deepin.dde.application-manager.json
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"magic": "dsg.config.meta",
|
||||||
|
"version": "1.0",
|
||||||
|
"contents": {
|
||||||
|
"appExtraEnvironments": {
|
||||||
|
"value": [],
|
||||||
|
"serial": 0,
|
||||||
|
"flags": [],
|
||||||
|
"name": "Launching app with extra environments",
|
||||||
|
"name[zh_CN]": "启动应用时附加额外环境变量",
|
||||||
|
"description": "Launching app with extra environments",
|
||||||
|
"permissions": "readwrite",
|
||||||
|
"visibility": "public"
|
||||||
|
},
|
||||||
|
"appEnvironmentsBlacklist": {
|
||||||
|
"value": [],
|
||||||
|
"serial": 0,
|
||||||
|
"flags": [],
|
||||||
|
"name": "Ignore blacklisted environment variables before launching app",
|
||||||
|
"name[zh_CN]": "启动应用时取消某些环境变量",
|
||||||
|
"description": "Ignore blacklisted environment variables before launching app",
|
||||||
|
"permissions": "readwrite",
|
||||||
|
"visibility": "public"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -65,4 +65,8 @@ constexpr auto ApplicationManagerHookDir = u8"/deepin/dde-application-manager/ho
|
|||||||
|
|
||||||
constexpr auto ApplicationManagerToolsConfig = u8"org.deepin.dde.am";
|
constexpr auto ApplicationManagerToolsConfig = u8"org.deepin.dde.am";
|
||||||
|
|
||||||
|
constexpr auto ApplicationManagerConfig = u8"org.deepin.dde.application-manager";
|
||||||
|
constexpr auto AppExtraEnvironments = u8"appExtraEnvironments";
|
||||||
|
constexpr auto AppEnvironmentsBlacklist = u8"appEnvironmentsBlacklist";
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -24,6 +24,7 @@ target_link_libraries(
|
|||||||
Qt${QT_VERSION_MAJOR}::Core
|
Qt${QT_VERSION_MAJOR}::Core
|
||||||
Qt${QT_VERSION_MAJOR}::DBus
|
Qt${QT_VERSION_MAJOR}::DBus
|
||||||
Qt${QT_VERSION_MAJOR}::Concurrent
|
Qt${QT_VERSION_MAJOR}::Concurrent
|
||||||
|
Dtk6::Core
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(
|
target_include_directories(
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "launchoptions.h"
|
#include "launchoptions.h"
|
||||||
#include "desktopentry.h"
|
#include "desktopentry.h"
|
||||||
#include "desktopfileparser.h"
|
#include "desktopfileparser.h"
|
||||||
|
#include "config.h"
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
@ -31,22 +32,51 @@
|
|||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <wordexp.h>
|
#include <wordexp.h>
|
||||||
|
#include <DConfig>
|
||||||
|
|
||||||
|
static inline void appendEnvs(const QVariant &var, QStringList &envs)
|
||||||
|
{
|
||||||
|
if (var.canConvert<QStringList>()) {
|
||||||
|
envs.append(var.value<QStringList>());
|
||||||
|
} else if (var.canConvert<QString>()) {
|
||||||
|
envs.append(var.value<QString>().split(";", Qt::SkipEmptyParts));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ApplicationService::appendExtraEnvironments(QVariantMap &runtimeOptions) const noexcept
|
void ApplicationService::appendExtraEnvironments(QVariantMap &runtimeOptions) const noexcept
|
||||||
{
|
{
|
||||||
QStringList envs;
|
DCORE_USE_NAMESPACE
|
||||||
|
QStringList envs, unsetEnvs;
|
||||||
const QString &env = environ();
|
const QString &env = environ();
|
||||||
if (!env.isEmpty())
|
if (!env.isEmpty())
|
||||||
envs.append(env);
|
envs.append(env);
|
||||||
|
|
||||||
if (auto it = runtimeOptions.find("env"); it != runtimeOptions.cend()) {
|
if (auto it = runtimeOptions.find("env"); it != runtimeOptions.cend()) {
|
||||||
envs.append(it->value<QString>());
|
appendEnvs(*it, envs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto it = runtimeOptions.find("unsetEnv"); it != runtimeOptions.cend()) {
|
||||||
|
appendEnvs(*it, unsetEnvs);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<DConfig> config(DConfig::create(ApplicationServiceID,
|
||||||
|
ApplicationManagerConfig,
|
||||||
|
QString("/%1").arg((id())))); // $appid as subpath
|
||||||
|
if (config->isValid()) {
|
||||||
|
const QStringList &extraEnvs = config->value(AppExtraEnvironments).toStringList();
|
||||||
|
if (!extraEnvs.isEmpty())
|
||||||
|
envs.append(extraEnvs);
|
||||||
|
|
||||||
|
const QStringList &envsBlacklist = config->value(AppEnvironmentsBlacklist).toStringList();
|
||||||
|
if (!envsBlacklist.isEmpty())
|
||||||
|
unsetEnvs.append(envsBlacklist);
|
||||||
}
|
}
|
||||||
|
|
||||||
// it's useful for App to get itself AppId.
|
// it's useful for App to get itself AppId.
|
||||||
envs.append(QString{"DSG_APP_ID=%1"}.arg(id()));
|
envs.append(QString{"DSG_APP_ID=%1"}.arg(id()));
|
||||||
|
|
||||||
runtimeOptions.insert("env", envs.join(';'));
|
runtimeOptions.insert("env", envs);
|
||||||
|
runtimeOptions.insert("unsetEnv", unsetEnvs);
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplicationService::ApplicationService(DesktopFile source,
|
ApplicationService::ApplicationService(DesktopFile source,
|
||||||
@ -220,8 +250,8 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
|
|||||||
execStr = toString(actionExec.value());
|
execStr = toString(actionExec.value());
|
||||||
if (execStr.isEmpty()) {
|
if (execStr.isEmpty()) {
|
||||||
qWarning() << "exec value to string failed, try default action."; // we need this log.
|
qWarning() << "exec value to string failed, try default action."; // we need this log.
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +295,7 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
|
|||||||
|
|
||||||
if (terminal()) {
|
if (terminal()) {
|
||||||
// don't change this sequence
|
// don't change this sequence
|
||||||
execCmds.push_front("-C"); // means run a shellscript
|
execCmds.push_front("-e"); // run all original execution commands in deepin-terminal
|
||||||
execCmds.push_front("--keep-open"); // keep terminal open, prevent exit immediately
|
execCmds.push_front("--keep-open"); // keep terminal open, prevent exit immediately
|
||||||
execCmds.push_front("deepin-terminal");
|
execCmds.push_front("deepin-terminal");
|
||||||
}
|
}
|
||||||
@ -274,46 +304,78 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
|
|||||||
auto &jobManager = parent()->jobManager();
|
auto &jobManager = parent()->jobManager();
|
||||||
return jobManager.addJob(
|
return jobManager.addJob(
|
||||||
m_applicationPath.path(),
|
m_applicationPath.path(),
|
||||||
[this, binary = std::move(bin), commands = std::move(cmds)](const QVariant &variantValue) -> QVariant {
|
[this, binary = std::move(bin), commands = std::move(cmds)](const QVariant &value) -> QVariant {
|
||||||
auto resourceFile = variantValue.toString();
|
auto rawResources = value.toString();
|
||||||
auto instanceRandomUUID = QUuid::createUuid().toString(QUuid::Id128);
|
auto instanceRandomUUID = QUuid::createUuid().toString(QUuid::Id128);
|
||||||
auto objectPath = m_applicationPath.path() + "/" + instanceRandomUUID;
|
auto objectPath = m_applicationPath.path() + "/" + instanceRandomUUID;
|
||||||
auto newCommands = commands;
|
auto newCommands = commands;
|
||||||
|
|
||||||
newCommands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath()));
|
newCommands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath()));
|
||||||
auto location = newCommands.indexOf(R"(%f)");
|
if (rawResources.isEmpty()) {
|
||||||
if (location != -1) { // due to std::move, there only remove once
|
|
||||||
newCommands.remove(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resourceFile.isEmpty()) {
|
|
||||||
newCommands.push_front(QString{R"(--unitName=app-DDE-%1@%2.service)"}.arg(
|
newCommands.push_front(QString{R"(--unitName=app-DDE-%1@%2.service)"}.arg(
|
||||||
escapeApplicationId(this->id()), instanceRandomUUID)); // launcher should use this instanceId
|
escapeApplicationId(this->id()), instanceRandomUUID)); // launcher should use this instanceId
|
||||||
|
|
||||||
QProcess process;
|
QProcess process;
|
||||||
qDebug() << "run with commands:" << newCommands;
|
qDebug() << "launcher :" << m_launcher << "run with commands:" << newCommands;
|
||||||
process.start(m_launcher, newCommands);
|
process.start(m_launcher, newCommands);
|
||||||
process.waitForFinished();
|
process.waitForFinished();
|
||||||
if (auto code = process.exitCode(); code != 0) {
|
if (auto code = process.exitCode(); code != 0) {
|
||||||
qWarning() << "Launch Application Failed";
|
qWarning() << "Launch Application Failed";
|
||||||
return QDBusError::Failed;
|
return QDBusError::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return objectPath;
|
return objectPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto url = QUrl::fromUserInput(resourceFile);
|
auto location = newCommands.end();
|
||||||
if (!url.isValid()) { // if url is invalid, passing to launcher directly
|
qsizetype fieldIndex{-1};
|
||||||
auto scheme = url.scheme();
|
for (auto it = newCommands.begin(); it != newCommands.end(); ++it) {
|
||||||
if (!scheme.isEmpty()) {
|
auto fieldLocation = it->indexOf(R"(%f)");
|
||||||
// TODO: resourceFile = processRemoteFile(resourceFile);
|
if (fieldLocation != -1) {
|
||||||
|
fieldIndex = fieldLocation;
|
||||||
|
location = it;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldLocation = it->indexOf(R"(%F)");
|
||||||
|
if (fieldLocation != -1) {
|
||||||
|
fieldIndex = fieldLocation;
|
||||||
|
location = it;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: resourceFile must be available in the following contexts
|
if (location == newCommands.end()) {
|
||||||
newCommands.insert(location, resourceFile);
|
qCritical() << R"(internal logic error, can't find %f or %F in exec command, abort.)";
|
||||||
|
return QDBusError::Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &rawResource = rawResources.split(' ', Qt::SkipEmptyParts);
|
||||||
|
QStringList resources;
|
||||||
|
std::transform(rawResource.cbegin(), rawResource.cend(), std::back_inserter(resources), [](const QString &res) {
|
||||||
|
auto url = QUrl::fromUserInput(res);
|
||||||
|
if (url.isValid()) {
|
||||||
|
if (url.isLocalFile()) {
|
||||||
|
return url.toLocalFile();
|
||||||
|
}
|
||||||
|
// for now, we only support local file, maybe we will support remote file in the future.
|
||||||
|
// TODO: return processRemoteFile(url);
|
||||||
|
} // if url is invalid, passing to launcher directly
|
||||||
|
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
auto tmpRes = resources.join(' ');
|
||||||
|
|
||||||
|
location->replace(fieldIndex, tmpRes.size(), tmpRes);
|
||||||
|
auto newCmd = location->split(' ', Qt::SkipEmptyParts);
|
||||||
|
location = newCommands.erase(location);
|
||||||
|
for (auto &c : newCmd) {
|
||||||
|
location = newCommands.insert(location, std::move(c));
|
||||||
|
}
|
||||||
newCommands.push_front(QString{R"(--unitName=DDE-%1@%2.service)"}.arg(this->id(), instanceRandomUUID));
|
newCommands.push_front(QString{R"(--unitName=DDE-%1@%2.service)"}.arg(this->id(), instanceRandomUUID));
|
||||||
|
|
||||||
QProcess process;
|
QProcess process;
|
||||||
qDebug() << "run with commands:" << newCommands;
|
qDebug().noquote() << "launcher :" << m_launcher << "run with commands:" << newCommands;
|
||||||
process.start(getApplicationLauncherBinary(), newCommands);
|
process.start(getApplicationLauncherBinary(), newCommands);
|
||||||
process.waitForFinished();
|
process.waitForFinished();
|
||||||
auto exitCode = process.exitCode();
|
auto exitCode = process.exitCode();
|
||||||
@ -321,6 +383,7 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
|
|||||||
qWarning() << "Launch Application Failed";
|
qWarning() << "Launch Application Failed";
|
||||||
return QDBusError::Failed;
|
return QDBusError::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return objectPath;
|
return objectPath;
|
||||||
},
|
},
|
||||||
std::move(res));
|
std::move(res));
|
||||||
@ -529,6 +592,12 @@ bool ApplicationService::terminal() const noexcept
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ApplicationService::startupWMClass() const noexcept
|
||||||
|
{
|
||||||
|
auto value = findEntryValue(DesktopFileEntryKey, "StartupWMClass", EntryValueType::String);
|
||||||
|
return value.isNull() ? QString{} : value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
qint64 ApplicationService::installedTime() const noexcept
|
qint64 ApplicationService::installedTime() const noexcept
|
||||||
{
|
{
|
||||||
return m_installedTime;
|
return m_installedTime;
|
||||||
@ -599,6 +668,12 @@ bool ApplicationService::autostartCheck(const QString &filePath) const noexcept
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString source = s.value(DesktopFileEntryKey, X_Deepin_GenerateSource).value_or(DesktopEntry::Value{}).toString();
|
||||||
|
// file has been removed
|
||||||
|
if (source != m_autostartSource.m_filePath && filePath != m_autostartSource.m_filePath) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto hiddenVal = s.value(DesktopFileEntryKey, DesktopEntryHidden);
|
auto hiddenVal = s.value(DesktopFileEntryKey, DesktopEntryHidden);
|
||||||
if (!hiddenVal) {
|
if (!hiddenVal) {
|
||||||
qDebug() << "no hidden in autostart desktop";
|
qDebug() << "no hidden in autostart desktop";
|
||||||
@ -636,11 +711,6 @@ bool ApplicationService::isAutoStart() const noexcept
|
|||||||
{"*.desktop"},
|
{"*.desktop"},
|
||||||
QDir::Name | QDir::DirsLast);
|
QDir::Name | QDir::DirsLast);
|
||||||
|
|
||||||
// file has been removed
|
|
||||||
if (destDesktopFile != m_autostartSource.m_filePath) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return autostartCheck(destDesktopFile);
|
return autostartCheck(destDesktopFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -863,6 +933,7 @@ void ApplicationService::resetEntry(DesktopEntry *newEntry) noexcept
|
|||||||
emit terminalChanged();
|
emit terminalChanged();
|
||||||
emit environChanged();
|
emit environChanged();
|
||||||
emit launchedTimesChanged();
|
emit launchedTimesChanged();
|
||||||
|
emit startupWMClassChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QStringList> ApplicationService::unescapeExecArgs(const QString &str) noexcept
|
std::optional<QStringList> ApplicationService::unescapeExecArgs(const QString &str) noexcept
|
||||||
@ -919,139 +990,160 @@ std::optional<QStringList> ApplicationService::unescapeExecArgs(const QString &s
|
|||||||
return execList;
|
return execList;
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchTask ApplicationService::unescapeExec(const QString &str, const QStringList &fields) noexcept
|
LaunchTask ApplicationService::unescapeExec(const QString &str, QStringList fields) noexcept
|
||||||
{
|
{
|
||||||
LaunchTask task;
|
LaunchTask task;
|
||||||
auto opt = unescapeExecArgs(str);
|
auto args = unescapeExecArgs(str);
|
||||||
|
|
||||||
if (!opt.has_value()) {
|
if (!args) {
|
||||||
qWarning() << "unescapeExecArgs failed.";
|
qWarning() << "unescapeExecArgs failed.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto execList = std::move(opt).value();
|
if (args->isEmpty()) {
|
||||||
if (execList.isEmpty()) {
|
|
||||||
qWarning() << "exec format is invalid.";
|
qWarning() << "exec format is invalid.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
task.LaunchBin = execList.first();
|
auto processUrl = [](const QString &str) {
|
||||||
QRegularExpression re{"%[fFuUickdDnNvm]"};
|
auto url = QUrl::fromUserInput(str);
|
||||||
auto matcher = re.match(str);
|
if (!url.isValid()) {
|
||||||
if (!matcher.hasMatch()) {
|
qDebug() << "url is invalid, pass to exec directly.";
|
||||||
task.command.append(std::move(execList));
|
return str;
|
||||||
task.Resources.emplace_back(QString{""}); // mapReduce should run once at least
|
|
||||||
return task;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto list = matcher.capturedTexts();
|
if (url.isLocalFile()) {
|
||||||
if (list.count() != 1) {
|
return url.toLocalFile();
|
||||||
qWarning() << "invalid exec format, all filed code will be ignored.";
|
|
||||||
for (const auto &code : list) {
|
|
||||||
execList.removeOne(code);
|
|
||||||
}
|
|
||||||
task.command.append(std::move(execList));
|
|
||||||
return task;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto filesCode = list.first().back().toLatin1();
|
return url.toString();
|
||||||
auto codeStr = QString(R"(%%1)").arg(filesCode);
|
};
|
||||||
auto location = execList.indexOf(codeStr);
|
|
||||||
if (location == -1) {
|
task.LaunchBin = args->first();
|
||||||
qWarning() << "invalid exec format, all filed code will be ignored.";
|
const QChar percentage{'%'};
|
||||||
|
bool exclusiveField{false};
|
||||||
|
|
||||||
|
for (const auto &arg : *args) {
|
||||||
|
QString newArg;
|
||||||
|
|
||||||
|
for (const auto *it = arg.cbegin(); it != arg.cend();) {
|
||||||
|
if (*it != percentage) {
|
||||||
|
newArg.append(*(it++));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto *code = it + 1;
|
||||||
|
if (code == arg.cend()) {
|
||||||
|
qWarning() << R"(content of exec is invalid, a unterminated % is detected.)";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (filesCode) {
|
if (*code == percentage) {
|
||||||
case 'f': { // Defer to async job
|
newArg.append(percentage);
|
||||||
task.command.append(std::move(execList));
|
it += 2;
|
||||||
for (const auto &field : fields) {
|
continue;
|
||||||
task.Resources.emplace_back(field);
|
|
||||||
}
|
}
|
||||||
} break;
|
|
||||||
case 'u': {
|
switch (code->toLatin1()) {
|
||||||
execList.removeAt(location);
|
case 'f': { // Defer to async job
|
||||||
if (fields.empty()) {
|
if (exclusiveField) {
|
||||||
task.command.append(execList);
|
qDebug() << R"(exclusive field is detected again, %f will be ignored.)";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (fields.count() > 1) {
|
exclusiveField = true;
|
||||||
|
|
||||||
|
if (fields.empty()) {
|
||||||
|
qDebug() << R"(fields is empty, %f will be ignored.)";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fields.size() > 1) {
|
||||||
|
qDebug() << R"(fields count is greater than one, %f will only take first element.)";
|
||||||
|
}
|
||||||
|
|
||||||
|
task.Resources.emplace_back(fields.takeFirst());
|
||||||
|
newArg.append(R"(%f)");
|
||||||
|
} break;
|
||||||
|
case 'u': {
|
||||||
|
if (exclusiveField) {
|
||||||
|
qDebug() << R"(exclusive field is detected again, %f will be ignored.)";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
exclusiveField = true;
|
||||||
|
|
||||||
|
if (fields.empty()) {
|
||||||
|
qDebug() << "fields is empty, %u will be ignored.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fields.size() > 1) {
|
||||||
qDebug() << R"(fields count is greater than one, %u will only take first element.)";
|
qDebug() << R"(fields count is greater than one, %u will only take first element.)";
|
||||||
}
|
}
|
||||||
execList.insert(location, fields.first());
|
|
||||||
task.command.append(execList);
|
newArg.append(processUrl(fields.takeFirst()));
|
||||||
} break;
|
} break;
|
||||||
case 'F': {
|
case 'F': { // Defer to async job
|
||||||
execList.remove(location);
|
if (exclusiveField) {
|
||||||
auto it = execList.begin() + location;
|
qDebug() << R"(exclusive field is detected again, %f will be ignored.)";
|
||||||
for (const auto &field : fields) {
|
break;
|
||||||
auto tmp = QUrl::fromUserInput(field);
|
|
||||||
if (auto scheme = tmp.scheme(); scheme.startsWith("file") or scheme.isEmpty()) {
|
|
||||||
it = execList.insert(it, tmp.toLocalFile());
|
|
||||||
} else {
|
|
||||||
qWarning() << "shouldn't replace %F with an URL:" << field;
|
|
||||||
it = execList.insert(it, field);
|
|
||||||
}
|
}
|
||||||
++it;
|
exclusiveField = true;
|
||||||
}
|
|
||||||
task.command.append(std::move(execList));
|
task.Resources.emplace_back(fields.join(' '));
|
||||||
|
fields.clear();
|
||||||
|
newArg.append(R"(%F)");
|
||||||
} break;
|
} break;
|
||||||
case 'U': {
|
case 'U': {
|
||||||
execList.removeAt(location);
|
if (exclusiveField) {
|
||||||
auto it = execList.begin() + location;
|
qDebug() << R"(exclusive field is detected again, %f will be ignored.)";
|
||||||
for (const auto &field : fields) {
|
break;
|
||||||
it = execList.insert(it, field);
|
|
||||||
++it;
|
|
||||||
}
|
}
|
||||||
task.command.append(std::move(execList));
|
exclusiveField = true;
|
||||||
|
|
||||||
|
QStringList urls;
|
||||||
|
std::transform(fields.cbegin(), fields.cend(), std::back_inserter(urls), processUrl);
|
||||||
|
fields.clear();
|
||||||
|
newArg.append(urls.join(' ')); // split at the end of loop
|
||||||
} break;
|
} break;
|
||||||
case 'i': {
|
case 'i': {
|
||||||
execList.removeAt(location);
|
|
||||||
auto val = m_entry->value(DesktopFileEntryKey, "Icon");
|
auto val = m_entry->value(DesktopFileEntryKey, "Icon");
|
||||||
if (!val) {
|
if (!val) {
|
||||||
qDebug() << R"(Application Icons can't be found. %i will be ignored.)";
|
qDebug() << R"(Application Icons can't be found. %i will be ignored.)";
|
||||||
task.command.append(std::move(execList));
|
break;
|
||||||
return task;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto iconStr = toIconString(val.value());
|
auto iconStr = toIconString(val.value());
|
||||||
if (iconStr.isEmpty()) {
|
if (iconStr.isEmpty()) {
|
||||||
qDebug() << R"(Icons Convert to string failed. %i will be ignored.)";
|
qDebug() << R"(Icons Convert to string failed. %i will be ignored.)";
|
||||||
task.command.append(std::move(execList));
|
break;
|
||||||
return task;
|
|
||||||
}
|
}
|
||||||
auto it = execList.insert(location, iconStr);
|
|
||||||
execList.insert(it, "--icon");
|
// split at the end of loop
|
||||||
task.command.append(std::move(execList));
|
newArg.append(QString{"--icon %1"}.arg(iconStr));
|
||||||
} break;
|
} break;
|
||||||
case 'c': {
|
case 'c': {
|
||||||
execList.removeAt(location);
|
|
||||||
auto val = m_entry->value(DesktopFileEntryKey, "Name");
|
auto val = m_entry->value(DesktopFileEntryKey, "Name");
|
||||||
if (!val) {
|
if (!val) {
|
||||||
qDebug() << R"(Application Name can't be found. %c will be ignored.)";
|
qDebug() << R"(Application Name can't be found. %c will be ignored.)";
|
||||||
task.command.append(std::move(execList));
|
break;
|
||||||
return task;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &rawValue = val.value();
|
const auto &rawValue = val.value();
|
||||||
if (!rawValue.canConvert<QStringMap>()) {
|
if (!rawValue.canConvert<QStringMap>()) {
|
||||||
qDebug() << "Name's underlying type mismatch:" << "QStringMap" << rawValue.metaType().name();
|
qDebug() << "Name's underlying type mismatch:" << "QStringMap" << rawValue.metaType().name();
|
||||||
task.command.append(std::move(execList));
|
break;
|
||||||
return task;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto NameStr = toLocaleString(rawValue.value<QStringMap>(), getUserLocale());
|
auto NameStr = toLocaleString(rawValue.value<QStringMap>(), getUserLocale());
|
||||||
if (NameStr.isEmpty()) {
|
if (NameStr.isEmpty()) {
|
||||||
qDebug() << R"(Name Convert to locale string failed. %c will be ignored.)";
|
qDebug() << R"(Name Convert to locale string failed. %c will be ignored.)";
|
||||||
task.command.append(std::move(execList));
|
break;
|
||||||
return task;
|
|
||||||
}
|
}
|
||||||
execList.insert(location, NameStr);
|
|
||||||
task.command.append(std::move(execList));
|
newArg.append(NameStr);
|
||||||
} break;
|
} break;
|
||||||
case 'k': { // ignore all desktop file location for now.
|
case 'k': { // ignore all desktop file location for now.
|
||||||
execList.removeAt(location);
|
newArg.append(m_desktopSource.sourcePath());
|
||||||
task.command.append(std::move(execList));
|
|
||||||
} break;
|
} break;
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'D':
|
case 'D':
|
||||||
@ -1060,11 +1152,19 @@ LaunchTask ApplicationService::unescapeExec(const QString &str, const QStringLis
|
|||||||
case 'v':
|
case 'v':
|
||||||
[[fallthrough]]; // Deprecated field codes should be removed from the command line and ignored.
|
[[fallthrough]]; // Deprecated field codes should be removed from the command line and ignored.
|
||||||
case 'm': {
|
case 'm': {
|
||||||
execList.removeAt(location);
|
qDebug() << "field code" << *code << "has been deprecated.";
|
||||||
task.command.append(std::move(execList));
|
|
||||||
} break;
|
} break;
|
||||||
default: {
|
default: {
|
||||||
qDebug() << "unrecognized file code.";
|
qDebug() << "unknown field code:" << *code << ", ignore it.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it += 2; // skip filed code
|
||||||
|
}
|
||||||
|
|
||||||
|
auto newArgList = newArg.split(' ', Qt::SkipEmptyParts);
|
||||||
|
if (!newArgList.isEmpty()) {
|
||||||
|
task.command.append(std::move(newArgList));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1072,9 +1172,54 @@ LaunchTask ApplicationService::unescapeExec(const QString &str, const QStringLis
|
|||||||
task.Resources.emplace_back(QString{""}); // mapReduce should run once at least
|
task.Resources.emplace_back(QString{""}); // mapReduce should run once at least
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qInfo() << "after unescape exec:" << task.LaunchBin << task.command << task.Resources;
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApplicationService::unescapeEens(QVariantMap &options) noexcept
|
||||||
|
{
|
||||||
|
if (options.find("env") == options.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QStringList result;
|
||||||
|
auto envs = options["env"];
|
||||||
|
for (const QString &var : envs.toStringList()) {
|
||||||
|
wordexp_t p;
|
||||||
|
if (wordexp(var.toStdString().c_str(), &p, 0) == 0) {
|
||||||
|
for (size_t i = 0; i < p.we_wordc; i++) {
|
||||||
|
result << QString::fromLocal8Bit(p.we_wordv[i]); // 将结果转换为QString
|
||||||
|
}
|
||||||
|
wordfree(&p);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
options.insert("env", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplicationService::autoRemoveFromDesktop() const noexcept
|
||||||
|
{
|
||||||
|
auto dir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||||
|
if (dir.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileInfo desktopFile{QDir{dir}.filePath(m_desktopSource.desktopId() + ".desktop")};
|
||||||
|
|
||||||
|
if (!desktopFile.isSymbolicLink()) {
|
||||||
|
qDebug() << desktopFile.filePath() << " is not symbolicLink";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file{desktopFile.filePath()};
|
||||||
|
auto success = file.remove();
|
||||||
|
if (!success) {
|
||||||
|
qWarning() << "remove desktop file failed:" << file.errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QVariant ApplicationService::findEntryValue(const QString &group,
|
QVariant ApplicationService::findEntryValue(const QString &group,
|
||||||
const QString &valueKey,
|
const QString &valueKey,
|
||||||
EntryValueType type,
|
EntryValueType type,
|
||||||
|
@ -74,6 +74,9 @@ public:
|
|||||||
Q_PROPERTY(bool Terminal READ terminal NOTIFY terminalChanged)
|
Q_PROPERTY(bool Terminal READ terminal NOTIFY terminalChanged)
|
||||||
[[nodiscard]] bool terminal() const noexcept;
|
[[nodiscard]] bool terminal() const noexcept;
|
||||||
|
|
||||||
|
Q_PROPERTY(QString StartupWMClass READ startupWMClass NOTIFY startupWMClassChanged)
|
||||||
|
[[nodiscard]] QString startupWMClass() const noexcept;
|
||||||
|
|
||||||
// FIXME:
|
// FIXME:
|
||||||
// This property should implement with fuse guarded
|
// This property should implement with fuse guarded
|
||||||
// $XDG_CONFIG_HOME/autostart/. Current implementation has some problems,
|
// $XDG_CONFIG_HOME/autostart/. Current implementation has some problems,
|
||||||
@ -131,7 +134,9 @@ public:
|
|||||||
EntryValueType type,
|
EntryValueType type,
|
||||||
const QLocale &locale = getUserLocale()) const noexcept;
|
const QLocale &locale = getUserLocale()) const noexcept;
|
||||||
|
|
||||||
[[nodiscard]] LaunchTask unescapeExec(const QString &str, const QStringList &fields) noexcept;
|
[[nodiscard]] LaunchTask unescapeExec(const QString &str, QStringList fields) noexcept;
|
||||||
|
void autoRemoveFromDesktop() const noexcept;
|
||||||
|
void unescapeEens(QVariantMap&) noexcept;
|
||||||
[[nodiscard]] static std::optional<QStringList> unescapeExecArgs(const QString &str) noexcept;
|
[[nodiscard]] static std::optional<QStringList> unescapeExecArgs(const QString &str) noexcept;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
@ -163,6 +168,7 @@ Q_SIGNALS:
|
|||||||
void terminalChanged();
|
void terminalChanged();
|
||||||
void environChanged();
|
void environChanged();
|
||||||
void launchedTimesChanged();
|
void launchedTimesChanged();
|
||||||
|
void startupWMClassChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class ApplicationManager1Service;
|
friend class ApplicationManager1Service;
|
||||||
|
@ -544,6 +544,8 @@ template <typename Key, typename Value>
|
|||||||
ObjectMap dumpDBusObject(const QHash<Key, QSharedPointer<Value>> &map)
|
ObjectMap dumpDBusObject(const QHash<Key, QSharedPointer<Value>> &map)
|
||||||
{
|
{
|
||||||
static_assert(std::is_base_of_v<QObject, Value>, "dumpDBusObject only support which derived by QObject class");
|
static_assert(std::is_base_of_v<QObject, Value>, "dumpDBusObject only support which derived by QObject class");
|
||||||
|
static_assert(std::is_same_v<Key, QString> || std::is_same_v<Key, QDBusObjectPath>,
|
||||||
|
"dumpDBusObject only support QString/QDBusObject as key type");
|
||||||
ObjectMap objs;
|
ObjectMap objs;
|
||||||
|
|
||||||
for (const auto &[key, value] : map.asKeyValueRange()) {
|
for (const auto &[key, value] : map.asKeyValueRange()) {
|
||||||
@ -552,8 +554,6 @@ ObjectMap dumpDBusObject(const QHash<Key, QSharedPointer<Value>> &map)
|
|||||||
objs.insert(QDBusObjectPath{getObjectPathFromAppId(key)}, interAndProps);
|
objs.insert(QDBusObjectPath{getObjectPathFromAppId(key)}, interAndProps);
|
||||||
} else if constexpr (std::is_same_v<Key, QDBusObjectPath>) {
|
} else if constexpr (std::is_same_v<Key, QDBusObjectPath>) {
|
||||||
objs.insert(key, interAndProps);
|
objs.insert(key, interAndProps);
|
||||||
} else {
|
|
||||||
static_assert(false, "dumpDBusObject only support QString/QDBusObject as key type");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ QStringList generateCommand(const QVariantMap &props) noexcept
|
|||||||
options.emplace_back(std::make_unique<setUserLaunchOption>(value));
|
options.emplace_back(std::make_unique<setUserLaunchOption>(value));
|
||||||
} else if (key == setEnvLaunchOption::key()) {
|
} else if (key == setEnvLaunchOption::key()) {
|
||||||
options.emplace_back(std::make_unique<setEnvLaunchOption>(value));
|
options.emplace_back(std::make_unique<setEnvLaunchOption>(value));
|
||||||
|
} else if (key == unsetEnvLaunchOption::key()) {
|
||||||
|
options.emplace_back(std::make_unique<unsetEnvLaunchOption>(value));
|
||||||
} else if (key == hookLaunchOption::key()) {
|
} else if (key == hookLaunchOption::key()) {
|
||||||
options.emplace_back(std::make_unique<hookLaunchOption>(value));
|
options.emplace_back(std::make_unique<hookLaunchOption>(value));
|
||||||
} else if (key == setWorkingPathLaunchOption::key()) {
|
} else if (key == setWorkingPathLaunchOption::key()) {
|
||||||
@ -100,16 +102,6 @@ QStringList splitLaunchOption::generateCommandLine() const noexcept
|
|||||||
return QStringList{m_val.toString()};
|
return QStringList{m_val.toString()};
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList setEnvLaunchOption::generateCommandLine() const noexcept
|
|
||||||
{
|
|
||||||
auto str = m_val.toString();
|
|
||||||
if (str.isEmpty()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return QStringList{QString{"--Environment=%1"}.arg(str)};
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList setWorkingPathLaunchOption::generateCommandLine() const noexcept
|
QStringList setWorkingPathLaunchOption::generateCommandLine() const noexcept
|
||||||
{
|
{
|
||||||
auto str = m_val.toString();
|
auto str = m_val.toString();
|
||||||
@ -120,13 +112,18 @@ QStringList setWorkingPathLaunchOption::generateCommandLine() const noexcept
|
|||||||
return QStringList{QString{"--WorkingDirectory=%1"}.arg(str)};
|
return QStringList{QString{"--WorkingDirectory=%1"}.arg(str)};
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList builtInSearchExecOption::generateCommandLine() const noexcept
|
QStringList StringListLaunchOption::generateCommandLine() const noexcept
|
||||||
{
|
{
|
||||||
auto list = m_val.toStringList();
|
auto list = m_val.toStringList();
|
||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto content = list.join(';');
|
QStringList ret;
|
||||||
return QStringList{QString{"--ExecSearchPath=%1"}.arg(content)};
|
const QString ok = optionKey();
|
||||||
|
for (const auto &ov : list) {
|
||||||
|
ret << QString{"%1=%2"}.arg(ok).arg(ov);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,14 @@ protected:
|
|||||||
LaunchOption() = default;
|
LaunchOption() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct StringListLaunchOption : public LaunchOption
|
||||||
|
{
|
||||||
|
using LaunchOption::LaunchOption;
|
||||||
|
[[nodiscard]] QStringList generateCommandLine() const noexcept override;
|
||||||
|
protected:
|
||||||
|
[[nodiscard]] virtual const QString optionKey() const noexcept = 0;
|
||||||
|
};
|
||||||
|
|
||||||
struct setUserLaunchOption : public LaunchOption
|
struct setUserLaunchOption : public LaunchOption
|
||||||
{
|
{
|
||||||
using LaunchOption::LaunchOption;
|
using LaunchOption::LaunchOption;
|
||||||
@ -43,9 +51,9 @@ struct setUserLaunchOption : public LaunchOption
|
|||||||
[[nodiscard]] QStringList generateCommandLine() const noexcept override;
|
[[nodiscard]] QStringList generateCommandLine() const noexcept override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct setEnvLaunchOption : public LaunchOption
|
struct setEnvLaunchOption : public StringListLaunchOption
|
||||||
{
|
{
|
||||||
using LaunchOption::LaunchOption;
|
using StringListLaunchOption::StringListLaunchOption;
|
||||||
[[nodiscard]] const QString &type() const noexcept override
|
[[nodiscard]] const QString &type() const noexcept override
|
||||||
{
|
{
|
||||||
static QString tp{systemdOption};
|
static QString tp{systemdOption};
|
||||||
@ -56,7 +64,10 @@ struct setEnvLaunchOption : public LaunchOption
|
|||||||
static QString env{"env"};
|
static QString env{"env"};
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
[[nodiscard]] QStringList generateCommandLine() const noexcept override;
|
protected:
|
||||||
|
[[nodiscard]] virtual const QString optionKey() const noexcept {
|
||||||
|
return QString("--Environment");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct splitLaunchOption : public LaunchOption
|
struct splitLaunchOption : public LaunchOption
|
||||||
@ -110,9 +121,9 @@ struct setWorkingPathLaunchOption : public LaunchOption
|
|||||||
[[nodiscard]] QStringList generateCommandLine() const noexcept override;
|
[[nodiscard]] QStringList generateCommandLine() const noexcept override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct builtInSearchExecOption : public LaunchOption
|
struct builtInSearchExecOption : public StringListLaunchOption
|
||||||
{
|
{
|
||||||
using LaunchOption::LaunchOption;
|
using StringListLaunchOption::StringListLaunchOption;
|
||||||
[[nodiscard]] const QString &type() const noexcept override
|
[[nodiscard]] const QString &type() const noexcept override
|
||||||
{
|
{
|
||||||
static QString tp{systemdOption};
|
static QString tp{systemdOption};
|
||||||
@ -123,7 +134,29 @@ struct builtInSearchExecOption : public LaunchOption
|
|||||||
static QString key{"_builtIn_searchExec"};
|
static QString key{"_builtIn_searchExec"};
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
[[nodiscard]] QStringList generateCommandLine() const noexcept override;
|
protected:
|
||||||
|
[[nodiscard]] virtual const QString optionKey() const noexcept {
|
||||||
|
return QString("--ExecSearchPath");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct unsetEnvLaunchOption : public StringListLaunchOption
|
||||||
|
{
|
||||||
|
using StringListLaunchOption::StringListLaunchOption;
|
||||||
|
[[nodiscard]] const QString &type() const noexcept override
|
||||||
|
{
|
||||||
|
static QString tp{systemdOption};
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
[[nodiscard]] static const QString &key() noexcept
|
||||||
|
{
|
||||||
|
static QString env{"unsetEnv"};
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
[[nodiscard]] virtual const QString optionKey() const noexcept {
|
||||||
|
return QString("--UnsetEnvironment");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
QStringList generateCommand(const QVariantMap &props) noexcept;
|
QStringList generateCommand(const QVariantMap &props) noexcept;
|
||||||
|
Loading…
Reference in New Issue
Block a user