forked from quickshell/quickshell
core/desktopentry: expose exec command and use execDetached on call
This commit is contained in:
parent
de25787451
commit
71334bfcaf
4 changed files with 58 additions and 26 deletions
|
@ -1,11 +1,9 @@
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
|
||||||
#include <qdatetime.h>
|
#include <qdatetime.h>
|
||||||
#include <qprocess.h>
|
|
||||||
|
|
||||||
namespace qs {
|
namespace qs {
|
||||||
|
|
||||||
const QDateTime Common::LAUNCH_TIME = QDateTime::currentDateTime();
|
const QDateTime Common::LAUNCH_TIME = QDateTime::currentDateTime();
|
||||||
QProcessEnvironment Common::INITIAL_ENVIRONMENT = {}; // NOLINT
|
|
||||||
|
|
||||||
} // namespace qs
|
} // namespace qs
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace qs {
|
||||||
|
|
||||||
struct Common {
|
struct Common {
|
||||||
static const QDateTime LAUNCH_TIME;
|
static const QDateTime LAUNCH_TIME;
|
||||||
static QProcessEnvironment INITIAL_ENVIRONMENT; // NOLINT
|
static inline QProcessEnvironment INITIAL_ENVIRONMENT = {}; // NOLINT
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace qs
|
} // namespace qs
|
||||||
|
|
|
@ -11,14 +11,14 @@
|
||||||
#include <qnamespace.h>
|
#include <qnamespace.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qpair.h>
|
#include <qpair.h>
|
||||||
#include <qprocess.h>
|
|
||||||
#include <qstringview.h>
|
#include <qstringview.h>
|
||||||
#include <qtenvironmentvariables.h>
|
#include <qtenvironmentvariables.h>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "../io/processcore.hpp"
|
||||||
#include "logcat.hpp"
|
#include "logcat.hpp"
|
||||||
#include "model.hpp"
|
#include "model.hpp"
|
||||||
|
#include "qmlglobal.hpp"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
QS_LOGGING_CATEGORY(logDesktopEntry, "quickshell.desktopentry", QtWarningMsg);
|
QS_LOGGING_CATEGORY(logDesktopEntry, "quickshell.desktopentry", QtWarningMsg);
|
||||||
|
@ -111,8 +111,10 @@ void DesktopEntry::parseEntry(const QString& text) {
|
||||||
else if (key == "NoDisplay") this->mNoDisplay = value == "true";
|
else if (key == "NoDisplay") this->mNoDisplay = value == "true";
|
||||||
else if (key == "Comment") this->mComment = value;
|
else if (key == "Comment") this->mComment = value;
|
||||||
else if (key == "Icon") this->mIcon = value;
|
else if (key == "Icon") this->mIcon = value;
|
||||||
else if (key == "Exec") this->mExecString = value;
|
else if (key == "Exec") {
|
||||||
else if (key == "Path") this->mWorkingDirectory = value;
|
this->mExecString = value;
|
||||||
|
this->mCommand = DesktopEntry::parseExecString(value);
|
||||||
|
} else if (key == "Path") this->mWorkingDirectory = value;
|
||||||
else if (key == "Terminal") this->mTerminal = value == "true";
|
else if (key == "Terminal") this->mTerminal = value == "true";
|
||||||
else if (key == "Categories") this->mCategories = value.split(u';', Qt::SkipEmptyParts);
|
else if (key == "Categories") this->mCategories = value.split(u';', Qt::SkipEmptyParts);
|
||||||
else if (key == "Keywords") this->mKeywords = value.split(u';', Qt::SkipEmptyParts);
|
else if (key == "Keywords") this->mKeywords = value.split(u';', Qt::SkipEmptyParts);
|
||||||
|
@ -127,7 +129,10 @@ void DesktopEntry::parseEntry(const QString& text) {
|
||||||
|
|
||||||
if (key == "Name") action->mName = value;
|
if (key == "Name") action->mName = value;
|
||||||
else if (key == "Icon") action->mIcon = value;
|
else if (key == "Icon") action->mIcon = value;
|
||||||
else if (key == "Exec") action->mExecString = value;
|
else if (key == "Exec") {
|
||||||
|
action->mExecString = value;
|
||||||
|
action->mCommand = DesktopEntry::parseExecString(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->mActions.insert(actionName, action);
|
this->mActions.insert(actionName, action);
|
||||||
|
@ -179,7 +184,7 @@ void DesktopEntry::parseEntry(const QString& text) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopEntry::execute() const {
|
void DesktopEntry::execute() const {
|
||||||
DesktopEntry::doExec(this->mExecString, this->mWorkingDirectory);
|
DesktopEntry::doExec(this->mCommand, this->mWorkingDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DesktopEntry::isValid() const { return !this->mName.isEmpty(); }
|
bool DesktopEntry::isValid() const { return !this->mName.isEmpty(); }
|
||||||
|
@ -251,23 +256,15 @@ QVector<QString> DesktopEntry::parseExecString(const QString& execString) {
|
||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopEntry::doExec(const QString& execString, const QString& workingDirectory) {
|
void DesktopEntry::doExec(const QList<QString>& execString, const QString& workingDirectory) {
|
||||||
auto args = DesktopEntry::parseExecString(execString);
|
qs::io::process::ProcessContext ctx;
|
||||||
if (args.isEmpty()) {
|
ctx.setCommand(execString);
|
||||||
qCWarning(logDesktopEntry) << "Tried to exec string" << execString << "which parsed as empty.";
|
ctx.setWorkingDirectory(workingDirectory);
|
||||||
return;
|
QuickshellGlobal::execDetached(ctx);
|
||||||
}
|
|
||||||
|
|
||||||
auto process = QProcess();
|
|
||||||
process.setProgram(args.at(0));
|
|
||||||
process.setArguments(args.sliced(1));
|
|
||||||
if (!workingDirectory.isEmpty()) process.setWorkingDirectory(workingDirectory);
|
|
||||||
process.setProcessEnvironment(qs::Common::INITIAL_ENVIRONMENT);
|
|
||||||
process.startDetached();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopAction::execute() const {
|
void DesktopAction::execute() const {
|
||||||
DesktopEntry::doExec(this->mExecString, this->entry->mWorkingDirectory);
|
DesktopEntry::doExec(this->mCommand, this->entry->mWorkingDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopEntryManager::DesktopEntryManager() {
|
DesktopEntryManager::DesktopEntryManager() {
|
||||||
|
|
|
@ -28,8 +28,19 @@ class DesktopEntry: public QObject {
|
||||||
Q_PROPERTY(QString comment MEMBER mComment CONSTANT);
|
Q_PROPERTY(QString comment MEMBER mComment CONSTANT);
|
||||||
/// Name of the icon associated with this application. May be empty.
|
/// Name of the icon associated with this application. May be empty.
|
||||||
Q_PROPERTY(QString icon MEMBER mIcon CONSTANT);
|
Q_PROPERTY(QString icon MEMBER mIcon CONSTANT);
|
||||||
/// The raw `Exec` string from the desktop entry. You probably want @@execute().
|
/// The raw `Exec` string from the desktop entry.
|
||||||
|
///
|
||||||
|
/// > [!WARNING] This cannot be reliably run as a command. See @@command for one you can run.
|
||||||
Q_PROPERTY(QString execString MEMBER mExecString CONSTANT);
|
Q_PROPERTY(QString execString MEMBER mExecString CONSTANT);
|
||||||
|
/// The parsed `Exec` command in the desktop entry.
|
||||||
|
///
|
||||||
|
/// The entry can be run with @@execute(), or by using this command in
|
||||||
|
/// @@Quickshell.Quickshell.execDetached() or @@Quickshell.Io.Process.
|
||||||
|
/// If used in `execDetached` or a `Process`, @@workingDirectory should also be passed to
|
||||||
|
/// the invoked process. See @@execute() for details.
|
||||||
|
///
|
||||||
|
/// > [!NOTE] The provided command does not invoke a terminal even if @@runInTerminal is true.
|
||||||
|
Q_PROPERTY(QVector<QString> command MEMBER mCommand CONSTANT);
|
||||||
/// The working directory to execute from.
|
/// The working directory to execute from.
|
||||||
Q_PROPERTY(QString workingDirectory MEMBER mWorkingDirectory CONSTANT);
|
Q_PROPERTY(QString workingDirectory MEMBER mWorkingDirectory CONSTANT);
|
||||||
/// If the application should run in a terminal.
|
/// If the application should run in a terminal.
|
||||||
|
@ -46,6 +57,16 @@ public:
|
||||||
void parseEntry(const QString& text);
|
void parseEntry(const QString& text);
|
||||||
|
|
||||||
/// Run the application. Currently ignores @@runInTerminal and field codes.
|
/// Run the application. Currently ignores @@runInTerminal and field codes.
|
||||||
|
///
|
||||||
|
/// This is equivalent to calling @@Quickshell.Quickshell.execDetached() with @@command
|
||||||
|
/// and @@DesktopEntry.workingDirectory as shown below:
|
||||||
|
///
|
||||||
|
/// ```qml
|
||||||
|
/// Quickshell.execDetached({
|
||||||
|
/// command: desktopEntry.command,
|
||||||
|
/// workingDirectory: desktopEntry.workingDirectory,
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
Q_INVOKABLE void execute() const;
|
Q_INVOKABLE void execute() const;
|
||||||
|
|
||||||
[[nodiscard]] bool isValid() const;
|
[[nodiscard]] bool isValid() const;
|
||||||
|
@ -54,7 +75,7 @@ public:
|
||||||
|
|
||||||
// currently ignores all field codes.
|
// currently ignores all field codes.
|
||||||
static QVector<QString> parseExecString(const QString& execString);
|
static QVector<QString> parseExecString(const QString& execString);
|
||||||
static void doExec(const QString& execString, const QString& workingDirectory);
|
static void doExec(const QList<QString>& execString, const QString& workingDirectory);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QString mId;
|
QString mId;
|
||||||
|
@ -64,6 +85,7 @@ public:
|
||||||
QString mComment;
|
QString mComment;
|
||||||
QString mIcon;
|
QString mIcon;
|
||||||
QString mExecString;
|
QString mExecString;
|
||||||
|
QVector<QString> mCommand;
|
||||||
QString mWorkingDirectory;
|
QString mWorkingDirectory;
|
||||||
bool mTerminal = false;
|
bool mTerminal = false;
|
||||||
QVector<QString> mCategories;
|
QVector<QString> mCategories;
|
||||||
|
@ -82,8 +104,19 @@ class DesktopAction: public QObject {
|
||||||
Q_PROPERTY(QString id MEMBER mId CONSTANT);
|
Q_PROPERTY(QString id MEMBER mId CONSTANT);
|
||||||
Q_PROPERTY(QString name MEMBER mName CONSTANT);
|
Q_PROPERTY(QString name MEMBER mName CONSTANT);
|
||||||
Q_PROPERTY(QString icon MEMBER mIcon CONSTANT);
|
Q_PROPERTY(QString icon MEMBER mIcon CONSTANT);
|
||||||
/// The raw `Exec` string from the desktop entry. You probably want @@execute().
|
/// The raw `Exec` string from the action.
|
||||||
|
///
|
||||||
|
/// > [!WARNING] This cannot be reliably run as a command. See @@command for one you can run.
|
||||||
Q_PROPERTY(QString execString MEMBER mExecString CONSTANT);
|
Q_PROPERTY(QString execString MEMBER mExecString CONSTANT);
|
||||||
|
/// The parsed `Exec` command in the action.
|
||||||
|
///
|
||||||
|
/// The entry can be run with @@execute(), or by using this command in
|
||||||
|
/// @@Quickshell.Quickshell.execDetached() or @@Quickshell.Io.Process.
|
||||||
|
/// If used in `execDetached` or a `Process`, @@DesktopEntry.workingDirectory should also be passed to
|
||||||
|
/// the invoked process.
|
||||||
|
///
|
||||||
|
/// > [!NOTE] The provided command does not invoke a terminal even if @@runInTerminal is true.
|
||||||
|
Q_PROPERTY(QVector<QString> command MEMBER mCommand CONSTANT);
|
||||||
QML_ELEMENT;
|
QML_ELEMENT;
|
||||||
QML_UNCREATABLE("DesktopAction instances must be retrieved from a DesktopEntry");
|
QML_UNCREATABLE("DesktopAction instances must be retrieved from a DesktopEntry");
|
||||||
|
|
||||||
|
@ -94,6 +127,9 @@ public:
|
||||||
, mId(std::move(id)) {}
|
, mId(std::move(id)) {}
|
||||||
|
|
||||||
/// Run the application. Currently ignores @@DesktopEntry.runInTerminal and field codes.
|
/// Run the application. Currently ignores @@DesktopEntry.runInTerminal and field codes.
|
||||||
|
///
|
||||||
|
/// This is equivalent to calling @@Quickshell.Quickshell.execDetached() with @@command
|
||||||
|
/// and @@DesktopEntry.workingDirectory.
|
||||||
Q_INVOKABLE void execute() const;
|
Q_INVOKABLE void execute() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -102,6 +138,7 @@ private:
|
||||||
QString mName;
|
QString mName;
|
||||||
QString mIcon;
|
QString mIcon;
|
||||||
QString mExecString;
|
QString mExecString;
|
||||||
|
QVector<QString> mCommand;
|
||||||
QHash<QString, QString> mEntries;
|
QHash<QString, QString> mEntries;
|
||||||
|
|
||||||
friend class DesktopEntry;
|
friend class DesktopEntry;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue