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