forked from quickshell/quickshell
io/process!: replace manageLifetime with startDetached
In most cases this is what was desired for usages of manageLifetime. Starting the process in a detached state also makes sure the process hierarchy will not result in the child being killed when Quickshell is killed.
This commit is contained in:
parent
c5bea858a0
commit
0662c37d67
5 changed files with 37 additions and 76 deletions
|
@ -7,8 +7,6 @@ qt_add_library(quickshell-io STATIC
|
||||||
ipchandler.cpp
|
ipchandler.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(quickshell-io-init OBJECT init.cpp)
|
|
||||||
|
|
||||||
if (SOCKETS)
|
if (SOCKETS)
|
||||||
target_sources(quickshell-io PRIVATE socket.cpp)
|
target_sources(quickshell-io PRIVATE socket.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
@ -24,9 +22,7 @@ qt_add_qml_module(quickshell-io
|
||||||
install_qml_module(quickshell-io)
|
install_qml_module(quickshell-io)
|
||||||
|
|
||||||
target_link_libraries(quickshell-io PRIVATE Qt::Quick)
|
target_link_libraries(quickshell-io PRIVATE Qt::Quick)
|
||||||
target_link_libraries(quickshell-io-init PRIVATE Qt::Qml)
|
target_link_libraries(quickshell PRIVATE quickshell-ioplugin)
|
||||||
|
|
||||||
target_link_libraries(quickshell PRIVATE quickshell-ioplugin quickshell-io-init)
|
|
||||||
|
|
||||||
qs_module_pch(quickshell-io)
|
qs_module_pch(quickshell-io)
|
||||||
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
#include "../core/plugin.hpp"
|
|
||||||
#include "process.hpp"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class IoPlugin: public QsEnginePlugin {
|
|
||||||
void onReload() override { DisownedProcessContext::destroyInstance(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
QS_REGISTER_PLUGIN(IoPlugin);
|
|
||||||
|
|
||||||
} // namespace
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <qmap.h>
|
#include <qmap.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qprocess.h>
|
#include <qprocess.h>
|
||||||
|
#include <qqmlinfo.h>
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
#include <qtypes.h>
|
#include <qtypes.h>
|
||||||
#include <qvariant.h>
|
#include <qvariant.h>
|
||||||
|
@ -16,10 +17,6 @@
|
||||||
#include "../core/qmlglobal.hpp"
|
#include "../core/qmlglobal.hpp"
|
||||||
#include "datastream.hpp"
|
#include "datastream.hpp"
|
||||||
|
|
||||||
// When the process ends this have no parent and is just leaked,
|
|
||||||
// meaning the destructor never runs and they are never killed.
|
|
||||||
static DisownedProcessContext* disownedCtx; // NOLINT
|
|
||||||
|
|
||||||
Process::Process(QObject* parent): QObject(parent) {
|
Process::Process(QObject* parent): QObject(parent) {
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
QuickshellSettings::instance(),
|
QuickshellSettings::instance(),
|
||||||
|
@ -29,13 +26,6 @@ Process::Process(QObject* parent): QObject(parent) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Process::~Process() {
|
|
||||||
if (!this->mLifetimeManaged && this->process != nullptr) {
|
|
||||||
if (disownedCtx == nullptr) disownedCtx = new DisownedProcessContext(); // NOLINT
|
|
||||||
disownedCtx->reparent(this->process);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Process::isRunning() const { return this->process != nullptr; }
|
bool Process::isRunning() const { return this->process != nullptr; }
|
||||||
|
|
||||||
void Process::setRunning(bool running) {
|
void Process::setRunning(bool running) {
|
||||||
|
@ -183,14 +173,6 @@ void Process::setStdinEnabled(bool enabled) {
|
||||||
emit this->stdinEnabledChanged();
|
emit this->stdinEnabledChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Process::isLifetimeManaged() const { return this->mLifetimeManaged; }
|
|
||||||
|
|
||||||
void Process::setLifetimeManaged(bool managed) {
|
|
||||||
if (managed == this->mLifetimeManaged) return;
|
|
||||||
this->mLifetimeManaged = managed;
|
|
||||||
emit this->lifetimeManagedChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Process::startProcessIfReady() {
|
void Process::startProcessIfReady() {
|
||||||
if (this->process != nullptr || !this->targetRunning || this->mCommand.isEmpty()) return;
|
if (this->process != nullptr || !this->targetRunning || this->mCommand.isEmpty()) return;
|
||||||
this->targetRunning = false;
|
this->targetRunning = false;
|
||||||
|
@ -215,8 +197,30 @@ void Process::startProcessIfReady() {
|
||||||
if (this->mStderrParser == nullptr) this->process->closeReadChannel(QProcess::StandardError);
|
if (this->mStderrParser == nullptr) this->process->closeReadChannel(QProcess::StandardError);
|
||||||
if (!this->mStdinEnabled) this->process->closeWriteChannel();
|
if (!this->mStdinEnabled) this->process->closeWriteChannel();
|
||||||
|
|
||||||
|
this->setupEnvironment(this->process);
|
||||||
|
this->process->start(cmd, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::startDetached() {
|
||||||
|
if (this->mCommand.isEmpty()) {
|
||||||
|
qmlWarning(this) << "Cannot start process as command is empty.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& cmd = this->mCommand.first();
|
||||||
|
auto args = this->mCommand.sliced(1);
|
||||||
|
|
||||||
|
QProcess process;
|
||||||
|
|
||||||
|
this->setupEnvironment(&process);
|
||||||
|
process.setProgram(cmd);
|
||||||
|
process.setArguments(args);
|
||||||
|
process.startDetached();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::setupEnvironment(QProcess* process) {
|
||||||
if (!this->mWorkingDirectory.isEmpty()) {
|
if (!this->mWorkingDirectory.isEmpty()) {
|
||||||
this->process->setWorkingDirectory(this->mWorkingDirectory);
|
process->setWorkingDirectory(this->mWorkingDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->mEnvironment.isEmpty() || this->mClearEnvironment) {
|
if (!this->mEnvironment.isEmpty() || this->mClearEnvironment) {
|
||||||
|
@ -237,10 +241,8 @@ void Process::startProcessIfReady() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->process->setProcessEnvironment(env);
|
process->setProcessEnvironment(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->process->start(cmd, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::onStarted() {
|
void Process::onStarted() {
|
||||||
|
@ -291,13 +293,3 @@ void Process::write(const QString& data) {
|
||||||
if (this->process == nullptr) return;
|
if (this->process == nullptr) return;
|
||||||
this->process->write(data.toUtf8());
|
this->process->write(data.toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisownedProcessContext::reparent(QProcess* process) {
|
|
||||||
process->setParent(this);
|
|
||||||
QObject::connect(process, &QProcess::finished, this, [process]() { process->deleteLater(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void DisownedProcessContext::destroyInstance() {
|
|
||||||
delete disownedCtx;
|
|
||||||
disownedCtx = nullptr;
|
|
||||||
}
|
|
||||||
|
|
|
@ -46,6 +46,9 @@ class Process: public QObject {
|
||||||
/// onRunningChanged: if (!running) running = true
|
/// onRunningChanged: if (!running) running = true
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// > [!NOTE] See @@startDetached() to prevent the process from being killed by Quickshell
|
||||||
|
/// > if Quickshell is killed or the configuration is reloaded.
|
||||||
Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged);
|
Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged);
|
||||||
/// The process ID of the running process or `null` if @@running is false.
|
/// The process ID of the running process or `null` if @@running is false.
|
||||||
Q_PROPERTY(QVariant processId READ processId NOTIFY processIdChanged);
|
Q_PROPERTY(QVariant processId READ processId NOTIFY processIdChanged);
|
||||||
|
@ -125,21 +128,11 @@ class Process: public QObject {
|
||||||
/// If stdin is enabled. Defaults to false. If this property is false the process's stdin channel
|
/// If stdin is enabled. Defaults to false. If this property is false the process's stdin channel
|
||||||
/// will be closed and @@write() will do nothing, even if set back to true.
|
/// will be closed and @@write() will do nothing, even if set back to true.
|
||||||
Q_PROPERTY(bool stdinEnabled READ stdinEnabled WRITE setStdinEnabled NOTIFY stdinEnabledChanged);
|
Q_PROPERTY(bool stdinEnabled READ stdinEnabled WRITE setStdinEnabled NOTIFY stdinEnabledChanged);
|
||||||
/// If the process should be killed when the Process object is destroyed or quickshell exits.
|
|
||||||
/// Defaults to true.
|
|
||||||
///
|
|
||||||
/// This property may be changed while the process is running and will affect it.
|
|
||||||
///
|
|
||||||
/// > [!WARNING] If set to false the process will still be killed if the quickshell config reloads.
|
|
||||||
/// > It will not be killed if quickshell exits normally or crashes.
|
|
||||||
Q_PROPERTY(bool manageLifetime READ isLifetimeManaged WRITE setLifetimeManaged NOTIFY lifetimeManagedChanged);
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
QML_ELEMENT;
|
QML_ELEMENT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Process(QObject* parent = nullptr);
|
explicit Process(QObject* parent = nullptr);
|
||||||
~Process() override;
|
|
||||||
Q_DISABLE_COPY_MOVE(Process);
|
|
||||||
|
|
||||||
/// Sends a signal to the process if @@running is true, otherwise does nothing.
|
/// Sends a signal to the process if @@running is true, otherwise does nothing.
|
||||||
Q_INVOKABLE void signal(qint32 signal);
|
Q_INVOKABLE void signal(qint32 signal);
|
||||||
|
@ -147,6 +140,12 @@ public:
|
||||||
/// Writes to the process's stdin. Does nothing if @@running is false.
|
/// Writes to the process's stdin. Does nothing if @@running is false.
|
||||||
Q_INVOKABLE void write(const QString& data);
|
Q_INVOKABLE void write(const QString& data);
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
Q_INVOKABLE void startDetached();
|
||||||
|
|
||||||
[[nodiscard]] bool isRunning() const;
|
[[nodiscard]] bool isRunning() const;
|
||||||
void setRunning(bool running);
|
void setRunning(bool running);
|
||||||
|
|
||||||
|
@ -173,9 +172,6 @@ public:
|
||||||
[[nodiscard]] bool stdinEnabled() const;
|
[[nodiscard]] bool stdinEnabled() const;
|
||||||
void setStdinEnabled(bool enabled);
|
void setStdinEnabled(bool enabled);
|
||||||
|
|
||||||
[[nodiscard]] bool isLifetimeManaged() const;
|
|
||||||
void setLifetimeManaged(bool managed);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void started();
|
void started();
|
||||||
void exited(qint32 exitCode, QProcess::ExitStatus exitStatus);
|
void exited(qint32 exitCode, QProcess::ExitStatus exitStatus);
|
||||||
|
@ -189,7 +185,6 @@ signals:
|
||||||
void stdoutParserChanged();
|
void stdoutParserChanged();
|
||||||
void stderrParserChanged();
|
void stderrParserChanged();
|
||||||
void stdinEnabledChanged();
|
void stdinEnabledChanged();
|
||||||
void lifetimeManagedChanged();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onStarted();
|
void onStarted();
|
||||||
|
@ -203,6 +198,7 @@ private slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void startProcessIfReady();
|
void startProcessIfReady();
|
||||||
|
void setupEnvironment(QProcess* process);
|
||||||
|
|
||||||
QProcess* process = nullptr;
|
QProcess* process = nullptr;
|
||||||
QList<QString> mCommand;
|
QList<QString> mCommand;
|
||||||
|
@ -216,15 +212,4 @@ private:
|
||||||
bool targetRunning = false;
|
bool targetRunning = false;
|
||||||
bool mStdinEnabled = false;
|
bool mStdinEnabled = false;
|
||||||
bool mClearEnvironment = false;
|
bool mClearEnvironment = false;
|
||||||
bool mLifetimeManaged = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DisownedProcessContext: public QObject {
|
|
||||||
Q_OBJECT;
|
|
||||||
|
|
||||||
void reparent(QProcess* process);
|
|
||||||
friend class Process;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static void destroyInstance();
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
|
|
||||||
#include <qtimer.h>
|
|
||||||
#include <qcontainerfwd.h>
|
#include <qcontainerfwd.h>
|
||||||
#include <qdatetime.h>
|
#include <qdatetime.h>
|
||||||
#include <qdbusconnection.h>
|
#include <qdbusconnection.h>
|
||||||
|
@ -11,6 +10,7 @@
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qproperty.h>
|
#include <qproperty.h>
|
||||||
#include <qstring.h>
|
#include <qstring.h>
|
||||||
|
#include <qtimer.h>
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
#include <qtypes.h>
|
#include <qtypes.h>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue