File indexing completed on 2022-07-03 16:55:24

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