File indexing completed on 2022-09-27 21:35:52

0001 /********************************************************************
0002  KSld - the KDE Screenlocker Daemon
0003  This file is part of the KDE project.
0004 
0005  Copyright 1999 Martin R. Jones <mjones@kde.org>
0006  Copyright 2003 Oswald Buddenhagen <ossi@kde.org>
0007  Copyright 2008 Chani Armitage <chanika@gmail.com>
0008  Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
0009 
0010 This program is free software; you can redistribute it and/or modify
0011 it under the terms of the GNU General Public License as published by
0012 the Free Software Foundation; either version 2 of the License, or
0013 (at your option) any later version.
0014 
0015 This program is distributed in the hope that it will be useful,
0016 but WITHOUT ANY WARRANTY; without even the implied warranty of
0017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0018 GNU General Public License for more details.
0019 
0020 You should have received a copy of the GNU General Public License
0021 along with this program.  If not, see <http://www.gnu.org/licenses/>.
0022 *********************************************************************/
0023 #include "ksldapp.h"
0024 #include "globalaccel.h"
0025 #include "interface.h"
0026 #include "kscreensaversettings.h"
0027 #include "logind.h"
0028 #include "powermanagement_inhibition.h"
0029 #include "waylandlocker.h"
0030 #include "x11locker.h"
0031 
0032 #include "kscreenlocker_logging.h"
0033 #include <config-kscreenlocker.h>
0034 
0035 #include "waylandserver.h"
0036 #include <config-X11.h>
0037 // KDE
0038 #include <KAuthorized>
0039 #include <KGlobalAccel>
0040 #include <KIdleTime>
0041 #include <KLibexec>
0042 #include <KLocalizedString>
0043 #include <KNotification>
0044 
0045 // Qt
0046 #include <QAction>
0047 #include <QKeyEvent>
0048 #include <QProcess>
0049 #include <QTimer>
0050 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0051 #include <private/qtx11extras_p.h>
0052 #else
0053 #include <QX11Info>
0054 #endif
0055 // X11
0056 #include <X11/Xlib.h>
0057 #include <xcb/xcb.h>
0058 #ifdef X11_Xinput_FOUND
0059 #include <X11/extensions/XInput2.h>
0060 #endif
0061 // other
0062 #include <signal.h>
0063 #include <unistd.h>
0064 
0065 #include <sys/socket.h>
0066 #include <sys/types.h>
0067 
0068 namespace ScreenLocker
0069 {
0070 static const QString s_qtQuickBackend = QStringLiteral("QT_QUICK_BACKEND");
0071 
0072 static KSldApp *s_instance = nullptr;
0073 
0074 KSldApp *KSldApp::self()
0075 {
0076     if (!s_instance) {
0077         s_instance = new KSldApp();
0078     }
0079 
0080     return s_instance;
0081 }
0082 
0083 KSldApp::KSldApp(QObject *parent)
0084     : QObject(parent)
0085     , m_lockState(Unlocked)
0086     , m_lockProcess(nullptr)
0087     , m_lockWindow(nullptr)
0088     , m_waylandServer(new WaylandServer(this))
0089     , m_lockedTimer(QElapsedTimer())
0090     , m_idleId(0)
0091     , m_lockGrace(0)
0092     , m_inGraceTime(false)
0093     , m_graceTimer(new QTimer(this))
0094     , m_inhibitCounter(0)
0095     , m_logind(nullptr)
0096     , m_greeterEnv(QProcessEnvironment::systemEnvironment())
0097     , m_powerManagementInhibition(new PowerManagementInhibition(this))
0098 {
0099     m_isX11 = QX11Info::isPlatformX11();
0100     m_isWayland = QCoreApplication::instance()->property("platformName").toString().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive);
0101 }
0102 
0103 KSldApp::~KSldApp()
0104 {
0105 }
0106 
0107 static int s_XTimeout;
0108 static int s_XInterval;
0109 static int s_XBlanking;
0110 static int s_XExposures;
0111 
0112 void KSldApp::cleanUp()
0113 {
0114     if (m_lockProcess && m_lockProcess->state() != QProcess::NotRunning) {
0115         m_lockProcess->terminate();
0116     }
0117     delete m_lockProcess;
0118     delete m_lockWindow;
0119 
0120     // Restore X screensaver parameters
0121     XSetScreenSaver(QX11Info::display(), s_XTimeout, s_XInterval, s_XBlanking, s_XExposures);
0122 }
0123 
0124 static bool s_graceTimeKill = false;
0125 static bool s_logindExit = false;
0126 
0127 static bool hasXInput()
0128 {
0129 #ifdef X11_Xinput_FOUND
0130     Display *dpy = QX11Info::display();
0131     int xi_opcode, event, error;
0132     // init XInput extension
0133     if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error)) {
0134         return false;
0135     }
0136 
0137     // verify that the XInput extension is at at least version 2.0
0138     int major = 2, minor = 0;
0139     int result = XIQueryVersion(dpy, &major, &minor);
0140     if (result == BadImplementation) {
0141         // Xinput 2.2 returns BadImplementation if checked against 2.0
0142         major = 2;
0143         minor = 2;
0144         return XIQueryVersion(dpy, &major, &minor) == Success;
0145     }
0146     return result == Success;
0147 #else
0148     return false;
0149 #endif
0150 }
0151 
0152 void KSldApp::initializeX11()
0153 {
0154     m_hasXInput2 = hasXInput();
0155     // Save X screensaver parameters
0156     XGetScreenSaver(QX11Info::display(), &s_XTimeout, &s_XInterval, &s_XBlanking, &s_XExposures);
0157     // And disable it. The internal X screensaver is not used at all, but we use its
0158     // internal idle timer (and it is also used by DPMS support in X). This timer must not
0159     // be altered by this code, since e.g. resetting the counter after activating our
0160     // screensaver would prevent DPMS from activating. We use the timer merely to detect
0161     // user activity.
0162     XSetScreenSaver(QX11Info::display(), 0, s_XInterval, s_XBlanking, s_XExposures);
0163 }
0164 
0165 void KSldApp::initialize()
0166 {
0167     if (m_isX11) {
0168         initializeX11();
0169     }
0170 
0171     // Global keys
0172     if (KAuthorized::authorizeAction(QStringLiteral("lock_screen"))) {
0173         qCDebug(KSCREENLOCKER) << "Configuring Lock Action";
0174         QAction *a = new QAction(this);
0175         a->setObjectName(QStringLiteral("Lock Session"));
0176         a->setProperty("componentName", QStringLiteral("ksmserver"));
0177         a->setText(i18n("Lock Session"));
0178         KGlobalAccel::self()->setGlobalShortcut(a, KScreenSaverSettings::defaultShortcuts());
0179         connect(a, &QAction::triggered, this, [this]() {
0180             lock(EstablishLock::Immediate);
0181         });
0182     }
0183 
0184     // idle support
0185     auto idleTimeSignal = static_cast<void (KIdleTime::*)(int, int)>(&KIdleTime::timeoutReached);
0186     connect(KIdleTime::instance(), idleTimeSignal, this, [this](int identifier) {
0187         if (identifier != m_idleId) {
0188             // not our identifier
0189             return;
0190         }
0191         if (lockState() != Unlocked) {
0192             return;
0193         }
0194         if (m_inhibitCounter // either we got a direct inhibit request thru our outdated o.f.Screensaver iface ...
0195             || isFdoPowerInhibited()) { // ... or the newer one at o.f.PowerManagement.Inhibit
0196             // there is at least one process blocking the auto lock of screen locker
0197             return;
0198         }
0199         if (m_lockGrace) { // short-circuit if grace time is zero
0200             m_inGraceTime = true;
0201         } else if (m_lockGrace == -1) {
0202             m_inGraceTime = true; // if no timeout configured, grace time lasts forever
0203         }
0204 
0205         lock(EstablishLock::Delayed);
0206     });
0207 
0208     m_lockProcess = new QProcess();
0209     m_lockProcess->setProcessChannelMode(QProcess::ForwardedErrorChannel);
0210     m_lockProcess->setReadChannel(QProcess::StandardOutput);
0211     auto finishedSignal = static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished);
0212     connect(m_lockProcess, finishedSignal, this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
0213         qCDebug(KSCREENLOCKER) << "Greeter process exitted with status:" << exitStatus << "exit code:" << exitCode;
0214 
0215         const bool regularExit = !exitCode && exitStatus == QProcess::NormalExit;
0216         if (regularExit || s_graceTimeKill || s_logindExit) {
0217             // unlock process finished successfully - we can remove the lock grab
0218 
0219             if (regularExit) {
0220                 qCDebug(KSCREENLOCKER) << "Unlocking now on regular exit.";
0221             } else if (s_graceTimeKill) {
0222                 qCDebug(KSCREENLOCKER) << "Unlocking anyway due to grace time.";
0223             } else {
0224                 Q_ASSERT(s_logindExit);
0225                 qCDebug(KSCREENLOCKER) << "Unlocking anyway since forced through logind.";
0226             }
0227 
0228             s_graceTimeKill = false;
0229             s_logindExit = false;
0230             doUnlock();
0231             return;
0232         }
0233 
0234         qCWarning(KSCREENLOCKER) << "Greeter process exit unregular. Restarting lock.";
0235 
0236         m_greeterCrashedCounter++;
0237         if (m_greeterCrashedCounter < 4) {
0238             // Perhaps it crashed due to a graphics driver issue, force software rendering now
0239             qCDebug(KSCREENLOCKER, "Trying to lock again with software rendering (%d/4).", m_greeterCrashedCounter);
0240             setForceSoftwareRendering(true);
0241             startLockProcess(EstablishLock::Immediate);
0242         } else if (m_lockWindow) {
0243             qCWarning(KSCREENLOCKER) << "Everything else failed. Need to put Greeter in emergency mode.";
0244             m_lockWindow->emergencyShow();
0245         } else {
0246             qCCritical(KSCREENLOCKER) << "Greeter process exitted and we could in no way recover from that!";
0247         }
0248     });
0249     connect(m_lockProcess, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
0250         if (error == QProcess::FailedToStart) {
0251             qCDebug(KSCREENLOCKER) << "Greeter Process  failed to start. Trying to directly unlock again.";
0252             doUnlock();
0253             m_waylandServer->stop();
0254             qCCritical(KSCREENLOCKER) << "Greeter Process not available";
0255         } else {
0256             qCWarning(KSCREENLOCKER) << "Greeter Process encountered an unhandled error:" << error;
0257         }
0258     });
0259     m_lockedTimer.invalidate();
0260     m_graceTimer->setSingleShot(true);
0261     connect(m_graceTimer, &QTimer::timeout, this, &KSldApp::endGraceTime);
0262     // create our D-Bus interface
0263     new Interface(this);
0264 
0265     // connect to logind
0266     m_logind = new LogindIntegration(this);
0267     connect(m_logind, &LogindIntegration::requestLock, this, [this]() {
0268         lock(EstablishLock::Immediate);
0269     });
0270     connect(m_logind, &LogindIntegration::requestUnlock, this, [this]() {
0271         if (lockState() == Locked || lockState() == AcquiringLock) {
0272             if (m_lockProcess->state() != QProcess::NotRunning) {
0273                 s_logindExit = true;
0274                 m_lockProcess->terminate();
0275             } else {
0276                 doUnlock();
0277             }
0278         }
0279     });
0280     connect(m_logind, &LogindIntegration::prepareForSleep, this, [this](bool goingToSleep) {
0281         if (!goingToSleep) {
0282             // not interested in doing anything on wakeup
0283             return;
0284         }
0285         if (KScreenSaverSettings::lockOnResume()) {
0286             lock(EstablishLock::Immediate);
0287         }
0288     });
0289     connect(m_logind, &LogindIntegration::inhibited, this, [this]() {
0290         // if we are already locked, we immediately remove the inhibition lock
0291         if (m_lockState == KSldApp::Locked) {
0292             m_logind->uninhibit();
0293         }
0294     });
0295     connect(m_logind, &LogindIntegration::connectedChanged, this, [this]() {
0296         if (!m_logind->isConnected()) {
0297             return;
0298         }
0299         if (m_lockState == ScreenLocker::KSldApp::Unlocked && KScreenSaverSettings::lockOnResume()) {
0300             m_logind->inhibit();
0301         }
0302         if (m_logind->isLocked()) {
0303             lock(EstablishLock::Immediate);
0304         }
0305     });
0306     connect(this, &KSldApp::locked, this, [this]() {
0307         m_logind->uninhibit();
0308         m_logind->setLocked(true);
0309         if (m_lockGrace > 0 && m_inGraceTime) {
0310             m_graceTimer->start(m_lockGrace);
0311         }
0312     });
0313     connect(this, &KSldApp::unlocked, this, [this]() {
0314         m_logind->setLocked(false);
0315         if (KScreenSaverSettings::lockOnResume()) {
0316             m_logind->inhibit();
0317         }
0318     });
0319 
0320     m_globalAccel = new GlobalAccel(this);
0321     connect(this, &KSldApp::locked, m_globalAccel, &GlobalAccel::prepare);
0322     connect(this, &KSldApp::unlocked, m_globalAccel, &GlobalAccel::release);
0323 
0324     // fallback for non-logind systems:
0325     // connect to signal emitted by Solid. This is emitted unconditionally also on logind enabled systems
0326     // ksld ignores it in case logind is used
0327     QDBusConnection::sessionBus().connect(QStringLiteral("org.kde.Solid.PowerManagement"),
0328                                           QStringLiteral("/org/kde/Solid/PowerManagement/Actions/SuspendSession"),
0329                                           QStringLiteral("org.kde.Solid.PowerManagement.Actions.SuspendSession"),
0330                                           QStringLiteral("aboutToSuspend"),
0331                                           this,
0332                                           SLOT(solidSuspend()));
0333 
0334     configure();
0335 
0336     if (m_logind->isLocked()) {
0337         lock(EstablishLock::Immediate);
0338     }
0339     if (KScreenSaverSettings::lockOnStart()) {
0340         lock(EstablishLock::Immediate);
0341     }
0342 }
0343 
0344 void KSldApp::configure()
0345 {
0346     KScreenSaverSettings::self()->load();
0347     // idle support
0348     if (m_idleId) {
0349         KIdleTime::instance()->removeIdleTimeout(m_idleId);
0350         m_idleId = 0;
0351     }
0352     const int timeout = KScreenSaverSettings::timeout();
0353     // screen saver enabled means there is an auto lock timer
0354     // timeout > 0 is for backwards compatibility with old configs
0355     if (KScreenSaverSettings::autolock() && timeout > 0) {
0356         // timeout stored in minutes
0357         m_idleId = KIdleTime::instance()->addIdleTimeout(timeout * 1000 * 60);
0358     }
0359     if (KScreenSaverSettings::lock()) {
0360         // lockGrace is stored in seconds
0361         m_lockGrace = KScreenSaverSettings::lockGrace() * 1000;
0362     } else {
0363         m_lockGrace = -1;
0364     }
0365     if (m_logind && m_logind->isConnected()) {
0366         if (KScreenSaverSettings::lockOnResume() && !m_logind->isInhibited()) {
0367             m_logind->inhibit();
0368         } else if (!KScreenSaverSettings::lockOnResume() && m_logind->isInhibited()) {
0369             m_logind->uninhibit();
0370         }
0371     }
0372 }
0373 
0374 void KSldApp::lock(EstablishLock establishLock, int attemptCount)
0375 {
0376     if (lockState() != Unlocked) {
0377         // already locked or acquiring lock, no need to lock again
0378         // but make sure it's really locked
0379         endGraceTime();
0380         if (establishLock == EstablishLock::Immediate) {
0381             // signal the greeter to switch to immediateLock mode
0382             kill(m_lockProcess->processId(), SIGUSR1);
0383         }
0384         return;
0385     }
0386 
0387     if (attemptCount == 0) {
0388         Q_EMIT aboutToLock();
0389     }
0390 
0391     qCDebug(KSCREENLOCKER) << "lock called";
0392     if (!establishGrab()) {
0393         if (attemptCount < 3) {
0394             qCWarning(KSCREENLOCKER) << "Could not establish screen lock. Trying again in 10ms";
0395             QTimer::singleShot(10, this, [=]() {
0396                 lock(establishLock, attemptCount + 1);
0397             });
0398         } else {
0399             qCCritical(KSCREENLOCKER) << "Could not establish screen lock";
0400         }
0401         return;
0402     }
0403 
0404     KNotification::event(QStringLiteral("locked"), i18n("Screen locked"), QPixmap(), nullptr, KNotification::CloseOnTimeout, QStringLiteral("ksmserver"));
0405 
0406     // blank the screen
0407     showLockWindow();
0408 
0409     m_lockState = AcquiringLock;
0410 
0411     setForceSoftwareRendering(false);
0412     // start unlock screen process
0413     startLockProcess(establishLock);
0414     Q_EMIT lockStateChanged();
0415 }
0416 
0417 /*
0418  * Forward declarations:
0419  * Only called from KSldApp::establishGrab(). Using from somewhere else is incorrect usage!
0420  **/
0421 static bool grabKeyboard();
0422 static bool grabMouse();
0423 
0424 class XServerGrabber
0425 {
0426 public:
0427     XServerGrabber()
0428     {
0429         xcb_grab_server(QX11Info::connection());
0430     }
0431     ~XServerGrabber()
0432     {
0433         xcb_ungrab_server(QX11Info::connection());
0434         xcb_flush(QX11Info::connection());
0435     }
0436 };
0437 
0438 bool KSldApp::establishGrab()
0439 {
0440     if (m_isWayland) {
0441         return m_waylandFd >= 0;
0442     }
0443     if (!m_isX11) {
0444         return true;
0445     }
0446     XSync(QX11Info::display(), False);
0447     XServerGrabber serverGrabber;
0448     if (!grabKeyboard()) {
0449         return false;
0450     }
0451 
0452     if (!grabMouse()) {
0453         XUngrabKeyboard(QX11Info::display(), CurrentTime);
0454         XFlush(QX11Info::display());
0455         return false;
0456     }
0457 
0458 #ifdef X11_Xinput_FOUND
0459     if (m_hasXInput2) {
0460         // get all devices
0461         Display *dpy = QX11Info::display();
0462         int numMasters;
0463         XIDeviceInfo *masters = XIQueryDevice(dpy, XIAllMasterDevices, &numMasters);
0464         bool success = true;
0465         for (int i = 0; i < numMasters; ++i) {
0466             // ignoring core pointer and core keyboard as we already grabbed them
0467             if (qstrcmp(masters[i].name, "Virtual core pointer") == 0) {
0468                 continue;
0469             }
0470             if (qstrcmp(masters[i].name, "Virtual core keyboard") == 0) {
0471                 continue;
0472             }
0473             XIEventMask mask;
0474             uchar bitmask[] = {0, 0};
0475             mask.deviceid = masters[i].deviceid;
0476             mask.mask = bitmask;
0477             mask.mask_len = sizeof(bitmask);
0478             XISetMask(bitmask, XI_ButtonPress);
0479             XISetMask(bitmask, XI_ButtonRelease);
0480             XISetMask(bitmask, XI_Motion);
0481             XISetMask(bitmask, XI_Enter);
0482             XISetMask(bitmask, XI_Leave);
0483             const int result = XIGrabDevice(dpy,
0484                                             masters[i].deviceid,
0485                                             QX11Info::appRootWindow(),
0486                                             XCB_TIME_CURRENT_TIME,
0487                                             XCB_CURSOR_NONE,
0488                                             XIGrabModeAsync,
0489                                             XIGrabModeAsync,
0490                                             True,
0491                                             &mask);
0492             if (result != XIGrabSuccess) {
0493                 success = false;
0494                 break;
0495             }
0496         }
0497         if (!success) {
0498             // ungrab all devices again
0499             for (int i = 0; i < numMasters; ++i) {
0500                 XIUngrabDevice(dpy, masters[i].deviceid, XCB_TIME_CURRENT_TIME);
0501             }
0502             xcb_connection_t *c = QX11Info::connection();
0503             xcb_ungrab_keyboard(c, XCB_CURRENT_TIME);
0504             xcb_ungrab_pointer(c, XCB_CURRENT_TIME);
0505         }
0506         XIFreeDeviceInfo(masters);
0507         XFlush(dpy);
0508         return success;
0509     }
0510 #endif
0511 
0512     return true;
0513 }
0514 
0515 static bool grabKeyboard()
0516 {
0517     int rv = XGrabKeyboard(QX11Info::display(), QX11Info::appRootWindow(), True, GrabModeAsync, GrabModeAsync, CurrentTime);
0518 
0519     return (rv == GrabSuccess);
0520 }
0521 
0522 static bool grabMouse()
0523 {
0524 #define GRABEVENTS ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask
0525     int rv = XGrabPointer(QX11Info::display(), QX11Info::appRootWindow(), True, GRABEVENTS, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
0526 #undef GRABEVENTS
0527 
0528     return (rv == GrabSuccess);
0529 }
0530 
0531 void KSldApp::doUnlock()
0532 {
0533     qCDebug(KSCREENLOCKER) << "Grab Released";
0534     if (m_isX11) {
0535         xcb_connection_t *c = QX11Info::connection();
0536         xcb_ungrab_keyboard(c, XCB_CURRENT_TIME);
0537         xcb_ungrab_pointer(c, XCB_CURRENT_TIME);
0538         xcb_flush(c);
0539 #ifdef X11_Xinput_FOUND
0540         if (m_hasXInput2) {
0541             // get all devices
0542             Display *dpy = QX11Info::display();
0543             int numMasters;
0544             XIDeviceInfo *masters = XIQueryDevice(dpy, XIAllMasterDevices, &numMasters);
0545             // ungrab all devices again
0546             for (int i = 0; i < numMasters; ++i) {
0547                 XIUngrabDevice(dpy, masters[i].deviceid, XCB_TIME_CURRENT_TIME);
0548             }
0549             XIFreeDeviceInfo(masters);
0550             XFlush(dpy);
0551         }
0552 #endif
0553     }
0554     hideLockWindow();
0555     // delete the window again, to get rid of event filter
0556     delete m_lockWindow;
0557     m_lockWindow = nullptr;
0558     m_lockState = Unlocked;
0559     m_lockedTimer.invalidate();
0560     m_greeterCrashedCounter = 0;
0561     endGraceTime();
0562     m_waylandServer->stop();
0563     KNotification::event(QStringLiteral("unlocked"), i18n("Screen unlocked"), QPixmap(), nullptr, KNotification::CloseOnTimeout, QStringLiteral("ksmserver"));
0564     Q_EMIT unlocked();
0565     Q_EMIT lockStateChanged();
0566 }
0567 
0568 bool KSldApp::isFdoPowerInhibited() const
0569 {
0570     return m_powerManagementInhibition->isInhibited();
0571 }
0572 
0573 void KSldApp::setWaylandFd(int fd)
0574 {
0575     m_waylandFd = fd;
0576 }
0577 
0578 void KSldApp::startLockProcess(EstablishLock establishLock)
0579 {
0580     QProcessEnvironment env = m_greeterEnv;
0581 
0582     if (m_isWayland && m_waylandFd >= 0) {
0583         int socket = dup(m_waylandFd);
0584         if (socket >= 0) {
0585             env.insert(QStringLiteral("WAYLAND_SOCKET"), QString::number(socket));
0586         }
0587     }
0588 
0589     QStringList args;
0590     if (establishLock == EstablishLock::Immediate) {
0591         args << QStringLiteral("--immediateLock");
0592     }
0593     if (establishLock == EstablishLock::DefaultToSwitchUser) {
0594         args << QStringLiteral("--immediateLock");
0595         args << QStringLiteral("--switchuser");
0596     }
0597 
0598     if (m_lockGrace > 0) {
0599         args << QStringLiteral("--graceTime");
0600         args << QString::number(m_lockGrace);
0601     }
0602     if (m_lockGrace == -1) {
0603         args << QStringLiteral("--nolock");
0604     }
0605     if (m_forceSoftwareRendering) {
0606         env.insert(s_qtQuickBackend, QStringLiteral("software"));
0607     }
0608 
0609     // start the Wayland server
0610     int fd = m_waylandServer->start();
0611     if (fd == -1) {
0612         qCWarning(KSCREENLOCKER) << "Could not start the Wayland server.";
0613         Q_EMIT m_lockProcess->errorOccurred(QProcess::FailedToStart);
0614         return;
0615     }
0616 
0617     args << QStringLiteral("--ksldfd");
0618     args << QString::number(fd);
0619 
0620     auto greeterPath = KLibexec::path(QStringLiteral(KSCREENLOCKER_GREET_BIN_REL));
0621     if (!QFile::exists(greeterPath)) {
0622         greeterPath = KSCREENLOCKER_GREET_BIN_ABS;
0623     }
0624 
0625     m_lockProcess->setProcessEnvironment(env);
0626     m_lockProcess->start(greeterPath, args);
0627     close(fd);
0628 }
0629 
0630 void KSldApp::userActivity()
0631 {
0632     if (isGraceTime()) {
0633         unlock();
0634     }
0635     if (m_lockWindow) {
0636         m_lockWindow->userActivity();
0637     }
0638 }
0639 
0640 void KSldApp::showLockWindow()
0641 {
0642     if (!m_lockWindow) {
0643         if (m_isX11) {
0644             m_lockWindow = new X11Locker(this);
0645 
0646             connect(
0647                 m_lockWindow,
0648                 &AbstractLocker::userActivity,
0649                 m_lockWindow,
0650                 [this]() {
0651                     if (isGraceTime()) {
0652                         unlock();
0653                     }
0654                 },
0655                 Qt::QueuedConnection);
0656         }
0657 
0658         if (m_isWayland) {
0659             m_lockWindow = new WaylandLocker(this);
0660         }
0661         if (!m_lockWindow) {
0662             return;
0663         }
0664         m_lockWindow->setGlobalAccel(m_globalAccel);
0665 
0666         connect(m_lockWindow, &AbstractLocker::lockWindowShown, this, &KSldApp::lockScreenShown);
0667 
0668         connect(m_waylandServer, &WaylandServer::x11WindowAdded, m_lockWindow, &AbstractLocker::addAllowedWindow);
0669     }
0670     m_lockWindow->showLockWindow();
0671     if (m_isX11) {
0672         XSync(QX11Info::display(), False);
0673     }
0674 }
0675 
0676 void KSldApp::hideLockWindow()
0677 {
0678     if (!m_lockWindow) {
0679         return;
0680     }
0681     m_lockWindow->hideLockWindow();
0682 }
0683 
0684 uint KSldApp::activeTime() const
0685 {
0686     if (m_lockedTimer.isValid()) {
0687         return m_lockedTimer.elapsed();
0688     }
0689     return 0;
0690 }
0691 
0692 bool KSldApp::isGraceTime() const
0693 {
0694     return m_inGraceTime;
0695 }
0696 
0697 void KSldApp::endGraceTime()
0698 {
0699     m_graceTimer->stop();
0700     m_inGraceTime = false;
0701 }
0702 
0703 void KSldApp::unlock()
0704 {
0705     if (!isGraceTime()) {
0706         return;
0707     }
0708     s_graceTimeKill = true;
0709     m_lockProcess->terminate();
0710 }
0711 
0712 void KSldApp::inhibit()
0713 {
0714     ++m_inhibitCounter;
0715 }
0716 
0717 void KSldApp::uninhibit()
0718 {
0719     --m_inhibitCounter;
0720 }
0721 
0722 void KSldApp::solidSuspend()
0723 {
0724     // ignore in case that we use logind
0725     if (m_logind && m_logind->isConnected()) {
0726         return;
0727     }
0728     if (KScreenSaverSettings::lockOnResume()) {
0729         lock(EstablishLock::Immediate);
0730     }
0731 }
0732 
0733 void KSldApp::lockScreenShown()
0734 {
0735     if (m_lockState == Locked) {
0736         return;
0737     }
0738     m_lockState = Locked;
0739     m_lockedTimer.restart();
0740     Q_EMIT locked();
0741     Q_EMIT lockStateChanged();
0742 }
0743 
0744 void KSldApp::setGreeterEnvironment(const QProcessEnvironment &env)
0745 {
0746     m_greeterEnv = env;
0747     if (m_isWayland) {
0748         m_greeterEnv.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("wayland"));
0749     }
0750 }
0751 
0752 bool KSldApp::event(QEvent *event)
0753 {
0754     if (event->type() == QEvent::KeyPress && m_globalAccel) {
0755         if (m_globalAccel->keyEvent(static_cast<QKeyEvent *>(event))) {
0756             event->setAccepted(true);
0757         }
0758     }
0759     return false;
0760 }
0761 
0762 } // namespace