File indexing completed on 2024-04-28 15:29:09
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2006 Aaron Seigo <aseigo@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "knotificationrestrictions.h" 0009 0010 #include <QApplication> 0011 #include <QDBusConnection> 0012 #include <QDBusMessage> 0013 #include <QDBusReply> 0014 0015 #include "debug_p.h" 0016 #include <config-knotifications.h> 0017 0018 #if HAVE_XTEST 0019 #include <QTimer> 0020 0021 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0022 #include <QX11Info> 0023 #endif 0024 0025 #include <X11/extensions/XTest.h> 0026 #include <X11/keysym.h> 0027 #endif // HAVE_XTEST 0028 0029 class Q_DECL_HIDDEN KNotificationRestrictions::Private 0030 { 0031 public: 0032 Private(KNotificationRestrictions *qq, Services c, const QString &r) 0033 : q(qq) 0034 , control(c) 0035 , screenSaverDbusCookie(-1) 0036 , reason(r) 0037 #if HAVE_XTEST 0038 , screensaverTimer(nullptr) 0039 , haveXTest(0) 0040 , XTestKeyCode(0) 0041 , isX11(QGuiApplication::platformName() == QLatin1String("xcb")) 0042 #endif // HAVE_XTEST 0043 { 0044 } 0045 0046 void screensaverFakeKeyEvent(); 0047 void startScreenSaverPrevention(); 0048 void stopScreenSaverPrevention(); 0049 0050 static QString determineProgramName(); 0051 0052 KNotificationRestrictions *q; 0053 Services control; 0054 int screenSaverDbusCookie; 0055 QString reason; 0056 #if HAVE_XTEST 0057 QTimer *screensaverTimer; 0058 int haveXTest; 0059 int XTestKeyCode; 0060 bool isX11; 0061 #endif // HAVE_XTEST 0062 }; 0063 0064 KNotificationRestrictions::KNotificationRestrictions(Services control, QObject *parent) 0065 : KNotificationRestrictions(control, QStringLiteral("no_reason_specified"), parent) 0066 { 0067 } 0068 0069 KNotificationRestrictions::KNotificationRestrictions(Services control, const QString &reason, QObject *parent) 0070 : QObject(parent) 0071 , d(new Private(this, control, reason)) 0072 { 0073 if (d->control & ScreenSaver) { 0074 d->startScreenSaverPrevention(); 0075 } 0076 } 0077 0078 KNotificationRestrictions::~KNotificationRestrictions() 0079 { 0080 if (d->control & ScreenSaver) { 0081 d->stopScreenSaverPrevention(); 0082 } 0083 } 0084 0085 void KNotificationRestrictions::Private::screensaverFakeKeyEvent() 0086 { 0087 qCDebug(LOG_KNOTIFICATIONS); 0088 #if HAVE_XTEST 0089 if (!isX11) { 0090 return; 0091 } 0092 qCDebug(LOG_KNOTIFICATIONS) << "---- using XTestFakeKeyEvent"; 0093 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0094 Display *display = QX11Info::display(); 0095 #else 0096 Display *display = qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->display(); 0097 #endif 0098 0099 XTestFakeKeyEvent(display, XTestKeyCode, true, CurrentTime); 0100 XTestFakeKeyEvent(display, XTestKeyCode, false, CurrentTime); 0101 XSync(display, false); 0102 #endif // HAVE_XTEST 0103 } 0104 0105 void KNotificationRestrictions::Private::startScreenSaverPrevention() 0106 { 0107 qCDebug(LOG_KNOTIFICATIONS); 0108 0109 QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.ScreenSaver"), 0110 QStringLiteral("/ScreenSaver"), 0111 QStringLiteral("org.freedesktop.ScreenSaver"), 0112 QStringLiteral("Inhibit")); 0113 message << determineProgramName(); 0114 message << reason; 0115 QDBusReply<uint> reply = QDBusConnection::sessionBus().call(message); 0116 if (reply.isValid()) { 0117 screenSaverDbusCookie = reply.value(); 0118 return; 0119 } 0120 #if HAVE_XTEST 0121 if (!isX11) { 0122 return; 0123 } 0124 0125 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0126 Display *display = QX11Info::display(); 0127 #else 0128 Display *display = qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->display(); 0129 #endif 0130 0131 if (!haveXTest) { 0132 int a; 0133 int b; 0134 int c; 0135 int e; 0136 haveXTest = XTestQueryExtension(display, &a, &b, &c, &e); 0137 0138 if (!haveXTest) { 0139 qCDebug(LOG_KNOTIFICATIONS) << "--- No XTEST!"; 0140 return; 0141 } 0142 } 0143 0144 if (!XTestKeyCode) { 0145 XTestKeyCode = XKeysymToKeycode(display, XK_Shift_L); 0146 0147 if (!XTestKeyCode) { 0148 qCDebug(LOG_KNOTIFICATIONS) << "--- No XKeyCode for XK_Shift_L!"; 0149 return; 0150 } 0151 } 0152 0153 if (!screensaverTimer) { 0154 screensaverTimer = new QTimer(q); 0155 connect(screensaverTimer, SIGNAL(timeout()), q, SLOT(screensaverFakeKeyEvent())); 0156 } 0157 0158 qCDebug(LOG_KNOTIFICATIONS) << "---- using XTest"; 0159 // send a fake event right away in case this got started after a period of 0160 // inactivity leading to the screensaver set to activate in <55s 0161 screensaverFakeKeyEvent(); 0162 screensaverTimer->start(55000); 0163 #endif // HAVE_XTEST 0164 } 0165 0166 void KNotificationRestrictions::Private::stopScreenSaverPrevention() 0167 { 0168 if (screenSaverDbusCookie != -1) { 0169 QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.ScreenSaver"), 0170 QStringLiteral("/ScreenSaver"), 0171 QStringLiteral("org.freedesktop.ScreenSaver"), 0172 QStringLiteral("UnInhibit")); 0173 message << static_cast<uint>(screenSaverDbusCookie); 0174 screenSaverDbusCookie = -1; 0175 if (QDBusConnection::sessionBus().send(message)) { 0176 return; 0177 } 0178 } 0179 #if HAVE_XTEST 0180 if (!isX11) { 0181 return; 0182 } 0183 delete screensaverTimer; 0184 screensaverTimer = nullptr; 0185 #endif // HAVE_XTEST 0186 } 0187 0188 QString KNotificationRestrictions::Private::determineProgramName() 0189 { 0190 QString appName = QGuiApplication::applicationDisplayName(); 0191 if (appName.isEmpty()) { 0192 appName = QCoreApplication::applicationName(); 0193 } 0194 if (appName.isEmpty()) { 0195 appName = tr("Unknown Application"); 0196 } 0197 return appName; 0198 } 0199 0200 #include "moc_knotificationrestrictions.cpp"