summaryrefslogtreecommitdiff
path: root/src/processrunner.h
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2019-11-11 14:14:01 -0500
committerGitHub <noreply@github.com>2019-11-11 14:14:01 -0500
commitd6c3bad01a85c1a5b1a3bdd86efc85efdd4c5f29 (patch)
treefddae0025e65bd1d5064bf8ad6fa73a23aa750e9 /src/processrunner.h
parent7b3c5dcbb3b5d520d166eb5b51f669968f57302e (diff)
parentdecd5c1828f495be4e230c9fc6fb79dd9bfdfb81 (diff)
Merge pull request #887 from isanae/spawning-and-waiting
Spawning, waiting and locking
Diffstat (limited to 'src/processrunner.h')
-rw-r--r--src/processrunner.h172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/processrunner.h b/src/processrunner.h
new file mode 100644
index 00000000..c61d6b70
--- /dev/null
+++ b/src/processrunner.h
@@ -0,0 +1,172 @@
+#ifndef PROCESSRUNNER_H
+#define PROCESSRUNNER_H
+
+#include "spawn.h"
+#include "uilocker.h"
+#include "envmodule.h"
+#include <executableinfo.h>
+
+class OrganizerCore;
+class IUserInterface;
+class Executable;
+class MOShortcut;
+
+// handles spawning a process and waiting for it, including setting up the lock
+// widget if required
+//
+class ProcessRunner
+{
+public:
+ enum Results
+ {
+ // the process is still running
+ Running = 1,
+
+ // the process has run to completion
+ Completed,
+
+ // the process couldn't be started or waited for
+ Error,
+
+ // the user has clicked the cancel button in the lock widget
+ Cancelled,
+
+ // the user has clicked the unlock button in the lock widget
+ ForceUnlocked
+ };
+
+ enum WaitFlag
+ {
+ NoFlags = 0x00,
+
+ // the ui will be refreshed once the process has completed
+ Refresh = 0x01,
+
+ // the process will be waited for even if locking is disabled
+ ForceWait = 0x02
+ };
+
+ using WaitFlags = QFlags<WaitFlag>;
+ using ForcedLibraries = QList<MOBase::ExecutableForcedLoadSetting>;
+
+ ProcessRunner(OrganizerCore& core, IUserInterface* ui);
+
+ // move only
+ ProcessRunner(ProcessRunner&&) = default;
+ ProcessRunner& operator=(const ProcessRunner&) = delete;
+ ProcessRunner(const ProcessRunner&) = delete;
+ ProcessRunner& operator=(ProcessRunner&&) = delete;
+
+ ProcessRunner& setBinary(const QFileInfo &binary);
+ ProcessRunner& setArguments(const QString& arguments);
+ ProcessRunner& setCurrentDirectory(const QDir& directory);
+ ProcessRunner& setSteamID(const QString& steamID);
+ ProcessRunner& setCustomOverwrite(const QString& customOverwrite);
+ ProcessRunner& setForcedLibraries(const ForcedLibraries& forcedLibraries);
+ ProcessRunner& setProfileName(const QString& profileName);
+ ProcessRunner& setWaitForCompletion(
+ WaitFlags flags=NoFlags, UILocker::Reasons reason=UILocker::LockUI);
+
+ // if the target is an executable file, runs that; for anything else, calls
+ // ShellExecute() on it
+ //
+ ProcessRunner& setFromFile(QWidget* parent, const QFileInfo& targetInfo);
+
+ ProcessRunner& setFromExecutable(const Executable& exe);
+ ProcessRunner& setFromShortcut(const MOShortcut& shortcut);
+
+ // this is a messy one that's used for running an arbitrary file from the
+ // command line, or by plugins (see OrganizerProxy::startApplication())
+ //
+ // 1) if `executable` contains a path separator, it's treated as a binary on
+ // disk and will be launched with given settings; it's also looked up in
+ // the list of configured executables, which sets the steam ID and forced
+ // libraries
+ //
+ // 2) if `executable` has no path separators, it's treated purely as an
+ // executable, but its arguments, current directory and custom overwrite
+ // can also be overridden
+ //
+ // if the executable is not found in the list, the binary is run solely
+ // based on the parameters given
+ //
+ ProcessRunner& setFromFileOrExecutable(
+ const QString &executable,
+ const QStringList &args,
+ const QString &cwd={},
+ const QString &profile={},
+ const QString &forcedCustomOverwrite={},
+ bool ignoreCustomOverwrite=false);
+
+ // spawns the process and waits for it if required
+ //
+ Results run();
+
+ // takes ownership of the given handle and waits for it if required
+ //
+ Results attachToProcess(HANDLE h);
+
+ // exit code of the process, will return -1 if the process wasn't waited for
+ //
+ DWORD exitCode() const;
+
+ // this may be INVALID_HANDLE_VALUE if:
+ //
+ // 1) no process was started, or
+ // 2) the process was started successfully, but the system didn't return a
+ // handle for it; this can happen for inproc handlers, for example, such
+ // the photo viewer
+ //
+ // note that the handle is still owned by this ProcessRunner and will be
+ // closed when destroyed; see stealProcessHandle()
+ //
+ HANDLE getProcessHandle() const;
+
+ // releases ownership of the process handle; if this is called after the
+ // process is completed, exitCode() will still return the correct value
+ //
+ env::HandlePtr stealProcessHandle();
+
+ // waits for all usvfs processes spawned by this instance of MO; returns
+ // immediately with ForceUnlocked if locking is disabled
+ //
+ // strictly speaking, this shouldn't be here, as it has nothing to do with
+ // running a process, but it uses the same internal stuff as when running a
+ // process
+ //
+ Results waitForAllUSVFSProcessesWithLock(UILocker::Reasons reason);
+
+private:
+ OrganizerCore& m_core;
+ IUserInterface* m_ui;
+ spawn::SpawnParameters m_sp;
+ QString m_customOverwrite;
+ ForcedLibraries m_forcedLibraries;
+ QString m_profileName;
+ UILocker::Reasons m_lockReason;
+ WaitFlags m_waitFlags;
+ QString m_shellOpen;
+ env::HandlePtr m_handle;
+ DWORD m_exitCode;
+
+
+ // runs the command in m_shellOpen; returns empty if it can be waited for
+ //
+ std::optional<Results> runShell();
+
+ // runs the binary; returns empty if it can be waited for
+ //
+ std::optional<Results> runBinary();
+
+ // waits for process completion if required
+ //
+ Results postRun();
+
+ // creates the lock widget and calls f()
+ //
+ void withLock(std::function<void (UILocker::Session&)> f);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(ProcessRunner::WaitFlags);
+
+#endif // PROCESSRUNNER_H