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 <qdatetime.h>
 | 
			
		||||
#include <qprocess.h>
 | 
			
		||||
 | 
			
		||||
namespace qs {
 | 
			
		||||
 | 
			
		||||
const QDateTime Common::LAUNCH_TIME = QDateTime::currentDateTime();
 | 
			
		||||
QProcessEnvironment Common::INITIAL_ENVIRONMENT = {}; // NOLINT
 | 
			
		||||
 | 
			
		||||
} // namespace qs
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ namespace qs {
 | 
			
		|||
 | 
			
		||||
struct Common {
 | 
			
		||||
	static const QDateTime LAUNCH_TIME;
 | 
			
		||||
	static QProcessEnvironment INITIAL_ENVIRONMENT; // NOLINT
 | 
			
		||||
	static inline QProcessEnvironment INITIAL_ENVIRONMENT = {}; // NOLINT
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace qs
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,14 +11,14 @@
 | 
			
		|||
#include <qnamespace.h>
 | 
			
		||||
#include <qobject.h>
 | 
			
		||||
#include <qpair.h>
 | 
			
		||||
#include <qprocess.h>
 | 
			
		||||
#include <qstringview.h>
 | 
			
		||||
#include <qtenvironmentvariables.h>
 | 
			
		||||
#include <ranges>
 | 
			
		||||
 | 
			
		||||
#include "common.hpp"
 | 
			
		||||
#include "../io/processcore.hpp"
 | 
			
		||||
#include "logcat.hpp"
 | 
			
		||||
#include "model.hpp"
 | 
			
		||||
#include "qmlglobal.hpp"
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
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 == "Comment") this->mComment = value;
 | 
			
		||||
				else if (key == "Icon") this->mIcon = value;
 | 
			
		||||
				else if (key == "Exec") this->mExecString = value;
 | 
			
		||||
				else if (key == "Path") this->mWorkingDirectory = value;
 | 
			
		||||
				else if (key == "Exec") {
 | 
			
		||||
					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 == "Categories") this->mCategories = 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;
 | 
			
		||||
				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);
 | 
			
		||||
| 
						 | 
				
			
			@ -179,7 +184,7 @@ void DesktopEntry::parseEntry(const QString& text) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void DesktopEntry::execute() const {
 | 
			
		||||
	DesktopEntry::doExec(this->mExecString, this->mWorkingDirectory);
 | 
			
		||||
	DesktopEntry::doExec(this->mCommand, this->mWorkingDirectory);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DesktopEntry::isValid() const { return !this->mName.isEmpty(); }
 | 
			
		||||
| 
						 | 
				
			
			@ -251,23 +256,15 @@ QVector<QString> DesktopEntry::parseExecString(const QString& execString) {
 | 
			
		|||
	return arguments;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DesktopEntry::doExec(const QString& execString, const QString& workingDirectory) {
 | 
			
		||||
	auto args = DesktopEntry::parseExecString(execString);
 | 
			
		||||
	if (args.isEmpty()) {
 | 
			
		||||
		qCWarning(logDesktopEntry) << "Tried to exec string" << execString << "which parsed as empty.";
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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 DesktopEntry::doExec(const QList<QString>& execString, const QString& workingDirectory) {
 | 
			
		||||
	qs::io::process::ProcessContext ctx;
 | 
			
		||||
	ctx.setCommand(execString);
 | 
			
		||||
	ctx.setWorkingDirectory(workingDirectory);
 | 
			
		||||
	QuickshellGlobal::execDetached(ctx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DesktopAction::execute() const {
 | 
			
		||||
	DesktopEntry::doExec(this->mExecString, this->entry->mWorkingDirectory);
 | 
			
		||||
	DesktopEntry::doExec(this->mCommand, this->entry->mWorkingDirectory);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DesktopEntryManager::DesktopEntryManager() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,8 +28,19 @@ class DesktopEntry: public QObject {
 | 
			
		|||
	Q_PROPERTY(QString comment MEMBER mComment CONSTANT);
 | 
			
		||||
	/// Name of the icon associated with this application. May be empty.
 | 
			
		||||
	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);
 | 
			
		||||
	/// 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.
 | 
			
		||||
	Q_PROPERTY(QString workingDirectory MEMBER mWorkingDirectory CONSTANT);
 | 
			
		||||
	/// If the application should run in a terminal.
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +57,16 @@ public:
 | 
			
		|||
	void parseEntry(const QString& text);
 | 
			
		||||
 | 
			
		||||
	/// 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;
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] bool isValid() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +75,7 @@ public:
 | 
			
		|||
 | 
			
		||||
	// currently ignores all field codes.
 | 
			
		||||
	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:
 | 
			
		||||
	QString mId;
 | 
			
		||||
| 
						 | 
				
			
			@ -64,6 +85,7 @@ public:
 | 
			
		|||
	QString mComment;
 | 
			
		||||
	QString mIcon;
 | 
			
		||||
	QString mExecString;
 | 
			
		||||
	QVector<QString> mCommand;
 | 
			
		||||
	QString mWorkingDirectory;
 | 
			
		||||
	bool mTerminal = false;
 | 
			
		||||
	QVector<QString> mCategories;
 | 
			
		||||
| 
						 | 
				
			
			@ -82,8 +104,19 @@ class DesktopAction: public QObject {
 | 
			
		|||
	Q_PROPERTY(QString id MEMBER mId CONSTANT);
 | 
			
		||||
	Q_PROPERTY(QString name MEMBER mName 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);
 | 
			
		||||
	/// 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_UNCREATABLE("DesktopAction instances must be retrieved from a DesktopEntry");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -94,6 +127,9 @@ public:
 | 
			
		|||
	    , mId(std::move(id)) {}
 | 
			
		||||
 | 
			
		||||
	/// 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;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
| 
						 | 
				
			
			@ -102,6 +138,7 @@ private:
 | 
			
		|||
	QString mName;
 | 
			
		||||
	QString mIcon;
 | 
			
		||||
	QString mExecString;
 | 
			
		||||
	QVector<QString> mCommand;
 | 
			
		||||
	QHash<QString, QString> mEntries;
 | 
			
		||||
 | 
			
		||||
	friend class DesktopEntry;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue