Skip to content

Commit 0662c37

Browse files
committed
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.
1 parent c5bea85 commit 0662c37

File tree

5 files changed

+37
-76
lines changed

5 files changed

+37
-76
lines changed

src/io/CMakeLists.txt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ qt_add_library(quickshell-io STATIC
77
ipchandler.cpp
88
)
99

10-
add_library(quickshell-io-init OBJECT init.cpp)
11-
1210
if (SOCKETS)
1311
target_sources(quickshell-io PRIVATE socket.cpp)
1412
endif()
@@ -24,9 +22,7 @@ qt_add_qml_module(quickshell-io
2422
install_qml_module(quickshell-io)
2523

2624
target_link_libraries(quickshell-io PRIVATE Qt::Quick)
27-
target_link_libraries(quickshell-io-init PRIVATE Qt::Qml)
28-
29-
target_link_libraries(quickshell PRIVATE quickshell-ioplugin quickshell-io-init)
25+
target_link_libraries(quickshell PRIVATE quickshell-ioplugin)
3026

3127
qs_module_pch(quickshell-io)
3228

src/io/init.cpp

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/io/process.cpp

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <qmap.h>
99
#include <qobject.h>
1010
#include <qprocess.h>
11+
#include <qqmlinfo.h>
1112
#include <qtmetamacros.h>
1213
#include <qtypes.h>
1314
#include <qvariant.h>
@@ -16,10 +17,6 @@
1617
#include "../core/qmlglobal.hpp"
1718
#include "datastream.hpp"
1819

19-
// When the process ends this have no parent and is just leaked,
20-
// meaning the destructor never runs and they are never killed.
21-
static DisownedProcessContext* disownedCtx; // NOLINT
22-
2320
Process::Process(QObject* parent): QObject(parent) {
2421
QObject::connect(
2522
QuickshellSettings::instance(),
@@ -29,13 +26,6 @@ Process::Process(QObject* parent): QObject(parent) {
2926
);
3027
}
3128

32-
Process::~Process() {
33-
if (!this->mLifetimeManaged && this->process != nullptr) {
34-
if (disownedCtx == nullptr) disownedCtx = new DisownedProcessContext(); // NOLINT
35-
disownedCtx->reparent(this->process);
36-
}
37-
}
38-
3929
bool Process::isRunning() const { return this->process != nullptr; }
4030

4131
void Process::setRunning(bool running) {
@@ -183,14 +173,6 @@ void Process::setStdinEnabled(bool enabled) {
183173
emit this->stdinEnabledChanged();
184174
}
185175

186-
bool Process::isLifetimeManaged() const { return this->mLifetimeManaged; }
187-
188-
void Process::setLifetimeManaged(bool managed) {
189-
if (managed == this->mLifetimeManaged) return;
190-
this->mLifetimeManaged = managed;
191-
emit this->lifetimeManagedChanged();
192-
}
193-
194176
void Process::startProcessIfReady() {
195177
if (this->process != nullptr || !this->targetRunning || this->mCommand.isEmpty()) return;
196178
this->targetRunning = false;
@@ -215,8 +197,30 @@ void Process::startProcessIfReady() {
215197
if (this->mStderrParser == nullptr) this->process->closeReadChannel(QProcess::StandardError);
216198
if (!this->mStdinEnabled) this->process->closeWriteChannel();
217199

200+
this->setupEnvironment(this->process);
201+
this->process->start(cmd, args);
202+
}
203+
204+
void Process::startDetached() {
205+
if (this->mCommand.isEmpty()) {
206+
qmlWarning(this) << "Cannot start process as command is empty.";
207+
return;
208+
}
209+
210+
auto& cmd = this->mCommand.first();
211+
auto args = this->mCommand.sliced(1);
212+
213+
QProcess process;
214+
215+
this->setupEnvironment(&process);
216+
process.setProgram(cmd);
217+
process.setArguments(args);
218+
process.startDetached();
219+
}
220+
221+
void Process::setupEnvironment(QProcess* process) {
218222
if (!this->mWorkingDirectory.isEmpty()) {
219-
this->process->setWorkingDirectory(this->mWorkingDirectory);
223+
process->setWorkingDirectory(this->mWorkingDirectory);
220224
}
221225

222226
if (!this->mEnvironment.isEmpty() || this->mClearEnvironment) {
@@ -237,10 +241,8 @@ void Process::startProcessIfReady() {
237241
}
238242
}
239243

240-
this->process->setProcessEnvironment(env);
244+
process->setProcessEnvironment(env);
241245
}
242-
243-
this->process->start(cmd, args);
244246
}
245247

246248
void Process::onStarted() {
@@ -291,13 +293,3 @@ void Process::write(const QString& data) {
291293
if (this->process == nullptr) return;
292294
this->process->write(data.toUtf8());
293295
}
294-
295-
void DisownedProcessContext::reparent(QProcess* process) {
296-
process->setParent(this);
297-
QObject::connect(process, &QProcess::finished, this, [process]() { process->deleteLater(); });
298-
}
299-
300-
void DisownedProcessContext::destroyInstance() {
301-
delete disownedCtx;
302-
disownedCtx = nullptr;
303-
}

src/io/process.hpp

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ class Process: public QObject {
4646
/// onRunningChanged: if (!running) running = true
4747
/// }
4848
/// ```
49+
///
50+
/// > [!NOTE] See @@startDetached() to prevent the process from being killed by Quickshell
51+
/// > if Quickshell is killed or the configuration is reloaded.
4952
Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged);
5053
/// The process ID of the running process or `null` if @@running is false.
5154
Q_PROPERTY(QVariant processId READ processId NOTIFY processIdChanged);
@@ -125,28 +128,24 @@ class Process: public QObject {
125128
/// If stdin is enabled. Defaults to false. If this property is false the process's stdin channel
126129
/// will be closed and @@write() will do nothing, even if set back to true.
127130
Q_PROPERTY(bool stdinEnabled READ stdinEnabled WRITE setStdinEnabled NOTIFY stdinEnabledChanged);
128-
/// If the process should be killed when the Process object is destroyed or quickshell exits.
129-
/// Defaults to true.
130-
///
131-
/// This property may be changed while the process is running and will affect it.
132-
///
133-
/// > [!WARNING] If set to false the process will still be killed if the quickshell config reloads.
134-
/// > It will not be killed if quickshell exits normally or crashes.
135-
Q_PROPERTY(bool manageLifetime READ isLifetimeManaged WRITE setLifetimeManaged NOTIFY lifetimeManagedChanged);
136131
// clang-format on
137132
QML_ELEMENT;
138133

139134
public:
140135
explicit Process(QObject* parent = nullptr);
141-
~Process() override;
142-
Q_DISABLE_COPY_MOVE(Process);
143136

144137
/// Sends a signal to the process if @@running is true, otherwise does nothing.
145138
Q_INVOKABLE void signal(qint32 signal);
146139

147140
/// Writes to the process's stdin. Does nothing if @@running is false.
148141
Q_INVOKABLE void write(const QString& data);
149142

143+
/// Launches an instance of the process detached from quickshell.
144+
///
145+
/// The subprocess will not be tracked, @@running will be false,
146+
/// and the subprocess will not be killed by Quickshell.
147+
Q_INVOKABLE void startDetached();
148+
150149
[[nodiscard]] bool isRunning() const;
151150
void setRunning(bool running);
152151

@@ -173,9 +172,6 @@ class Process: public QObject {
173172
[[nodiscard]] bool stdinEnabled() const;
174173
void setStdinEnabled(bool enabled);
175174

176-
[[nodiscard]] bool isLifetimeManaged() const;
177-
void setLifetimeManaged(bool managed);
178-
179175
signals:
180176
void started();
181177
void exited(qint32 exitCode, QProcess::ExitStatus exitStatus);
@@ -189,7 +185,6 @@ class Process: public QObject {
189185
void stdoutParserChanged();
190186
void stderrParserChanged();
191187
void stdinEnabledChanged();
192-
void lifetimeManagedChanged();
193188

194189
private slots:
195190
void onStarted();
@@ -203,6 +198,7 @@ private slots:
203198

204199
private:
205200
void startProcessIfReady();
201+
void setupEnvironment(QProcess* process);
206202

207203
QProcess* process = nullptr;
208204
QList<QString> mCommand;
@@ -216,15 +212,4 @@ private slots:
216212
bool targetRunning = false;
217213
bool mStdinEnabled = false;
218214
bool mClearEnvironment = false;
219-
bool mLifetimeManaged = true;
220-
};
221-
222-
class DisownedProcessContext: public QObject {
223-
Q_OBJECT;
224-
225-
void reparent(QProcess* process);
226-
friend class Process;
227-
228-
public:
229-
static void destroyInstance();
230215
};

src/services/mpris/player.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "player.hpp"
22

3-
#include <qtimer.h>
43
#include <qcontainerfwd.h>
54
#include <qdatetime.h>
65
#include <qdbusconnection.h>
@@ -11,6 +10,7 @@
1110
#include <qobject.h>
1211
#include <qproperty.h>
1312
#include <qstring.h>
13+
#include <qtimer.h>
1414
#include <qtmetamacros.h>
1515
#include <qtypes.h>
1616

0 commit comments

Comments
 (0)