KNotifications

knotificationrestrictions.cpp
1 /*
2  This file is part of the KDE libraries
3  SPDX-FileCopyrightText: 2006 Aaron Seigo <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #include "knotificationrestrictions.h"
9 
10 #include <QApplication>
11 #include <QDBusConnection>
12 #include <QDBusMessage>
13 #include <QDBusReply>
14 
15 #include "debug_p.h"
16 #include <config-knotifications.h>
17 
18 #if HAVE_XTEST
19 #include <QTimer>
20 
21 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
22 #include <QX11Info>
23 #endif
24 
25 #include <X11/extensions/XTest.h>
26 #include <X11/keysym.h>
27 #endif // HAVE_XTEST
28 
29 class Q_DECL_HIDDEN KNotificationRestrictions::Private
30 {
31 public:
32  Private(KNotificationRestrictions *qq, Services c, const QString &r)
33  : q(qq)
34  , control(c)
35  , screenSaverDbusCookie(-1)
36  , reason(r)
37 #if HAVE_XTEST
38  , screensaverTimer(nullptr)
39  , haveXTest(0)
40  , XTestKeyCode(0)
41  , isX11(QGuiApplication::platformName() == QLatin1String("xcb"))
42 #endif // HAVE_XTEST
43  {
44  }
45 
46  void screensaverFakeKeyEvent();
47  void startScreenSaverPrevention();
48  void stopScreenSaverPrevention();
49 
50  static QString determineProgramName();
51 
53  Services control;
54  int screenSaverDbusCookie;
55  QString reason;
56 #if HAVE_XTEST
57  QTimer *screensaverTimer;
58  int haveXTest;
59  int XTestKeyCode;
60  bool isX11;
61 #endif // HAVE_XTEST
62 };
63 
65  : KNotificationRestrictions(control, QStringLiteral("no_reason_specified"), parent)
66 {
67 }
68 
70  : QObject(parent)
71  , d(new Private(this, control, reason))
72 {
73  if (d->control & ScreenSaver) {
74  d->startScreenSaverPrevention();
75  }
76 }
77 
78 KNotificationRestrictions::~KNotificationRestrictions()
79 {
80  if (d->control & ScreenSaver) {
81  d->stopScreenSaverPrevention();
82  }
83 }
84 
85 void KNotificationRestrictions::Private::screensaverFakeKeyEvent()
86 {
87  qCDebug(LOG_KNOTIFICATIONS);
88 #if HAVE_XTEST
89  if (!isX11) {
90  return;
91  }
92  qCDebug(LOG_KNOTIFICATIONS) << "---- using XTestFakeKeyEvent";
93 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
94  Display *display = QX11Info::display();
95 #else
96  Display *display = qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->display();
97 #endif
98 
99  XTestFakeKeyEvent(display, XTestKeyCode, true, CurrentTime);
100  XTestFakeKeyEvent(display, XTestKeyCode, false, CurrentTime);
101  XSync(display, false);
102 #endif // HAVE_XTEST
103 }
104 
105 void KNotificationRestrictions::Private::startScreenSaverPrevention()
106 {
107  qCDebug(LOG_KNOTIFICATIONS);
108 
109  QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.ScreenSaver"),
110  QStringLiteral("/ScreenSaver"),
111  QStringLiteral("org.freedesktop.ScreenSaver"),
112  QStringLiteral("Inhibit"));
113  message << determineProgramName();
114  message << reason;
116  if (reply.isValid()) {
117  screenSaverDbusCookie = reply.value();
118  return;
119  }
120 #if HAVE_XTEST
121  if (!isX11) {
122  return;
123  }
124 
125 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
126  Display *display = QX11Info::display();
127 #else
128  Display *display = qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->display();
129 #endif
130 
131  if (!haveXTest) {
132  int a;
133  int b;
134  int c;
135  int e;
136  haveXTest = XTestQueryExtension(display, &a, &b, &c, &e);
137 
138  if (!haveXTest) {
139  qCDebug(LOG_KNOTIFICATIONS) << "--- No XTEST!";
140  return;
141  }
142  }
143 
144  if (!XTestKeyCode) {
145  XTestKeyCode = XKeysymToKeycode(display, XK_Shift_L);
146 
147  if (!XTestKeyCode) {
148  qCDebug(LOG_KNOTIFICATIONS) << "--- No XKeyCode for XK_Shift_L!";
149  return;
150  }
151  }
152 
153  if (!screensaverTimer) {
154  screensaverTimer = new QTimer(q);
155  connect(screensaverTimer, SIGNAL(timeout()), q, SLOT(screensaverFakeKeyEvent()));
156  }
157 
158  qCDebug(LOG_KNOTIFICATIONS) << "---- using XTest";
159  // send a fake event right away in case this got started after a period of
160  // inactivity leading to the screensaver set to activate in <55s
161  screensaverFakeKeyEvent();
162  screensaverTimer->start(55000);
163 #endif // HAVE_XTEST
164 }
165 
166 void KNotificationRestrictions::Private::stopScreenSaverPrevention()
167 {
168  if (screenSaverDbusCookie != -1) {
169  QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.ScreenSaver"),
170  QStringLiteral("/ScreenSaver"),
171  QStringLiteral("org.freedesktop.ScreenSaver"),
172  QStringLiteral("UnInhibit"));
173  message << static_cast<uint>(screenSaverDbusCookie);
174  screenSaverDbusCookie = -1;
175  if (QDBusConnection::sessionBus().send(message)) {
176  return;
177  }
178  }
179 #if HAVE_XTEST
180  if (!isX11) {
181  return;
182  }
183  delete screensaverTimer;
184  screensaverTimer = nullptr;
185 #endif // HAVE_XTEST
186 }
187 
188 QString KNotificationRestrictions::Private::determineProgramName()
189 {
191  if (appName.isEmpty()) {
193  }
194  if (appName.isEmpty()) {
195  appName = tr("Unknown Application");
196  }
197  return appName;
198 }
199 
200 #include "moc_knotificationrestrictions.cpp"
bool isValid() const const
QDBusMessage call(const QDBusMessage &message, QDBus::CallMode mode, int timeout) const const
KNotificationRestrictions(Services control=NonCriticalServices, QObject *parent=nullptr)
Constructs a new service for restrict some services.
QDBusConnection sessionBus()
bool isEmpty() const const
QCA_EXPORT QString appName()
QDBusMessage createMethodCall(const QString &service, const QString &path, const QString &interface, const QString &method)
@ ScreenSaver
Causes the screensaver to be prevented from automatically turning on.
QString message
QDBusReply::Type value() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon May 8 2023 03:49:15 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.