File indexing completed on 2024-04-28 09:22:04

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