1 | /* This file is part of the KDE libraries |
2 | Copyright (C) 2006 Aaron Seigo <aseigo@kde.org> |
3 | |
4 | This library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Library General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2 of the License, or (at your option) any later version. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Library General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Library General Public License |
15 | along with this library; see the file COPYING.LIB. If not, write to |
16 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | Boston, MA 02110-1301, USA. |
18 | */ |
19 | |
20 | #include "knotificationrestrictions.h" |
21 | |
22 | #include <QApplication> |
23 | #include <QDBusConnection> |
24 | #include <QDBusMessage> |
25 | #include <QDBusReply> |
26 | |
27 | #include <config-knotifications.h> |
28 | #include "debug_p.h" |
29 | |
30 | #if HAVE_XTEST |
31 | #include <QTimer> |
32 | #include <QX11Info> |
33 | |
34 | #include <X11/keysym.h> |
35 | #include <X11/extensions/XTest.h> |
36 | #endif // HAVE_XTEST |
37 | |
38 | class Q_DECL_HIDDEN KNotificationRestrictions::Private |
39 | { |
40 | public: |
41 | Private(KNotificationRestrictions *qq, Services c, const QString &r) |
42 | : q(qq), |
43 | control(c) |
44 | , screenSaverDbusCookie(-1) |
45 | , reason(r) |
46 | #if HAVE_XTEST |
47 | , screensaverTimer(nullptr), |
48 | haveXTest(0), |
49 | XTestKeyCode(0), |
50 | isX11(QX11Info::isPlatformX11()) |
51 | #endif // HAVE_XTEST |
52 | { |
53 | } |
54 | |
55 | void screensaverFakeKeyEvent(); |
56 | void startScreenSaverPrevention(); |
57 | void stopScreenSaverPrevention(); |
58 | |
59 | static QString determineProgramName(); |
60 | |
61 | KNotificationRestrictions *q; |
62 | Services control; |
63 | int screenSaverDbusCookie; |
64 | QString reason; |
65 | #if HAVE_XTEST |
66 | QTimer *screensaverTimer; |
67 | int haveXTest; |
68 | int XTestKeyCode; |
69 | bool isX11; |
70 | #endif // HAVE_XTEST |
71 | }; |
72 | |
73 | KNotificationRestrictions::KNotificationRestrictions(Services control, |
74 | QObject *parent) |
75 | : KNotificationRestrictions(control, QStringLiteral("no_reason_specified" ), parent) |
76 | { |
77 | } |
78 | |
79 | KNotificationRestrictions::KNotificationRestrictions(Services control, |
80 | const QString &reason, |
81 | QObject *parent) |
82 | : QObject(parent), |
83 | d(new Private(this, control, reason)) |
84 | { |
85 | if (d->control & ScreenSaver) { |
86 | d->startScreenSaverPrevention(); |
87 | } |
88 | } |
89 | |
90 | KNotificationRestrictions::~KNotificationRestrictions() |
91 | { |
92 | if (d->control & ScreenSaver) { |
93 | d->stopScreenSaverPrevention(); |
94 | } |
95 | |
96 | delete d; |
97 | } |
98 | |
99 | void KNotificationRestrictions::Private::screensaverFakeKeyEvent() |
100 | { |
101 | qCDebug(LOG_KNOTIFICATIONS); |
102 | #if HAVE_XTEST |
103 | if (!isX11) { |
104 | return; |
105 | } |
106 | qCDebug(LOG_KNOTIFICATIONS) << "---- using XTestFakeKeyEvent" ; |
107 | Display *display = QX11Info::display(); |
108 | XTestFakeKeyEvent(display, XTestKeyCode, true, CurrentTime); |
109 | XTestFakeKeyEvent(display, XTestKeyCode, false, CurrentTime); |
110 | XSync(display, false); |
111 | #endif // HAVE_XTEST |
112 | } |
113 | |
114 | void KNotificationRestrictions::Private::startScreenSaverPrevention() |
115 | { |
116 | qCDebug(LOG_KNOTIFICATIONS); |
117 | |
118 | QDBusMessage message = QDBusMessage::createMethodCall( |
119 | QStringLiteral("org.freedesktop.ScreenSaver" ), QStringLiteral("/ScreenSaver" ), QStringLiteral("org.freedesktop.ScreenSaver" ), QStringLiteral("Inhibit" )); |
120 | message << determineProgramName(); |
121 | message << reason; |
122 | QDBusReply<uint> reply = QDBusConnection::sessionBus().call(message); |
123 | if (reply.isValid()) { |
124 | screenSaverDbusCookie = reply.value(); |
125 | return; |
126 | } |
127 | #if HAVE_XTEST |
128 | if (!isX11) { |
129 | return; |
130 | } |
131 | if (!haveXTest) { |
132 | int a, b, c, e; |
133 | haveXTest = XTestQueryExtension(QX11Info::display(), &a, &b, &c, &e); |
134 | |
135 | if (!haveXTest) { |
136 | qCDebug(LOG_KNOTIFICATIONS) << "--- No XTEST!" ; |
137 | return; |
138 | } |
139 | } |
140 | |
141 | if (!XTestKeyCode) { |
142 | XTestKeyCode = XKeysymToKeycode(QX11Info::display(), XK_Shift_L); |
143 | |
144 | if (!XTestKeyCode) { |
145 | qCDebug(LOG_KNOTIFICATIONS) << "--- No XKeyCode for XK_Shift_L!" ; |
146 | return; |
147 | } |
148 | } |
149 | |
150 | if (!screensaverTimer) { |
151 | screensaverTimer = new QTimer(q); |
152 | connect(screensaverTimer, SIGNAL(timeout()), |
153 | q, SLOT(screensaverFakeKeyEvent())); |
154 | } |
155 | |
156 | qCDebug(LOG_KNOTIFICATIONS) << "---- using XTest" ; |
157 | // send a fake event right away in case this got started after a period of |
158 | // inactivity leading to the screensaver set to activate in <55s |
159 | screensaverFakeKeyEvent(); |
160 | screensaverTimer->start(55000); |
161 | #endif // HAVE_XTEST |
162 | } |
163 | |
164 | void KNotificationRestrictions::Private::stopScreenSaverPrevention() |
165 | { |
166 | |
167 | if (screenSaverDbusCookie != -1) { |
168 | QDBusMessage message = QDBusMessage::createMethodCall( |
169 | QStringLiteral("org.freedesktop.ScreenSaver" ), QStringLiteral("/ScreenSaver" ), QStringLiteral("org.freedesktop.ScreenSaver" ), QStringLiteral("UnInhibit" )); |
170 | message << static_cast<uint>(screenSaverDbusCookie); |
171 | screenSaverDbusCookie = -1; |
172 | if (QDBusConnection::sessionBus().send(message)) { |
173 | return; |
174 | } |
175 | } |
176 | #if HAVE_XTEST |
177 | if (!isX11) { |
178 | return; |
179 | } |
180 | delete screensaverTimer; |
181 | screensaverTimer = nullptr; |
182 | #endif // HAVE_XTEST |
183 | } |
184 | |
185 | QString KNotificationRestrictions::Private::determineProgramName() |
186 | { |
187 | QString appName = QGuiApplication::applicationDisplayName(); |
188 | if (appName.isEmpty()) { |
189 | appName = QCoreApplication::applicationName(); |
190 | } |
191 | if (appName.isEmpty()) { |
192 | appName = tr("Unknown Application" ); |
193 | } |
194 | return appName; |
195 | } |
196 | |
197 | #include "moc_knotificationrestrictions.cpp" |
198 | |