Phosphor
Qt6 / Wayland library suite for window-management tools
 
Loading...
Searching...
No Matches
Process.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 fuddlesworth
2// SPDX-License-Identifier: LGPL-2.1-or-later
3
4#pragma once
5
6#include <PhosphorShell/phosphorshell_export.h>
7
8#include <QObject>
9#include <QProcess>
10#include <QStringConverter>
11#include <QStringList>
12#include <QtQml/qqmlregistration.h>
13
14QT_BEGIN_NAMESPACE
15class QTimer;
16QT_END_NAMESPACE
17
18namespace PhosphorShell {
19
20class PHOSPHORSHELL_EXPORT Process : public QObject
21{
22 Q_OBJECT
23 Q_DISABLE_COPY_MOVE(Process)
24
25 Q_PROPERTY(QStringList command READ command WRITE setCommand NOTIFY commandChanged)
26 Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged)
27 Q_PROPERTY(int interval READ interval WRITE setInterval NOTIFY intervalChanged)
28 // Property names are `stdoutText` / `stderrText` — `stdout` and `stderr`
29 // are macros in <cstdio>, and any TU that transitively includes <cstdio>
30 // before this header would have moc see `Q_PROPERTY(QString (*) ...)`
31 // and fail to compile. The defensive rename keeps the QML name distinct
32 // from the macro.
33 Q_PROPERTY(QString stdoutText READ stdoutText NOTIFY stdoutTextChanged)
34 Q_PROPERTY(QString stderrText READ stderrText NOTIFY stderrTextChanged)
35 Q_PROPERTY(int exitCode READ exitCode NOTIFY exitCodeChanged)
39 Q_PROPERTY(QProcess::ExitStatus exitStatus READ exitStatus NOTIFY exitStatusChanged)
40
41public:
42 explicit Process(QObject* parent = nullptr);
43 ~Process() override;
44
45 [[nodiscard]] QStringList command() const;
46 void setCommand(const QStringList& command);
47
48 [[nodiscard]] bool running() const;
49 void setRunning(bool running);
50
51 [[nodiscard]] int interval() const;
52 void setInterval(int interval);
53
54 [[nodiscard]] QString stdoutText() const;
55 [[nodiscard]] QString stderrText() const;
56 [[nodiscard]] int exitCode() const;
57 [[nodiscard]] QProcess::ExitStatus exitStatus() const;
58
59Q_SIGNALS:
67 void finished(int exitCode, QProcess::ExitStatus exitStatus);
68
69private Q_SLOTS:
70 void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
71 void onReadyReadStdout();
72 void onReadyReadStderr();
73
74private:
75 void startProcess();
76 void stopProcess();
77
78 QStringList m_command;
79 bool m_running = false;
80 int m_interval = 0;
81 QString m_stdout;
82 QString m_stderr;
83 // "Fresh run" latches — set in startProcess, cleared by the first
84 // readyRead of the new run. The next readyRead REPLACES the buffer
85 // instead of appending, so a clock-style interval=N consumer never
86 // sees a transient empty stdoutText (the visible "blink" the old
87 // emit-on-clear path produced). Drain in onProcessFinished still
88 // honours the latch: a run that exited with no output at all
89 // explicitly clears the buffer there so old data doesn't linger.
90 bool m_stdoutFresh = true;
91 bool m_stderrFresh = true;
92 // Stateful UTF-8 → UTF-16 decoders that retain partial multi-byte
93 // sequences across `readyRead*` chunk boundaries. Without this, a
94 // codepoint that straddles two read chunks (common at 4 KiB
95 // boundaries for non-ASCII output) would decode to U+FFFD on each
96 // side. Reset on each new process invocation.
97 QStringDecoder m_stdoutDecoder{QStringConverter::Utf8};
98 QStringDecoder m_stderrDecoder{QStringConverter::Utf8};
99 int m_exitCode = 0;
100 QProcess::ExitStatus m_exitStatus = QProcess::NormalExit;
101 QProcess* m_process = nullptr;
102 QTimer* m_timer = nullptr;
103};
104
105} // namespace PhosphorShell
Definition Process.h:21
QString stderrText() const
QStringList command() const
void setRunning(bool running)
void setCommand(const QStringList &command)
void setInterval(int interval)
Process(QObject *parent=nullptr)
Last process exit status (NormalExit / CrashExit).
QString stdoutText() const
void finished(int exitCode, QProcess::ExitStatus exitStatus)
QProcess::ExitStatus exitStatus() const
Definition Environment.h:11