|
|
|
@ -250,8 +250,8 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
|
|
|
|
|
execStr = toString(actionExec.value());
|
|
|
|
|
if (execStr.isEmpty()) {
|
|
|
|
|
qWarning() << "exec value to string failed, try default action."; // we need this log.
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -286,8 +286,7 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto [bin, execCmds, res] = std::move(task);
|
|
|
|
|
if (bin.isEmpty()) {
|
|
|
|
|
if (task.LaunchBin.isEmpty()) {
|
|
|
|
|
qCritical() << "error command is detected, abort.";
|
|
|
|
|
safe_sendErrorReply(QDBusError::Failed);
|
|
|
|
|
return {};
|
|
|
|
@ -295,55 +294,60 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
|
|
|
|
|
|
|
|
|
|
if (terminal()) {
|
|
|
|
|
// don't change this sequence
|
|
|
|
|
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("deepin-terminal");
|
|
|
|
|
cmds.push_back("deepin-terminal");
|
|
|
|
|
cmds.push_back("--keep-open"); // keep terminal open, prevent exit immediately
|
|
|
|
|
cmds.push_back("-e"); // run all original execution commands in deepin-terminal
|
|
|
|
|
}
|
|
|
|
|
cmds.append(std::move(execCmds));
|
|
|
|
|
|
|
|
|
|
auto &jobManager = parent()->jobManager();
|
|
|
|
|
return jobManager.addJob(
|
|
|
|
|
m_applicationPath.path(),
|
|
|
|
|
[this, binary = std::move(bin), commands = std::move(cmds)](const QVariant &variantValue) -> QVariant {
|
|
|
|
|
auto resourceFile = variantValue.toString();
|
|
|
|
|
[this, task, cmds = std::move(cmds)](const QVariant &value) -> QVariant { // do not change it to mutable lambda
|
|
|
|
|
auto instanceRandomUUID = QUuid::createUuid().toString(QUuid::Id128);
|
|
|
|
|
auto objectPath = m_applicationPath.path() + "/" + instanceRandomUUID;
|
|
|
|
|
auto newCommands = commands;
|
|
|
|
|
auto newCommands = cmds;
|
|
|
|
|
|
|
|
|
|
newCommands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath()));
|
|
|
|
|
auto location = newCommands.indexOf(R"(%f)");
|
|
|
|
|
if (location != -1) { // due to std::move, there only remove once
|
|
|
|
|
newCommands.remove(location);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (resourceFile.isEmpty()) {
|
|
|
|
|
if (value.isNull()) {
|
|
|
|
|
newCommands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath()));
|
|
|
|
|
newCommands.push_front(QString{R"(--unitName=app-DDE-%1@%2.service)"}.arg(
|
|
|
|
|
escapeApplicationId(this->id()), instanceRandomUUID)); // launcher should use this instanceId
|
|
|
|
|
newCommands.append(task.command);
|
|
|
|
|
|
|
|
|
|
QProcess process;
|
|
|
|
|
qDebug() << "run with commands:" << newCommands;
|
|
|
|
|
qDebug() << "launcher :" << m_launcher << "run with commands:" << newCommands;
|
|
|
|
|
process.start(m_launcher, newCommands);
|
|
|
|
|
process.waitForFinished();
|
|
|
|
|
if (auto code = process.exitCode(); code != 0) {
|
|
|
|
|
qWarning() << "Launch Application Failed";
|
|
|
|
|
return QDBusError::Failed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return objectPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto url = QUrl::fromUserInput(resourceFile);
|
|
|
|
|
if (!url.isValid()) { // if url is invalid, passing to launcher directly
|
|
|
|
|
auto scheme = url.scheme();
|
|
|
|
|
if (!scheme.isEmpty()) {
|
|
|
|
|
// TODO: resourceFile = processRemoteFile(resourceFile);
|
|
|
|
|
auto rawRes = value.toString();
|
|
|
|
|
if (task.argNum != -1) {
|
|
|
|
|
if (task.argNum >= newCommands.size()) {
|
|
|
|
|
qCritical() << "task.argNum >= task.command.size()";
|
|
|
|
|
return QDBusError::Failed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto tmp = task.command;
|
|
|
|
|
if (task.fieldLocation == -1) {
|
|
|
|
|
tmp.insert(task.argNum + 1, rawRes);
|
|
|
|
|
} else {
|
|
|
|
|
auto arg = tmp.at(task.argNum);
|
|
|
|
|
arg.insert(task.fieldLocation, rawRes);
|
|
|
|
|
tmp[task.argNum] = arg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newCommands.append(std::move(tmp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NOTE: resourceFile must be available in the following contexts
|
|
|
|
|
newCommands.insert(location, resourceFile);
|
|
|
|
|
|
|
|
|
|
newCommands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath()));
|
|
|
|
|
newCommands.push_front(QString{R"(--unitName=DDE-%1@%2.service)"}.arg(this->id(), instanceRandomUUID));
|
|
|
|
|
|
|
|
|
|
QProcess process;
|
|
|
|
|
qDebug() << "run with commands:" << newCommands;
|
|
|
|
|
qDebug().noquote() << "launcher :" << m_launcher << "run with commands:" << newCommands;
|
|
|
|
|
process.start(getApplicationLauncherBinary(), newCommands);
|
|
|
|
|
process.waitForFinished();
|
|
|
|
|
auto exitCode = process.exitCode();
|
|
|
|
@ -351,9 +355,10 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
|
|
|
|
|
qWarning() << "Launch Application Failed";
|
|
|
|
|
return QDBusError::Failed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return objectPath;
|
|
|
|
|
},
|
|
|
|
|
std::move(res));
|
|
|
|
|
std::move(task.Resources));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ApplicationService::SendToDesktop() const noexcept
|
|
|
|
@ -957,162 +962,227 @@ std::optional<QStringList> ApplicationService::unescapeExecArgs(const QString &s
|
|
|
|
|
return execList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LaunchTask ApplicationService::unescapeExec(const QString &str, const QStringList &fields) noexcept
|
|
|
|
|
LaunchTask ApplicationService::unescapeExec(const QString &str, QStringList fields) noexcept
|
|
|
|
|
{
|
|
|
|
|
LaunchTask task;
|
|
|
|
|
auto opt = unescapeExecArgs(str);
|
|
|
|
|
auto args = unescapeExecArgs(str);
|
|
|
|
|
|
|
|
|
|
if (!opt.has_value()) {
|
|
|
|
|
if (!args) {
|
|
|
|
|
qWarning() << "unescapeExecArgs failed.";
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto execList = std::move(opt).value();
|
|
|
|
|
if (execList.isEmpty()) {
|
|
|
|
|
if (args->isEmpty()) {
|
|
|
|
|
qWarning() << "exec format is invalid.";
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
task.LaunchBin = execList.first();
|
|
|
|
|
QRegularExpression re{"%[fFuUickdDnNvm]"};
|
|
|
|
|
auto matcher = re.match(str);
|
|
|
|
|
if (!matcher.hasMatch()) {
|
|
|
|
|
task.command.append(std::move(execList));
|
|
|
|
|
task.Resources.emplace_back(QString{""}); // mapReduce should run once at least
|
|
|
|
|
return task;
|
|
|
|
|
}
|
|
|
|
|
auto processUrl = [](const QString &str) {
|
|
|
|
|
auto url = QUrl::fromUserInput(str);
|
|
|
|
|
if (!url.isValid()) {
|
|
|
|
|
qDebug() << "url is invalid, pass to exec directly.";
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto list = matcher.capturedTexts();
|
|
|
|
|
if (list.count() != 1) {
|
|
|
|
|
qWarning() << "invalid exec format, all filed code will be ignored.";
|
|
|
|
|
for (const auto &code : list) {
|
|
|
|
|
execList.removeOne(code);
|
|
|
|
|
if (url.isLocalFile()) {
|
|
|
|
|
return url.toLocalFile();
|
|
|
|
|
}
|
|
|
|
|
task.command.append(std::move(execList));
|
|
|
|
|
return task;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto filesCode = list.first().back().toLatin1();
|
|
|
|
|
auto codeStr = QString(R"(%%1)").arg(filesCode);
|
|
|
|
|
auto location = execList.indexOf(codeStr);
|
|
|
|
|
if (location == -1) {
|
|
|
|
|
qWarning() << "invalid exec format, all filed code will be ignored.";
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
return url.toString();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
switch (filesCode) {
|
|
|
|
|
case 'f': { // Defer to async job
|
|
|
|
|
task.command.append(std::move(execList));
|
|
|
|
|
for (const auto &field : fields) {
|
|
|
|
|
task.Resources.emplace_back(field);
|
|
|
|
|
}
|
|
|
|
|
} break;
|
|
|
|
|
case 'u': {
|
|
|
|
|
execList.removeAt(location);
|
|
|
|
|
if (fields.empty()) {
|
|
|
|
|
task.command.append(execList);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (fields.count() > 1) {
|
|
|
|
|
qDebug() << R"(fields count is greater than one, %u will only take first element.)";
|
|
|
|
|
}
|
|
|
|
|
execList.insert(location, fields.first());
|
|
|
|
|
task.command.append(execList);
|
|
|
|
|
} break;
|
|
|
|
|
case 'F': {
|
|
|
|
|
execList.remove(location);
|
|
|
|
|
auto it = execList.begin() + location;
|
|
|
|
|
for (const auto &field : fields) {
|
|
|
|
|
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);
|
|
|
|
|
task.LaunchBin = args->first();
|
|
|
|
|
const QChar percentage{'%'};
|
|
|
|
|
bool exclusiveField{false};
|
|
|
|
|
|
|
|
|
|
for (auto arg = args->begin(); arg != args->end(); ++arg) {
|
|
|
|
|
QString newArg;
|
|
|
|
|
|
|
|
|
|
for (const auto *it = arg->cbegin(); it != arg->cend();) {
|
|
|
|
|
if (*it != percentage) {
|
|
|
|
|
newArg.append(*(it++));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
++it;
|
|
|
|
|
}
|
|
|
|
|
task.command.append(std::move(execList));
|
|
|
|
|
} break;
|
|
|
|
|
case 'U': {
|
|
|
|
|
execList.removeAt(location);
|
|
|
|
|
auto it = execList.begin() + location;
|
|
|
|
|
for (const auto &field : fields) {
|
|
|
|
|
it = execList.insert(it, field);
|
|
|
|
|
++it;
|
|
|
|
|
}
|
|
|
|
|
task.command.append(std::move(execList));
|
|
|
|
|
} break;
|
|
|
|
|
case 'i': {
|
|
|
|
|
execList.removeAt(location);
|
|
|
|
|
auto val = m_entry->value(DesktopFileEntryKey, "Icon");
|
|
|
|
|
if (!val) {
|
|
|
|
|
qDebug() << R"(Application Icons can't be found. %i will be ignored.)";
|
|
|
|
|
task.command.append(std::move(execList));
|
|
|
|
|
return task;
|
|
|
|
|
|
|
|
|
|
const auto *code = it + 1;
|
|
|
|
|
if (code == arg->cend()) {
|
|
|
|
|
qWarning() << R"(content of exec is invalid, a unterminated % is detected.)";
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*code == percentage) {
|
|
|
|
|
newArg.append(percentage);
|
|
|
|
|
it += 2;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (auto c = code->toLatin1(); c) {
|
|
|
|
|
case 'f':
|
|
|
|
|
[[fallthrough]];
|
|
|
|
|
case 'F': { // Defer to async job
|
|
|
|
|
if (exclusiveField) {
|
|
|
|
|
qDebug() << QString{"exclusive field is detected again, %%1 will be ignored."}.arg(c);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
exclusiveField = true;
|
|
|
|
|
|
|
|
|
|
if (fields.empty()) {
|
|
|
|
|
qDebug() << QString{"fields is empty, %%1 will be ignored."}.arg(c);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (c == 'F') {
|
|
|
|
|
task.Resources.emplace_back(fields.join(' '));
|
|
|
|
|
} else {
|
|
|
|
|
std::for_each(
|
|
|
|
|
fields.begin(), fields.end(), [&task](QString &str) { task.Resources.emplace_back(std::move(str)); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
task.argNum = std::distance(args->begin(), arg) - 1;
|
|
|
|
|
task.fieldLocation = std::distance(arg->cbegin(), it) - 1;
|
|
|
|
|
} break;
|
|
|
|
|
case 'u':
|
|
|
|
|
case 'U': {
|
|
|
|
|
if (exclusiveField) {
|
|
|
|
|
qDebug() << QString{"exclusive field is detected again, %%1 will be ignored."}.arg(c);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
exclusiveField = true;
|
|
|
|
|
|
|
|
|
|
if (fields.empty()) {
|
|
|
|
|
qDebug() << QString{"fields is empty, %%1 will be ignored."}.arg(c);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList urls;
|
|
|
|
|
std::transform(fields.cbegin(), fields.cend(), std::back_inserter(urls), processUrl);
|
|
|
|
|
fields.clear();
|
|
|
|
|
|
|
|
|
|
if (c == 'U') {
|
|
|
|
|
task.Resources.emplace_back(urls.join(' '));
|
|
|
|
|
} else {
|
|
|
|
|
std::for_each(
|
|
|
|
|
urls.begin(), urls.end(), [&task](QString &url) { task.Resources.emplace_back(std::move(url)); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
task.argNum = std::distance(args->begin(), arg) - 1;
|
|
|
|
|
task.fieldLocation = std::distance(arg->cbegin(), it) - 1;
|
|
|
|
|
} break;
|
|
|
|
|
case 'i': {
|
|
|
|
|
auto val = m_entry->value(DesktopFileEntryKey, "Icon");
|
|
|
|
|
if (!val) {
|
|
|
|
|
qDebug() << R"(Application Icons can't be found. %i will be ignored.)";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto iconStr = toIconString(val.value());
|
|
|
|
|
if (iconStr.isEmpty()) {
|
|
|
|
|
qDebug() << R"(Icons Convert to string failed. %i will be ignored.)";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// split at the end of loop
|
|
|
|
|
newArg.append(QString{"--icon %1"}.arg(iconStr));
|
|
|
|
|
} break;
|
|
|
|
|
case 'c': {
|
|
|
|
|
auto val = m_entry->value(DesktopFileEntryKey, "Name");
|
|
|
|
|
if (!val) {
|
|
|
|
|
qDebug() << R"(Application Name can't be found. %c will be ignored.)";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto &rawValue = val.value();
|
|
|
|
|
if (!rawValue.canConvert<QStringMap>()) {
|
|
|
|
|
qDebug() << "Name's underlying type mismatch:" << "QStringMap" << rawValue.metaType().name();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto NameStr = toLocaleString(rawValue.value<QStringMap>(), getUserLocale());
|
|
|
|
|
if (NameStr.isEmpty()) {
|
|
|
|
|
qDebug() << R"(Name Convert to locale string failed. %c will be ignored.)";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newArg.append(NameStr);
|
|
|
|
|
} break;
|
|
|
|
|
case 'k': { // ignore all desktop file location for now.
|
|
|
|
|
newArg.append(m_desktopSource.sourcePath());
|
|
|
|
|
} break;
|
|
|
|
|
case 'd':
|
|
|
|
|
case 'D':
|
|
|
|
|
case 'n':
|
|
|
|
|
case 'N':
|
|
|
|
|
case 'v':
|
|
|
|
|
[[fallthrough]]; // Deprecated field codes should be removed from the command line and ignored.
|
|
|
|
|
case 'm': {
|
|
|
|
|
qDebug() << "field code" << *code << "has been deprecated.";
|
|
|
|
|
} break;
|
|
|
|
|
default: {
|
|
|
|
|
qDebug() << "unknown field code:" << *code << ", ignore it.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
it += 2; // skip filed code
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto iconStr = toIconString(val.value());
|
|
|
|
|
if (iconStr.isEmpty()) {
|
|
|
|
|
qDebug() << R"(Icons Convert to string failed. %i will be ignored.)";
|
|
|
|
|
task.command.append(std::move(execList));
|
|
|
|
|
return task;
|
|
|
|
|
auto newArgList = newArg.split(' ', Qt::SkipEmptyParts);
|
|
|
|
|
if (!newArgList.isEmpty()) {
|
|
|
|
|
task.command.append(std::move(newArgList));
|
|
|
|
|
}
|
|
|
|
|
auto it = execList.insert(location, iconStr);
|
|
|
|
|
execList.insert(it, "--icon");
|
|
|
|
|
task.command.append(std::move(execList));
|
|
|
|
|
} break;
|
|
|
|
|
case 'c': {
|
|
|
|
|
execList.removeAt(location);
|
|
|
|
|
auto val = m_entry->value(DesktopFileEntryKey, "Name");
|
|
|
|
|
if (!val) {
|
|
|
|
|
qDebug() << R"(Application Name can't be found. %c will be ignored.)";
|
|
|
|
|
task.command.append(std::move(execList));
|
|
|
|
|
return task;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto &rawValue = val.value();
|
|
|
|
|
if (!rawValue.canConvert<QStringMap>()) {
|
|
|
|
|
qDebug() << "Name's underlying type mismatch:" << "QStringMap" << rawValue.metaType().name();
|
|
|
|
|
task.command.append(std::move(execList));
|
|
|
|
|
return task;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto NameStr = toLocaleString(rawValue.value<QStringMap>(), getUserLocale());
|
|
|
|
|
if (NameStr.isEmpty()) {
|
|
|
|
|
qDebug() << R"(Name Convert to locale string failed. %c will be ignored.)";
|
|
|
|
|
task.command.append(std::move(execList));
|
|
|
|
|
return task;
|
|
|
|
|
}
|
|
|
|
|
execList.insert(location, NameStr);
|
|
|
|
|
task.command.append(std::move(execList));
|
|
|
|
|
} break;
|
|
|
|
|
case 'k': { // ignore all desktop file location for now.
|
|
|
|
|
execList.removeAt(location);
|
|
|
|
|
task.command.append(std::move(execList));
|
|
|
|
|
} break;
|
|
|
|
|
case 'd':
|
|
|
|
|
case 'D':
|
|
|
|
|
case 'n':
|
|
|
|
|
case 'N':
|
|
|
|
|
case 'v':
|
|
|
|
|
[[fallthrough]]; // Deprecated field codes should be removed from the command line and ignored.
|
|
|
|
|
case 'm': {
|
|
|
|
|
execList.removeAt(location);
|
|
|
|
|
task.command.append(std::move(execList));
|
|
|
|
|
} break;
|
|
|
|
|
default: {
|
|
|
|
|
qDebug() << "unrecognized file code.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (task.Resources.isEmpty()) {
|
|
|
|
|
task.Resources.emplace_back(QString{""}); // mapReduce should run once at least
|
|
|
|
|
task.Resources.emplace_back(QVariant{}); // mapReduce should run once at least
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qInfo() << "after unescape exec:" << task.LaunchBin << task.command << task.Resources;
|
|
|
|
|
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,
|
|
|
|
|
const QString &valueKey,
|
|
|
|
|
EntryValueType type,
|
|
|
|
|