MythTV master
mythscreensaverdbus.cpp
Go to the documentation of this file.
1// Qt
2#include <QChar> // Fix Qt6 GCC SFINAE warning
3#include <QDBusConnection>
4#include <QDBusInterface>
5#include <QDBusReply>
6#include <QString>
7
8// MythTV
11
12// Std
13#include <array>
14#include <cstdint>
15#include <string>
16
17#define LOC QString("ScreenSaverDBus: ")
18
19const std::string kApp = "MythTV";
20const std::string kReason = "Watching TV";
21const std::string kDbusInhibit = "Inhibit";
22
23static constexpr size_t NUM_DBUS_METHODS { 4 };
24// Thanks to vlc for the set of dbus services to use.
25const std::array<const QString,NUM_DBUS_METHODS> kDbusService {
26 "org.freedesktop.ScreenSaver",
27 "org.freedesktop.PowerManagement.Inhibit",
28 "org.mate.SessionManager",
29 "org.gnome.SessionManager",
30};
31
32const std::array<const QString,NUM_DBUS_METHODS> kDbusPath {
33 "/ScreenSaver",
34 "/org/freedesktop/PowerManagement",
35 "/org/mate/SessionManager",
36 "/org/gnome/SessionManager",
37};
38
39// Service name is also the interface name in all cases
40
41const std::array<const QString,NUM_DBUS_METHODS> kDbusUnInhibit {
42 "UnInhibit",
43 "UnInhibit",
44 "Uninhibit",
45 "Uninhibit",
46};
47
49{
50 friend class MythScreenSaverDBus;
51
52 public:
53 ScreenSaverDBusPrivate(const QString &dbusService, const QString& dbusPath,
54 const QString &dbusInterface, QDBusConnection *bus)
55 : m_bus(bus),
56 m_interface(new QDBusInterface(dbusService, dbusPath , dbusInterface, *m_bus)),
57 m_serviceUsed(dbusService)
58 {
59 if (!m_interface->isValid())
60 {
61 LOG(VB_GENERAL, LOG_DEBUG, LOC +
62 QString("Could not connect to dbus service %1: %2")
63 .arg(dbusService, m_interface->lastError().message()));
64 }
65 else
66 {
67 LOG(VB_GENERAL, LOG_INFO, LOC + "Created for DBus service: " + dbusService);
68 }
69 }
71 {
72 delete m_interface;
73 }
74 void Inhibit(QString* errout = nullptr)
75 {
76 if (m_interface->isValid())
77 {
78 // method uint org.freedesktop.ScreenSaver.Inhibit(QString application_name, QString reason_for_inhibit)
79 QDBusMessage msg = m_interface->call(QDBus::Block,
80 kDbusInhibit.c_str(),
81 kApp.c_str(), kReason.c_str());
82 if (msg.type() == QDBusMessage::ReplyMessage)
83 {
84 QList<QVariant> replylist = msg.arguments();
85 const QVariant& reply = replylist.first();
86 m_cookie = reply.toUInt();
87 LOG(VB_GENERAL, LOG_INFO, LOC +
88 QString("Successfully inhibited screensaver via %1. cookie %2. nom nom")
89 .arg(m_serviceUsed).arg(m_cookie));
90 return;
91 }
92
93 // msg.type() == QDBusMessage::ErrorMessage
94 if (errout != nullptr)
95 {
96 *errout = msg.errorMessage();
97 }
98 else
99 {
100 LOG(VB_GENERAL, LOG_WARNING, LOC +
101 QString("Failed to disable screensaver via %1: %2")
102 .arg(m_serviceUsed, msg.errorMessage()));
103 }
104 }
105 }
107 {
108 if (m_interface->isValid())
109 {
110 // Don't block waiting for the reply, there isn't one
111 // method void org.freedesktop.ScreenSaver.UnInhibit(uint cookie) (or equivalent)
112 if (m_cookie != 0) {
113 m_interface->call(QDBus::NoBlock, m_unInhibit , m_cookie);
114 m_cookie = 0;
115 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Screensaver uninhibited via %1")
116 .arg(m_serviceUsed));
117 }
118 }
119 }
120 void SetUnInhibit(const QString &method) { m_unInhibit = method; }
121 bool isValid() const { return m_interface ? m_interface->isValid() : false; };
122
123 protected:
124 uint32_t m_cookie {0};
125 QDBusConnection *m_bus {nullptr};
126 QDBusInterface *m_interface {nullptr};
127 private:
128 // Disable copying and assignment
129 Q_DISABLE_COPY(ScreenSaverDBusPrivate)
130 QString m_unInhibit;
132};
133
135 : MythScreenSaver(Parent),
136 m_bus(QDBusConnection::sessionBus())
137{
138 // service, path, interface, bus - note that interface = service, hence it is used twice
139 for (size_t i=0; i < NUM_DBUS_METHODS; i++)
140 {
141 auto *ssdbp = new ScreenSaverDBusPrivate(kDbusService[i], kDbusPath[i], kDbusService[i], &m_bus);
142 if (!ssdbp->isValid())
143 {
144 delete ssdbp;
145 continue;
146 }
147 ssdbp->SetUnInhibit(kDbusUnInhibit[i]);
148
149 // Possible control. Does it work without error?
150 QString dbuserr;
151 ssdbp->Inhibit(&dbuserr);
152 ssdbp->UnInhibit();
153 if (!dbuserr.isEmpty())
154 {
155 LOG(VB_GENERAL, LOG_DEBUG, LOC +
156 QString("Error testing disable screensaver via %1: %2")
157 .arg(kDbusService[i], dbuserr));
158 delete ssdbp;
159 continue;
160 }
161 m_dbusPrivateInterfaces.push_back(ssdbp);
162 }
163}
164
166{
168 for (auto * interface : std::as_const(m_dbusPrivateInterfaces))
169 delete interface;
170}
171
173{
174 for (auto * interface : std::as_const(m_dbusPrivateInterfaces))
175 interface->Inhibit();
176}
177
179{
180 for (auto * interface : std::as_const(m_dbusPrivateInterfaces))
181 interface->UnInhibit();
182}
183
185{
186}
187
189{
190 return false;
191}
192
193#include "moc_mythscreensaverdbus.cpp"
QList< ScreenSaverDBusPrivate * > m_dbusPrivateInterfaces
Base Class for screensavers.
void SetUnInhibit(const QString &method)
void Inhibit(QString *errout=nullptr)
ScreenSaverDBusPrivate(const QString &dbusService, const QString &dbusPath, const QString &dbusInterface, QDBusConnection *bus)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
#define LOC
const std::string kReason
const std::array< const QString, NUM_DBUS_METHODS > kDbusPath
const std::array< const QString, NUM_DBUS_METHODS > kDbusService
KDE >= 4 and GNOME >= 3.10.
const std::string kDbusInhibit
const std::string kApp
const std::array< const QString, NUM_DBUS_METHODS > kDbusUnInhibit
static constexpr size_t NUM_DBUS_METHODS