core/qmlglobal: add execDetached functions for spawning processes

This commit is contained in:
outfoxxed 2025-06-15 00:07:01 -07:00
parent 0140356d99
commit 0499518143
Signed by untrusted user: outfoxxed
GPG key ID: 4C88A185FB89301E
10 changed files with 167 additions and 30 deletions

View file

@ -1,5 +1,6 @@
qt_add_library(quickshell-io STATIC
datastream.cpp
processcore.cpp
process.cpp
fileview.cpp
jsonadapter.cpp

View file

@ -3,9 +3,9 @@
#include <utility>
#include <qdir.h>
#include <qhash.h>
#include <qlist.h>
#include <qlogging.h>
#include <qmap.h>
#include <qobject.h>
#include <qprocess.h>
#include <qqmlinfo.h>
@ -13,10 +13,10 @@
#include <qtypes.h>
#include <qvariant.h>
#include "../core/common.hpp"
#include "../core/generation.hpp"
#include "../core/qmlglobal.hpp"
#include "datastream.hpp"
#include "processcore.hpp"
Process::Process(QObject* parent): QObject(parent) {
QObject::connect(
@ -79,9 +79,10 @@ void Process::onGlobalWorkingDirectoryChanged() {
}
}
QMap<QString, QVariant> Process::environment() const { return this->mEnvironment; }
QHash<QString, QVariant> Process::environment() const { return this->mEnvironment; }
void Process::setEnvironment(QMap<QString, QVariant> environment) {
void Process::setEnvironment(QHash<QString, QVariant> environment) {
qDebug() << "setEnv" << environment;
if (environment == this->mEnvironment) return;
this->mEnvironment = std::move(environment);
emit this->environmentChanged();
@ -224,24 +225,7 @@ void Process::setupEnvironment(QProcess* process) {
process->setWorkingDirectory(this->mWorkingDirectory);
}
const auto& sysenv = qs::Common::INITIAL_ENVIRONMENT;
auto env = this->mClearEnvironment ? QProcessEnvironment() : sysenv;
for (auto& name: this->mEnvironment.keys()) {
auto value = this->mEnvironment.value(name);
if (!value.isValid()) continue;
if (this->mClearEnvironment) {
if (value.isNull()) {
if (sysenv.contains(name)) env.insert(name, sysenv.value(name));
} else env.insert(name, value.toString());
} else {
if (value.isNull()) env.remove(name);
else env.insert(name, value.toString());
}
}
process->setProcessEnvironment(env);
qs::core::process::setupProcessEnvironment(process, this->mClearEnvironment, this->mEnvironment);
}
void Process::onStarted() {

View file

@ -1,6 +1,7 @@
#pragma once
#include <qcontainerfwd.h>
#include <qhash.h>
#include <qobject.h>
#include <qprocess.h>
#include <qqmlintegration.h>
@ -98,7 +99,7 @@ class Process: public QObject {
/// If the process is already running changing this property will affect the next
/// started process. If the property has been changed after starting a process it will
/// return the new value, not the one for the currently running process.
Q_PROPERTY(QMap<QString, QVariant> environment READ environment WRITE setEnvironment NOTIFY environmentChanged);
Q_PROPERTY(QHash<QString, QVariant> environment READ environment WRITE setEnvironment NOTIFY environmentChanged);
/// If the process's environment should be cleared prior to applying @@environment.
/// Defaults to false.
///
@ -140,10 +141,12 @@ public:
/// Writes to the process's stdin. Does nothing if @@running is false.
Q_INVOKABLE void write(const QString& data);
/// Launches an instance of the process detached from quickshell.
/// Launches an instance of the process detached from Quickshell.
///
/// The subprocess will not be tracked, @@running will be false,
/// and the subprocess will not be killed by Quickshell.
///
/// This function is equivalent to @@Quickshell.Quickshell.execDetached().
Q_INVOKABLE void startDetached();
[[nodiscard]] bool isRunning() const;
@ -157,8 +160,8 @@ public:
[[nodiscard]] QString workingDirectory() const;
void setWorkingDirectory(const QString& workingDirectory);
[[nodiscard]] QMap<QString, QVariant> environment() const;
void setEnvironment(QMap<QString, QVariant> environment);
[[nodiscard]] QHash<QString, QVariant> environment() const;
void setEnvironment(QHash<QString, QVariant> environment);
[[nodiscard]] bool environmentCleared() const;
void setEnvironmentCleared(bool cleared);
@ -203,7 +206,7 @@ private:
QProcess* process = nullptr;
QList<QString> mCommand;
QString mWorkingDirectory;
QMap<QString, QVariant> mEnvironment;
QHash<QString, QVariant> mEnvironment;
DataStreamParser* mStdoutParser = nullptr;
DataStreamParser* mStderrParser = nullptr;
QByteArray stdoutBuffer;

37
src/io/processcore.cpp Normal file
View file

@ -0,0 +1,37 @@
#include "processcore.hpp"
#include <qcontainerfwd.h>
#include <qhash.h>
#include <qprocess.h>
#include <qvariant.h>
#include "../core/common.hpp"
namespace qs::core::process {
void setupProcessEnvironment(
QProcess* process,
bool clear,
const QHash<QString, QVariant>& envChanges
) {
const auto& sysenv = qs::Common::INITIAL_ENVIRONMENT;
auto env = clear ? QProcessEnvironment() : sysenv;
for (auto& name: envChanges.keys()) {
auto value = envChanges.value(name);
if (!value.isValid()) continue;
if (clear) {
if (value.isNull()) {
if (sysenv.contains(name)) env.insert(name, sysenv.value(name));
} else env.insert(name, value.toString());
} else {
if (value.isNull()) env.remove(name);
else env.insert(name, value.toString());
}
}
process->setProcessEnvironment(env);
}
} // namespace qs::core::process

16
src/io/processcore.hpp Normal file
View file

@ -0,0 +1,16 @@
#pragma once
#include <qcontainerfwd.h>
#include <qhash.h>
#include <qprocess.h>
#include <qvariant.h>
namespace qs::core::process {
void setupProcessEnvironment(
QProcess* process,
bool clear,
const QHash<QString, QVariant>& envChanges
);
}

View file

@ -1,6 +1,6 @@
function (qs_test name)
add_executable(${name} ${ARGN})
target_link_libraries(${name} PRIVATE Qt::Quick Qt::Network Qt::Test)
target_link_libraries(${name} PRIVATE Qt::Quick Qt::Network Qt::Test quickshell-io)
add_test(NAME ${name} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMAND $<TARGET_FILE:${name}>)
endfunction()