forked from quickshell/quickshell
		
	feat: add Process.manageLifetime
This commit is contained in:
		
							parent
							
								
									4cfe6ee0a1
								
							
						
					
					
						commit
						62f99f5754
					
				
					 8 changed files with 90 additions and 6 deletions
				
			
		| 
						 | 
					@ -25,3 +25,9 @@ void QuickshellPlugin::initPlugins() {
 | 
				
			||||||
		plugin->registerTypes();
 | 
							plugin->registerTypes();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void QuickshellPlugin::runOnReload() {
 | 
				
			||||||
 | 
						for (QuickshellPlugin* plugin: plugins) {
 | 
				
			||||||
 | 
							plugin->onReload();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,9 +15,11 @@ public:
 | 
				
			||||||
	virtual bool applies() { return true; }
 | 
						virtual bool applies() { return true; }
 | 
				
			||||||
	virtual void init() {}
 | 
						virtual void init() {}
 | 
				
			||||||
	virtual void registerTypes() {}
 | 
						virtual void registerTypes() {}
 | 
				
			||||||
 | 
						virtual void onReload() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static void registerPlugin(QuickshellPlugin& plugin);
 | 
						static void registerPlugin(QuickshellPlugin& plugin);
 | 
				
			||||||
	static void initPlugins();
 | 
						static void initPlugins();
 | 
				
			||||||
 | 
						static void runOnReload();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NOLINTBEGIN
 | 
					// NOLINTBEGIN
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
#include <qtimer.h>
 | 
					#include <qtimer.h>
 | 
				
			||||||
#include <qurl.h>
 | 
					#include <qurl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "plugin.hpp"
 | 
				
			||||||
#include "qmlglobal.hpp"
 | 
					#include "qmlglobal.hpp"
 | 
				
			||||||
#include "reload.hpp"
 | 
					#include "reload.hpp"
 | 
				
			||||||
#include "shell.hpp"
 | 
					#include "shell.hpp"
 | 
				
			||||||
| 
						 | 
					@ -41,9 +42,8 @@ RootWrapper::~RootWrapper() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RootWrapper::reloadGraph(bool hard) {
 | 
					void RootWrapper::reloadGraph(bool hard) {
 | 
				
			||||||
	QuickshellGlobal::deleteInstance();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (this->root != nullptr) {
 | 
						if (this->root != nullptr) {
 | 
				
			||||||
 | 
							QuickshellGlobal::deleteInstance();
 | 
				
			||||||
		this->engine.clearComponentCache();
 | 
							this->engine.clearComponentCache();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,10 +77,14 @@ void RootWrapper::reloadGraph(bool hard) {
 | 
				
			||||||
		oldRoot->deleteLater();
 | 
							oldRoot->deleteLater();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		QTimer::singleShot(0, [this, newRoot]() {
 | 
							QTimer::singleShot(0, [this, newRoot]() {
 | 
				
			||||||
			if (this->root == newRoot) PostReloadHook::postReloadTree(this->root);
 | 
								if (this->root == newRoot) {
 | 
				
			||||||
 | 
									QuickshellPlugin::runOnReload();
 | 
				
			||||||
 | 
									PostReloadHook::postReloadTree(this->root);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		PostReloadHook::postReloadTree(newRoot);
 | 
							PostReloadHook::postReloadTree(newRoot);
 | 
				
			||||||
 | 
							QuickshellPlugin::runOnReload();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->onConfigChanged();
 | 
						this->onConfigChanged();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,14 +3,18 @@ qt_add_library(quickshell-io STATIC
 | 
				
			||||||
	process.cpp
 | 
						process.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()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qt_add_qml_module(quickshell-io URI Quickshell.Io)
 | 
					qt_add_qml_module(quickshell-io URI Quickshell.Io)
 | 
				
			||||||
target_link_libraries(quickshell-io PRIVATE ${QT_DEPS})
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_link_libraries(quickshell PRIVATE quickshell-ioplugin)
 | 
					target_link_libraries(quickshell-io PRIVATE ${QT_DEPS})
 | 
				
			||||||
 | 
					target_link_libraries(quickshell-io-init PRIVATE ${QT_DEPS})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					target_link_libraries(quickshell PRIVATE quickshell-ioplugin quickshell-io-init)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (TESTS)
 | 
					if (TESTS)
 | 
				
			||||||
	add_subdirectory(test)
 | 
						add_subdirectory(test)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/io/init.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/io/init.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					#include "../core/plugin.hpp"
 | 
				
			||||||
 | 
					#include "process.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IoPlugin: public QuickshellPlugin {
 | 
				
			||||||
 | 
						void onReload() override { DisownedProcessContext::destroyInstance(); }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QS_REGISTER_PLUGIN(IoPlugin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace
 | 
				
			||||||
							
								
								
									
										0
									
								
								src/io/plugin.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/io/plugin.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -15,6 +15,10 @@
 | 
				
			||||||
#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(
 | 
				
			||||||
	    QuickshellGlobal::instance(),
 | 
						    QuickshellGlobal::instance(),
 | 
				
			||||||
| 
						 | 
					@ -24,6 +28,13 @@ 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) {
 | 
				
			||||||
| 
						 | 
					@ -161,6 +172,14 @@ 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;
 | 
				
			||||||
| 
						 | 
					@ -261,3 +280,13 @@ 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@
 | 
				
			||||||
#include <qobject.h>
 | 
					#include <qobject.h>
 | 
				
			||||||
#include <qprocess.h>
 | 
					#include <qprocess.h>
 | 
				
			||||||
#include <qqmlintegration.h>
 | 
					#include <qqmlintegration.h>
 | 
				
			||||||
 | 
					#include <qtclasshelpermacros.h>
 | 
				
			||||||
#include <qtmetamacros.h>
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
#include <qtypes.h>
 | 
					#include <qtypes.h>
 | 
				
			||||||
#include <qvariant.h>
 | 
					#include <qvariant.h>
 | 
				
			||||||
| 
						 | 
					@ -43,7 +44,8 @@ class Process: public QObject {
 | 
				
			||||||
	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 pid READ pid NOTIFY pidChanged);
 | 
						Q_PROPERTY(QVariant pid READ pid NOTIFY pidChanged);
 | 
				
			||||||
	/// The command to execute.
 | 
						/// The command to execute. Each argument is its own string, which means you don't have
 | 
				
			||||||
 | 
						/// to deal with quoting anything.
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
	/// If the process is already running changing this property will affect the next
 | 
						/// 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
 | 
						/// started process. If the property has been changed after starting a process it will
 | 
				
			||||||
| 
						 | 
					@ -112,11 +114,21 @@ class Process: public QObject {
 | 
				
			||||||
	/// If stdin is enabled. Defaults to true. If this property is set to false the process's stdin channel
 | 
						/// If stdin is enabled. Defaults to true. If this property is set to false the process's stdin channel
 | 
				
			||||||
	/// will be closed and [write](#func.write) will do nothing, even if set back to true.
 | 
						/// will be closed and [write](#func.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);
 | 
				
			||||||
| 
						 | 
					@ -150,6 +162,9 @@ 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);
 | 
				
			||||||
| 
						 | 
					@ -163,6 +178,7 @@ signals:
 | 
				
			||||||
	void stdoutParserChanged();
 | 
						void stdoutParserChanged();
 | 
				
			||||||
	void stderrParserChanged();
 | 
						void stderrParserChanged();
 | 
				
			||||||
	void stdinEnabledChanged();
 | 
						void stdinEnabledChanged();
 | 
				
			||||||
 | 
						void lifetimeManagedChanged();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private slots:
 | 
					private slots:
 | 
				
			||||||
	void onStarted();
 | 
						void onStarted();
 | 
				
			||||||
| 
						 | 
					@ -189,4 +205,15 @@ 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();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue