summaryrefslogtreecommitdiff
path: root/accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.cpp
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2026-09-23 21:08:35 +0200
committerGregor Kleen <gkleen@yggdrasil.li>2026-09-23 21:08:35 +0200
commitae9a80c1f012686c1f65fce7ce76fdd1b77b0b71 (patch)
tree141f738276cf84c6b7e5633c2bd5f2b44e9b0b75 /accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.cpp
parent6a763272038e637a8a03dd9059d43a1ff44921dd (diff)
downloadnixos-ae9a80c1f012686c1f65fce7ce76fdd1b77b0b71.tar
nixos-ae9a80c1f012686c1f65fce7ce76fdd1b77b0b71.tar.gz
nixos-ae9a80c1f012686c1f65fce7ce76fdd1b77b0b71.tar.bz2
nixos-ae9a80c1f012686c1f65fce7ce76fdd1b77b0b71.tar.xz
nixos-ae9a80c1f012686c1f65fce7ce76fdd1b77b0b71.zip
...
Diffstat (limited to 'accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.cpp')
-rw-r--r--accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.cpp288
1 files changed, 288 insertions, 0 deletions
diff --git a/accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.cpp b/accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.cpp
new file mode 100644
index 00000000..6376b527
--- /dev/null
+++ b/accounts/gkleen@skadhi/shell/quickshell-plugins/Systemd.cpp
@@ -0,0 +1,288 @@
1#include "Systemd.hpp"
2
3#include <sstream>
4
5#include <QDBusConnection>
6#include <QDBusReply>
7#include <QDebug>
8#include <QDBusUnixFileDescriptor>
9#include <QDBusObjectPath>
10
11#include <set>
12
13Systemd::Systemd(QObject* parent) : QObject(parent) {
14 ListUnitsEntry::registerMetaType();
15 qDBusRegisterMetaType<ListUnitsResult>();
16
17 this->systemdManager = new DBusSystemdManager(
18 "org.freedesktop.systemd1",
19 "/org/freedesktop/systemd1",
20 QDBusConnection::sessionBus(),
21 this
22 );
23 this->logindManager = new DBusLogindManager(
24 "org.freedesktop.login1",
25 "/org/freedesktop/login1",
26 QDBusConnection::systemBus(),
27 this
28 );
29
30
31 QDBusReply<QDBusObjectPath> sessionPath = this->logindManager->GetSession("auto");
32 // qDebug() << sessionPath;
33 this->logindSession = new DBusLogindSession(
34 "org.freedesktop.login1",
35 sessionPath.value().path(),
36 QDBusConnection::systemBus(),
37 this
38 );
39 this->logindSessionProperties = new DBusProperties(
40 "org.freedesktop.login1",
41 sessionPath.value().path(),
42 QDBusConnection::systemBus(),
43 this
44 );
45
46 QObject::connect(this->logindManager, &DBusLogindManager::PrepareForShutdown, this, &Systemd::shutdown);
47 QObject::connect(this->logindManager, &DBusLogindManager::PrepareForSleep, this, &Systemd::sleep);
48 QObject::connect(this->logindSession, &DBusLogindSession::Lock, this, &Systemd::lock);
49 QObject::connect(this->logindSession, &DBusLogindSession::Unlock, this, &Systemd::unlock);
50 QObject::connect(this->logindSessionProperties, &DBusProperties::PropertiesChanged, this, &Systemd::onLogindSessionPropertiesChanged);
51 this->systemdManager->Subscribe();
52 QObject::connect(this->systemdManager, &DBusSystemdManager::UnitNew, this, &Systemd::onUserUnitNew);
53 QObject::connect(this->systemdManager, &DBusSystemdManager::UnitRemoved, this, &Systemd::onUserUnitRemoved);
54
55 for (const auto& unit: this->systemdManager->ListUnits().value())
56 this->onUserUnitNew(unit.primaryName, unit.unitPath);
57}
58
59void Systemd::onLogindSessionPropertiesChanged(const QString& interface_name, const QVariantMap& changed_properties, const QStringList& invalidated_properties) {
60 if (changed_properties.contains("IdleHint") || invalidated_properties.contains("IdleHint"))
61 emit this->idleHintChanged();
62 if (changed_properties.contains("LockedHint") || invalidated_properties.contains("LockedHint"))
63 emit this->lockedHintChanged();
64}
65void Systemd::onUserUnitNew(const QString& id, const QDBusObjectPath& object_path) {
66 for (auto unit: this->mUserUnits.valueList())
67 if (unit->path() == object_path)
68 return;
69
70 for (const auto& unit: this->systemdManager->ListUnits().value())
71 if (unit.unitPath == object_path) {
72 this->mUserUnits.insertObject(new SystemdUnit(this, object_path, id));
73 return;
74 }
75}
76void Systemd::onUserUnitRemoved(const QString& id, const QDBusObjectPath& object_path) {
77 std::set<SystemdUnit*> toRemove;
78 for (auto unit: this->mUserUnits.valueList())
79 if (unit->path() == object_path)
80 toRemove.insert(unit);
81
82 for (auto unit: toRemove) {
83 this->mUserUnits.removeObject(unit);
84 delete unit;
85 }
86}
87
88SystemdUnit::SystemdUnit(QObject* parent, const QDBusObjectPath& path, const QString& id): QObject(parent), mPath(path), mId(id) {
89 this->mUnitProperties = new DBusProperties(
90 "org.freedesktop.systemd1",
91 this->path().path(),
92 QDBusConnection::sessionBus(),
93 this
94 );
95}
96std::unique_ptr<DBusSystemdUnit> SystemdUnit::systemdUnit() {
97 return std::make_unique<DBusSystemdUnit>(
98 "org.freedesktop.systemd1",
99 this->path().path(),
100 QDBusConnection::sessionBus(),
101 nullptr
102 );
103}
104std::unique_ptr<DBusSystemdService> SystemdUnit::systemdService() {
105 if (!this->id().endsWith(".service"))
106 return std::unique_ptr<DBusSystemdService>();
107
108 return std::make_unique<DBusSystemdService>(
109 "org.freedesktop.systemd1",
110 this->path().path(),
111 QDBusConnection::sessionBus(),
112 nullptr
113 );
114}
115QList<QString> SystemdUnit::runtimeDirectory() {
116 if (std::unique_ptr<DBusSystemdService> systemdService = this->systemdService()) {
117 if (!this->mRuntimeDirectory)
118 this->mRuntimeDirectory = systemdService->runtimeDirectory();
119 return *this->mRuntimeDirectory;
120 }
121
122 return QList<QString>{};
123}
124QString SystemdUnit::activeState() {
125 if (!this->mActiveState) {
126 QObject::connect(this->mUnitProperties, &DBusProperties::PropertiesChanged, this, &SystemdUnit::onUnitPropertiesChanged);
127 this->mActiveState = this->systemdUnit()->activeState();
128 }
129
130 return *this->mActiveState;
131}
132
133const QDBusObjectPath& SystemdUnit::path() const { return this->mPath; }
134const QString& SystemdUnit::id() const { return this->mId; }
135void SystemdUnit::onUnitPropertiesChanged(const QString& interface_name, const QVariantMap& changed_properties, const QStringList& invalidated_properties) {
136 if (changed_properties.contains("ActiveState") || invalidated_properties.contains("ActiveState")) {
137 this->mActiveState = this->systemdUnit()->activeState();
138 emit this->activeStateChanged();
139 }
140}
141
142void Systemd::stopUserUnit(const QString& unit, const QString& mode) { this->systemdManager->StopUnit(unit, mode); }
143
144void Systemd::setBrightness(const QString& subsystem, const QString& name, quint32 brightness) { this->logindSession->SetBrightness(subsystem, name, brightness); }
145
146bool Systemd::idleHint() { return this->logindSession->idleHint(); }
147void Systemd::setIdleHint(bool idle) { this->logindSession->SetIdleHint(idle); }
148bool Systemd::lockedHint() { return this->logindSession->lockedHint(); }
149void Systemd::setLockedHint(bool locked) { this->logindSession->SetLockedHint(locked); }
150void Systemd::lockSession() { this->logindSession->call("Lock"); }
151void Systemd::suspend() { this->logindManager->Suspend(true); }
152void Systemd::hibernate() { this->logindManager->Hibernate(true); }
153
154ObjectModel<SystemdUnit>* Systemd::userUnits() { return &this->mUserUnits; }
155
156std::string SystemdInhibitorParams::toString(SystemdInhibitorParams::WhatItem what) {
157 if (what == SystemdInhibitorParams::Shutdown)
158 return "shutdown";
159 else if (what == SystemdInhibitorParams::Sleep)
160 return "sleep";
161 else if (what == SystemdInhibitorParams::Idle)
162 return "idle";
163 else if (what == SystemdInhibitorParams::HandlePowerKey)
164 return "handle-power-key";
165 else if (what == SystemdInhibitorParams::HandleSuspendKey)
166 return "handle-suspend-key";
167 else if (what == SystemdInhibitorParams::HandleHibernateKey)
168 return "handle-hibernate-key";
169 else if (what == SystemdInhibitorParams::HandleLidSwitch)
170 return "handle-lid-switch";
171 return "";
172}
173
174std::string SystemdInhibitorParams::toString(SystemdInhibitorParams::What what) {
175 std::ostringstream res;
176 bool first = true;
177 for (const WhatItem& item: SystemdInhibitorParams::allWhatItems) {
178 if (!(what & item))
179 continue;
180
181 if (!first)
182 res << ":";
183 else
184 first = false;
185 res << SystemdInhibitorParams::toString(item);
186 }
187 return res.str();
188}
189
190std::string SystemdInhibitorParams::toString(SystemdInhibitorParams::Mode mode) {
191 if (mode == SystemdInhibitorParams::Block)
192 return "block";
193 else if (mode == SystemdInhibitorParams::BlockWeak)
194 return "block-weak";
195 else if (mode == SystemdInhibitorParams::Delay)
196 return "delay";
197 return "";
198}
199
200bool SystemdInhibitor::enabled() const { return static_cast<bool>(this->activeInhibitor); }
201void SystemdInhibitor::setEnabled(bool enabled) {
202 this->mEnabled = enabled;
203
204 if (enabled)
205 this->update();
206 else
207 this->release();
208}
209
210SystemdInhibitorParams::What SystemdInhibitor::what() const { return this->mWhat; }
211void SystemdInhibitor::setWhat(SystemdInhibitorParams::What what) {
212 this->mWhat = what;
213 this->update();
214}
215
216QString SystemdInhibitor::who() const { return this->mWho; }
217void SystemdInhibitor::setWho(QString who) {
218 this->mWho = who;
219 this->update();
220}
221
222QString SystemdInhibitor::why() const { return this->mWhy; }
223void SystemdInhibitor::setWhy(QString why) {
224 this->mWhy = why;
225 this->update();
226}
227
228SystemdInhibitorParams::Mode SystemdInhibitor::mode() const { return this->mMode; }
229void SystemdInhibitor::setMode(SystemdInhibitorParams::Mode mode) {
230 this->mMode = mode;
231 this->update();
232}
233
234SystemdInhibitor::ActiveSystemdInhibitor::ActiveSystemdInhibitor(SystemdInhibitorParams::What what_, QString who_, QString why_, SystemdInhibitorParams::Mode mode_): what(what_), who(who_), why(why_), mode(mode_) {
235 DBusLogindManager logindManager(
236 "org.freedesktop.login1",
237 "/org/freedesktop/login1",
238 QDBusConnection::systemBus()
239 );
240 QDBusReply<QDBusUnixFileDescriptor> fd_ = logindManager.Inhibit(QString::fromStdString(SystemdInhibitorParams::toString(what)), who, why, QString::fromStdString(SystemdInhibitorParams::toString(mode)));
241 if (fd_.error().isValid())
242 throw fd_.error();
243 this->fd = ::dup(fd_.value().fileDescriptor());
244}
245SystemdInhibitor::ActiveSystemdInhibitor::~ActiveSystemdInhibitor() {
246 if (this->fd != -1)
247 ::close(this->fd);
248}
249
250void SystemdInhibitor::release() {
251 if (!this->activeInhibitor)
252 return;
253
254 this->activeInhibitor.reset();
255 emit this->enabledChanged();
256}
257
258void SystemdInhibitor::update() {
259 if (!this->mWhat || this->mWho.isEmpty() || this->mWhy.isEmpty() || !this->mMode || !this->mEnabled)
260 if (this->activeInhibitor)
261 this->release();
262 else
263 return;
264
265 if (this->activeInhibitor && this->mWhat == this->activeInhibitor->what && this->mWho == this->activeInhibitor->who && this->mWhy == this->activeInhibitor->why && this->mMode == this->activeInhibitor->mode)
266 return;
267
268 std::unique_ptr<ActiveSystemdInhibitor> otherInhibitor;
269 try {
270 otherInhibitor.reset(new SystemdInhibitor::ActiveSystemdInhibitor(this->mWhat, this->mWho, this->mWhy, this->mMode));
271 } catch (const QDBusError& err) {
272 qCritical().noquote()
273 << err.name().toStdString() << " " << err.message().toStdString();
274 return;
275 }
276 this->activeInhibitor.swap(otherInhibitor);
277
278 if (!otherInhibitor && this->activeInhibitor)
279 emit this->enabledChanged();
280 if (otherInhibitor && otherInhibitor->what != this->activeInhibitor->what)
281 emit this->whatChanged();
282 if (otherInhibitor && otherInhibitor->who != this->activeInhibitor->who)
283 emit this->whoChanged();
284 if (otherInhibitor && otherInhibitor->why != this->activeInhibitor->why)
285 emit this->whyChanged();
286 if (otherInhibitor && otherInhibitor->mode != this->activeInhibitor->mode)
287 emit this->modeChanged();
288}