1 /********************************************************************
2  KSld - the KDE Screenlocker Daemon
3  This file is part of the KDE project.
4 
5  Copyright 1999 Martin R. Jones <mjones@kde.org>
6  Copyright 2003 Oswald Buddenhagen <ossi@kde.org>
7  Copyright 2008 Chani Armitage <chanika@gmail.com>
8  Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
9 
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 *********************************************************************/
23 #include "ksldapp.h"
24 #include "globalaccel.h"
25 #include "interface.h"
26 #include "kscreensaversettings.h"
27 #include "logind.h"
28 #include "powermanagement_inhibition.h"
29 #include "waylandlocker.h"
30 #include "x11locker.h"
31 
32 #include "kscreenlocker_logging.h"
33 #include <config-kscreenlocker.h>
34 
35 #include "waylandserver.h"
36 #include <config-X11.h>
37 // KDE
38 #include <KAuthorized>
39 #include <KGlobalAccel>
40 #include <KIdleTime>
41 #include <KLocalizedString>
42 #include <KNotification>
43 
44 // Qt
45 #include <QAction>
46 #include <QKeyEvent>
47 #include <QProcess>
48 #include <QTimer>
49 #include <QX11Info>
50 // X11
51 #include <X11/Xlib.h>
52 #include <xcb/xcb.h>
53 #ifdef X11_Xinput_FOUND
54 #include <X11/extensions/XInput2.h>
55 #endif
56 // other
57 #include <signal.h>
58 #include <unistd.h>
59 
60 #include <sys/socket.h>
61 #include <sys/types.h>
62 
63 namespace ScreenLocker
64 {
65 static const QString s_qtQuickBackend = QStringLiteral("QT_QUICK_BACKEND");
66 
67 static KSldApp *s_instance = nullptr;
68 
self()69 KSldApp *KSldApp::self()
70 {
71     if (!s_instance) {
72         s_instance = new KSldApp();
73     }
74 
75     return s_instance;
76 }
77 
KSldApp(QObject * parent)78 KSldApp::KSldApp(QObject *parent)
79     : QObject(parent)
80     , m_lockState(Unlocked)
81     , m_lockProcess(nullptr)
82     , m_lockWindow(nullptr)
83     , m_waylandServer(new WaylandServer(this))
84     , m_lockedTimer(QElapsedTimer())
85     , m_idleId(0)
86     , m_lockGrace(0)
87     , m_inGraceTime(false)
88     , m_graceTimer(new QTimer(this))
89     , m_inhibitCounter(0)
90     , m_logind(nullptr)
91     , m_greeterEnv(QProcessEnvironment::systemEnvironment())
92     , m_powerManagementInhibition(new PowerManagementInhibition(this))
93 {
94     m_isX11 = QX11Info::isPlatformX11();
95     m_isWayland = QCoreApplication::instance()->property("platformName").toString().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive);
96 }
97 
~KSldApp()98 KSldApp::~KSldApp()
99 {
100 }
101 
102 static int s_XTimeout;
103 static int s_XInterval;
104 static int s_XBlanking;
105 static int s_XExposures;
106 
cleanUp()107 void KSldApp::cleanUp()
108 {
109     if (m_lockProcess && m_lockProcess->state() != QProcess::NotRunning) {
110         m_lockProcess->terminate();
111     }
112     delete m_lockProcess;
113     delete m_lockWindow;
114 
115     // Restore X screensaver parameters
116     XSetScreenSaver(QX11Info::display(), s_XTimeout, s_XInterval, s_XBlanking, s_XExposures);
117 }
118 
119 static bool s_graceTimeKill = false;
120 static bool s_logindExit = false;
121 
hasXInput()122 static bool hasXInput()
123 {
124 #ifdef X11_Xinput_FOUND
125     Display *dpy = QX11Info::display();
126     int xi_opcode, event, error;
127     // init XInput extension
128     if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error)) {
129         return false;
130     }
131 
132     // verify that the XInput extension is at at least version 2.0
133     int major = 2, minor = 0;
134     int result = XIQueryVersion(dpy, &major, &minor);
135     if (result == BadImplementation) {
136         // Xinput 2.2 returns BadImplementation if checked against 2.0
137         major = 2;
138         minor = 2;
139         return XIQueryVersion(dpy, &major, &minor) == Success;
140     }
141     return result == Success;
142 #else
143     return false;
144 #endif
145 }
146 
initializeX11()147 void KSldApp::initializeX11()
148 {
149     m_hasXInput2 = hasXInput();
150     // Save X screensaver parameters
151     XGetScreenSaver(QX11Info::display(), &s_XTimeout, &s_XInterval, &s_XBlanking, &s_XExposures);
152     // And disable it. The internal X screensaver is not used at all, but we use its
153     // internal idle timer (and it is also used by DPMS support in X). This timer must not
154     // be altered by this code, since e.g. resetting the counter after activating our
155     // screensaver would prevent DPMS from activating. We use the timer merely to detect
156     // user activity.
157     XSetScreenSaver(QX11Info::display(), 0, s_XInterval, s_XBlanking, s_XExposures);
158 }
159 
initialize()160 void KSldApp::initialize()
161 {
162     if (m_isX11) {
163         initializeX11();
164     }
165 
166     // Global keys
167     if (KAuthorized::authorizeAction(QStringLiteral("lock_screen"))) {
168         qCDebug(KSCREENLOCKER) << "Configuring Lock Action";
169         QAction *a = new QAction(this);
170         a->setObjectName(QStringLiteral("Lock Session"));
171         a->setProperty("componentName", QStringLiteral("ksmserver"));
172         a->setText(i18n("Lock Session"));
173         KGlobalAccel::self()->setGlobalShortcut(a, KScreenSaverSettings::defaultShortcuts());
174         connect(a, &QAction::triggered, this, [this]() {
175             lock(EstablishLock::Immediate);
176         });
177     }
178 
179     // idle support
180     auto idleTimeSignal = static_cast<void (KIdleTime::*)(int)>(&KIdleTime::timeoutReached);
181     connect(KIdleTime::instance(), idleTimeSignal, this, [this](int identifier) {
182         if (identifier != m_idleId) {
183             // not our identifier
184             return;
185         }
186         if (lockState() != Unlocked) {
187             return;
188         }
189         if (m_inhibitCounter // either we got a direct inhibit request thru our outdated o.f.Screensaver iface ...
190             || isFdoPowerInhibited()) { // ... or the newer one at o.f.PowerManagement.Inhibit
191             // there is at least one process blocking the auto lock of screen locker
192             return;
193         }
194         if (m_lockGrace) { // short-circuit if grace time is zero
195             m_inGraceTime = true;
196         } else if (m_lockGrace == -1) {
197             m_inGraceTime = true; // if no timeout configured, grace time lasts forever
198         }
199 
200         lock(EstablishLock::Delayed);
201     });
202 
203     m_lockProcess = new QProcess();
204     m_lockProcess->setProcessChannelMode(QProcess::ForwardedErrorChannel);
205     m_lockProcess->setReadChannel(QProcess::StandardOutput);
206     auto finishedSignal = static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished);
207     connect(m_lockProcess, finishedSignal, this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
208         qCDebug(KSCREENLOCKER) << "Greeter process exitted with status:" << exitStatus << "exit code:" << exitCode;
209 
210         const bool regularExit = !exitCode && exitStatus == QProcess::NormalExit;
211         if (regularExit || s_graceTimeKill || s_logindExit) {
212             // unlock process finished successfully - we can remove the lock grab
213 
214             if (regularExit) {
215                 qCDebug(KSCREENLOCKER) << "Unlocking now on regular exit.";
216             } else if (s_graceTimeKill) {
217                 qCDebug(KSCREENLOCKER) << "Unlocking anyway due to grace time.";
218             } else {
219                 Q_ASSERT(s_logindExit);
220                 qCDebug(KSCREENLOCKER) << "Unlocking anyway since forced through logind.";
221             }
222 
223             s_graceTimeKill = false;
224             s_logindExit = false;
225             doUnlock();
226             return;
227         }
228 
229         qCWarning(KSCREENLOCKER) << "Greeter process exit unregular. Restarting lock.";
230 
231         m_greeterCrashedCounter++;
232         if (m_greeterCrashedCounter < 4) {
233             // Perhaps it crashed due to a graphics driver issue, force software rendering now
234             qCDebug(KSCREENLOCKER, "Trying to lock again with software rendering (%d/4).", m_greeterCrashedCounter);
235             setForceSoftwareRendering(true);
236             startLockProcess(EstablishLock::Immediate);
237         } else if (m_lockWindow) {
238             qCWarning(KSCREENLOCKER) << "Everything else failed. Need to put Greeter in emergency mode.";
239             m_lockWindow->emergencyShow();
240         } else {
241             qCCritical(KSCREENLOCKER) << "Greeter process exitted and we could in no way recover from that!";
242         }
243     });
244     connect(m_lockProcess, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
245         if (error == QProcess::FailedToStart) {
246             qCDebug(KSCREENLOCKER) << "Greeter Process  failed to start. Trying to directly unlock again.";
247             doUnlock();
248             m_waylandServer->stop();
249             qCCritical(KSCREENLOCKER) << "Greeter Process not available";
250         } else {
251             qCWarning(KSCREENLOCKER) << "Greeter Process encountered an unhandled error:" << error;
252         }
253     });
254     m_lockedTimer.invalidate();
255     m_graceTimer->setSingleShot(true);
256     connect(m_graceTimer, &QTimer::timeout, this, &KSldApp::endGraceTime);
257     // create our D-Bus interface
258     new Interface(this);
259 
260     // connect to logind
261     m_logind = new LogindIntegration(this);
262     connect(m_logind, &LogindIntegration::requestLock, this, [this]() {
263         lock(EstablishLock::Immediate);
264     });
265     connect(m_logind, &LogindIntegration::requestUnlock, this, [this]() {
266         if (lockState() == Locked || lockState() == AcquiringLock) {
267             if (m_lockProcess->state() != QProcess::NotRunning) {
268                 s_logindExit = true;
269                 m_lockProcess->terminate();
270             } else {
271                 doUnlock();
272             }
273         }
274     });
275     connect(m_logind, &LogindIntegration::prepareForSleep, this, [this](bool goingToSleep) {
276         if (!goingToSleep) {
277             // not interested in doing anything on wakeup
278             return;
279         }
280         if (KScreenSaverSettings::lockOnResume()) {
281             lock(EstablishLock::Immediate);
282         }
283     });
284     connect(m_logind, &LogindIntegration::inhibited, this, [this]() {
285         // if we are already locked, we immediately remove the inhibition lock
286         if (m_lockState == KSldApp::Locked) {
287             m_logind->uninhibit();
288         }
289     });
290     connect(m_logind, &LogindIntegration::connectedChanged, this, [this]() {
291         if (!m_logind->isConnected()) {
292             return;
293         }
294         if (m_lockState == ScreenLocker::KSldApp::Unlocked && KScreenSaverSettings::lockOnResume()) {
295             m_logind->inhibit();
296         }
297         if (m_logind->isLocked()) {
298             lock(EstablishLock::Immediate);
299         }
300     });
301     connect(this, &KSldApp::locked, this, [this]() {
302         m_logind->uninhibit();
303         m_logind->setLocked(true);
304         if (m_lockGrace > 0 && m_inGraceTime) {
305             m_graceTimer->start(m_lockGrace);
306         }
307     });
308     connect(this, &KSldApp::unlocked, this, [this]() {
309         m_logind->setLocked(false);
310         if (KScreenSaverSettings::lockOnResume()) {
311             m_logind->inhibit();
312         }
313     });
314 
315     m_globalAccel = new GlobalAccel(this);
316     connect(this, &KSldApp::locked, m_globalAccel, &GlobalAccel::prepare);
317     connect(this, &KSldApp::unlocked, m_globalAccel, &GlobalAccel::release);
318 
319     // fallback for non-logind systems:
320     // connect to signal emitted by Solid. This is emitted unconditionally also on logind enabled systems
321     // ksld ignores it in case logind is used
322     QDBusConnection::sessionBus().connect(QStringLiteral("org.kde.Solid.PowerManagement"),
323                                           QStringLiteral("/org/kde/Solid/PowerManagement/Actions/SuspendSession"),
324                                           QStringLiteral("org.kde.Solid.PowerManagement.Actions.SuspendSession"),
325                                           QStringLiteral("aboutToSuspend"),
326                                           this,
327                                           SLOT(solidSuspend()));
328 
329     configure();
330 
331     if (m_logind->isLocked()) {
332         lock(EstablishLock::Immediate);
333     }
334 }
335 
configure()336 void KSldApp::configure()
337 {
338     KScreenSaverSettings::self()->load();
339     // idle support
340     if (m_idleId) {
341         KIdleTime::instance()->removeIdleTimeout(m_idleId);
342         m_idleId = 0;
343     }
344     const int timeout = KScreenSaverSettings::timeout();
345     // screen saver enabled means there is an auto lock timer
346     // timeout > 0 is for backwards compatibility with old configs
347     if (KScreenSaverSettings::autolock() && timeout > 0) {
348         // timeout stored in minutes
349         m_idleId = KIdleTime::instance()->addIdleTimeout(timeout * 1000 * 60);
350     }
351     if (KScreenSaverSettings::lock()) {
352         // lockGrace is stored in seconds
353         m_lockGrace = KScreenSaverSettings::lockGrace() * 1000;
354     } else {
355         m_lockGrace = -1;
356     }
357     if (m_logind && m_logind->isConnected()) {
358         if (KScreenSaverSettings::lockOnResume() && !m_logind->isInhibited()) {
359             m_logind->inhibit();
360         } else if (!KScreenSaverSettings::lockOnResume() && m_logind->isInhibited()) {
361             m_logind->uninhibit();
362         }
363     }
364 }
365 
lock(EstablishLock establishLock,int attemptCount)366 void KSldApp::lock(EstablishLock establishLock, int attemptCount)
367 {
368     if (lockState() != Unlocked) {
369         // already locked or acquiring lock, no need to lock again
370         // but make sure it's really locked
371         endGraceTime();
372         if (establishLock == EstablishLock::Immediate) {
373             // signal the greeter to switch to immediateLock mode
374             kill(m_lockProcess->processId(), SIGUSR1);
375         }
376         return;
377     }
378 
379     if (attemptCount == 0) {
380         Q_EMIT aboutToLock();
381     }
382 
383     qCDebug(KSCREENLOCKER) << "lock called";
384     if (!establishGrab()) {
385         if (attemptCount < 3) {
386             qCWarning(KSCREENLOCKER) << "Could not establish screen lock. Trying again in 10ms";
387             QTimer::singleShot(10, this, [=]() {
388                 lock(establishLock, attemptCount + 1);
389             });
390         } else {
391             qCCritical(KSCREENLOCKER) << "Could not establish screen lock";
392         }
393         return;
394     }
395 
396     KNotification::event(QStringLiteral("locked"), i18n("Screen locked"), QPixmap(), nullptr, KNotification::CloseOnTimeout, QStringLiteral("ksmserver"));
397 
398     // blank the screen
399     showLockWindow();
400 
401     m_lockState = AcquiringLock;
402 
403     setForceSoftwareRendering(false);
404     // start unlock screen process
405     startLockProcess(establishLock);
406     Q_EMIT lockStateChanged();
407 }
408 
409 /*
410  * Forward declarations:
411  * Only called from KSldApp::establishGrab(). Using from somewhere else is incorrect usage!
412  **/
413 static bool grabKeyboard();
414 static bool grabMouse();
415 
416 class XServerGrabber
417 {
418 public:
XServerGrabber()419     XServerGrabber()
420     {
421         xcb_grab_server(QX11Info::connection());
422     }
~XServerGrabber()423     ~XServerGrabber()
424     {
425         xcb_ungrab_server(QX11Info::connection());
426         xcb_flush(QX11Info::connection());
427     }
428 };
429 
establishGrab()430 bool KSldApp::establishGrab()
431 {
432     if (m_isWayland) {
433         return m_waylandFd >= 0;
434     }
435     if (!m_isX11) {
436         return true;
437     }
438     XSync(QX11Info::display(), False);
439     XServerGrabber serverGrabber;
440     if (!grabKeyboard()) {
441         return false;
442     }
443 
444     if (!grabMouse()) {
445         XUngrabKeyboard(QX11Info::display(), CurrentTime);
446         XFlush(QX11Info::display());
447         return false;
448     }
449 
450 #ifdef X11_Xinput_FOUND
451     if (m_hasXInput2) {
452         // get all devices
453         Display *dpy = QX11Info::display();
454         int numMasters;
455         XIDeviceInfo *masters = XIQueryDevice(dpy, XIAllMasterDevices, &numMasters);
456         bool success = true;
457         for (int i = 0; i < numMasters; ++i) {
458             // ignoring core pointer and core keyboard as we already grabbed them
459             if (qstrcmp(masters[i].name, "Virtual core pointer") == 0) {
460                 continue;
461             }
462             if (qstrcmp(masters[i].name, "Virtual core keyboard") == 0) {
463                 continue;
464             }
465             XIEventMask mask;
466             uchar bitmask[] = {0, 0};
467             mask.deviceid = masters[i].deviceid;
468             mask.mask = bitmask;
469             mask.mask_len = sizeof(bitmask);
470             XISetMask(bitmask, XI_ButtonPress);
471             XISetMask(bitmask, XI_ButtonRelease);
472             XISetMask(bitmask, XI_Motion);
473             XISetMask(bitmask, XI_Enter);
474             XISetMask(bitmask, XI_Leave);
475             const int result = XIGrabDevice(dpy,
476                                             masters[i].deviceid,
477                                             QX11Info::appRootWindow(),
478                                             XCB_TIME_CURRENT_TIME,
479                                             XCB_CURSOR_NONE,
480                                             XIGrabModeAsync,
481                                             XIGrabModeAsync,
482                                             True,
483                                             &mask);
484             if (result != XIGrabSuccess) {
485                 success = false;
486                 break;
487             }
488         }
489         if (!success) {
490             // ungrab all devices again
491             for (int i = 0; i < numMasters; ++i) {
492                 XIUngrabDevice(dpy, masters[i].deviceid, XCB_TIME_CURRENT_TIME);
493             }
494             xcb_connection_t *c = QX11Info::connection();
495             xcb_ungrab_keyboard(c, XCB_CURRENT_TIME);
496             xcb_ungrab_pointer(c, XCB_CURRENT_TIME);
497         }
498         XIFreeDeviceInfo(masters);
499         XFlush(dpy);
500         return success;
501     }
502 #endif
503 
504     return true;
505 }
506 
grabKeyboard()507 static bool grabKeyboard()
508 {
509     int rv = XGrabKeyboard(QX11Info::display(), QX11Info::appRootWindow(), True, GrabModeAsync, GrabModeAsync, CurrentTime);
510 
511     return (rv == GrabSuccess);
512 }
513 
grabMouse()514 static bool grabMouse()
515 {
516 #define GRABEVENTS ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask
517     int rv = XGrabPointer(QX11Info::display(), QX11Info::appRootWindow(), True, GRABEVENTS, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
518 #undef GRABEVENTS
519 
520     return (rv == GrabSuccess);
521 }
522 
doUnlock()523 void KSldApp::doUnlock()
524 {
525     qCDebug(KSCREENLOCKER) << "Grab Released";
526     if (m_isX11) {
527         xcb_connection_t *c = QX11Info::connection();
528         xcb_ungrab_keyboard(c, XCB_CURRENT_TIME);
529         xcb_ungrab_pointer(c, XCB_CURRENT_TIME);
530         xcb_flush(c);
531 #ifdef X11_Xinput_FOUND
532         if (m_hasXInput2) {
533             // get all devices
534             Display *dpy = QX11Info::display();
535             int numMasters;
536             XIDeviceInfo *masters = XIQueryDevice(dpy, XIAllMasterDevices, &numMasters);
537             // ungrab all devices again
538             for (int i = 0; i < numMasters; ++i) {
539                 XIUngrabDevice(dpy, masters[i].deviceid, XCB_TIME_CURRENT_TIME);
540             }
541             XIFreeDeviceInfo(masters);
542             XFlush(dpy);
543         }
544 #endif
545     }
546     hideLockWindow();
547     // delete the window again, to get rid of event filter
548     delete m_lockWindow;
549     m_lockWindow = nullptr;
550     m_lockState = Unlocked;
551     m_lockedTimer.invalidate();
552     m_greeterCrashedCounter = 0;
553     endGraceTime();
554     m_waylandServer->stop();
555     KNotification::event(QStringLiteral("unlocked"), i18n("Screen unlocked"), QPixmap(), nullptr, KNotification::CloseOnTimeout, QStringLiteral("ksmserver"));
556     Q_EMIT unlocked();
557     Q_EMIT lockStateChanged();
558 }
559 
isFdoPowerInhibited() const560 bool KSldApp::isFdoPowerInhibited() const
561 {
562     return m_powerManagementInhibition->isInhibited();
563 }
564 
setWaylandFd(int fd)565 void KSldApp::setWaylandFd(int fd)
566 {
567     m_waylandFd = fd;
568 }
569 
startLockProcess(EstablishLock establishLock)570 void KSldApp::startLockProcess(EstablishLock establishLock)
571 {
572     QProcessEnvironment env = m_greeterEnv;
573 
574     if (m_isWayland && m_waylandFd >= 0) {
575         int socket = dup(m_waylandFd);
576         if (socket >= 0) {
577             env.insert(QStringLiteral("WAYLAND_SOCKET"), QString::number(socket));
578         }
579     }
580 
581     QStringList args;
582     if (establishLock == EstablishLock::Immediate) {
583         args << QStringLiteral("--immediateLock");
584     }
585     if (establishLock == EstablishLock::DefaultToSwitchUser) {
586         args << QStringLiteral("--immediateLock");
587         args << QStringLiteral("--switchuser");
588     }
589 
590     if (m_lockGrace > 0) {
591         args << QStringLiteral("--graceTime");
592         args << QString::number(m_lockGrace);
593     }
594     if (m_lockGrace == -1) {
595         args << QStringLiteral("--nolock");
596     }
597     if (m_forceSoftwareRendering) {
598         env.insert(s_qtQuickBackend, QStringLiteral("software"));
599     }
600 
601     // start the Wayland server
602     int fd = m_waylandServer->start();
603     if (fd == -1) {
604         qCWarning(KSCREENLOCKER) << "Could not start the Wayland server.";
605         Q_EMIT m_lockProcess->errorOccurred(QProcess::FailedToStart);
606         return;
607     }
608 
609     args << QStringLiteral("--ksldfd");
610     args << QString::number(fd);
611 
612     m_lockProcess->setProcessEnvironment(env);
613     m_lockProcess->start(QStringLiteral(KSCREENLOCKER_GREET_BIN), args);
614     close(fd);
615 }
616 
userActivity()617 void KSldApp::userActivity()
618 {
619     if (isGraceTime()) {
620         unlock();
621     }
622     if (m_lockWindow) {
623         m_lockWindow->userActivity();
624     }
625 }
626 
showLockWindow()627 void KSldApp::showLockWindow()
628 {
629     if (!m_lockWindow) {
630         if (m_isX11) {
631             m_lockWindow = new X11Locker(this);
632 
633             connect(
634                 m_lockWindow,
635                 &AbstractLocker::userActivity,
636                 m_lockWindow,
637                 [this]() {
638                     if (isGraceTime()) {
639                         unlock();
640                     }
641                 },
642                 Qt::QueuedConnection);
643         }
644 
645         if (m_isWayland) {
646             m_lockWindow = new WaylandLocker(this);
647         }
648         if (!m_lockWindow) {
649             return;
650         }
651         m_lockWindow->setGlobalAccel(m_globalAccel);
652 
653         connect(m_lockWindow, &AbstractLocker::lockWindowShown, this, &KSldApp::lockScreenShown);
654 
655         connect(m_waylandServer, &WaylandServer::x11WindowAdded, m_lockWindow, &AbstractLocker::addAllowedWindow);
656     }
657     m_lockWindow->showLockWindow();
658     if (m_isX11) {
659         XSync(QX11Info::display(), False);
660     }
661 }
662 
hideLockWindow()663 void KSldApp::hideLockWindow()
664 {
665     if (!m_lockWindow) {
666         return;
667     }
668     m_lockWindow->hideLockWindow();
669 }
670 
activeTime() const671 uint KSldApp::activeTime() const
672 {
673     if (m_lockedTimer.isValid()) {
674         return m_lockedTimer.elapsed();
675     }
676     return 0;
677 }
678 
isGraceTime() const679 bool KSldApp::isGraceTime() const
680 {
681     return m_inGraceTime;
682 }
683 
endGraceTime()684 void KSldApp::endGraceTime()
685 {
686     m_graceTimer->stop();
687     m_inGraceTime = false;
688 }
689 
unlock()690 void KSldApp::unlock()
691 {
692     if (!isGraceTime()) {
693         return;
694     }
695     s_graceTimeKill = true;
696     m_lockProcess->terminate();
697 }
698 
inhibit()699 void KSldApp::inhibit()
700 {
701     ++m_inhibitCounter;
702 }
703 
uninhibit()704 void KSldApp::uninhibit()
705 {
706     --m_inhibitCounter;
707 }
708 
solidSuspend()709 void KSldApp::solidSuspend()
710 {
711     // ignore in case that we use logind
712     if (m_logind && m_logind->isConnected()) {
713         return;
714     }
715     if (KScreenSaverSettings::lockOnResume()) {
716         lock(EstablishLock::Immediate);
717     }
718 }
719 
lockScreenShown()720 void KSldApp::lockScreenShown()
721 {
722     if (m_lockState == Locked) {
723         return;
724     }
725     m_lockState = Locked;
726     m_lockedTimer.restart();
727     Q_EMIT locked();
728     Q_EMIT lockStateChanged();
729 }
730 
setGreeterEnvironment(const QProcessEnvironment & env)731 void KSldApp::setGreeterEnvironment(const QProcessEnvironment &env)
732 {
733     m_greeterEnv = env;
734     if (m_isWayland) {
735         m_greeterEnv.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("wayland"));
736     }
737 }
738 
event(QEvent * event)739 bool KSldApp::event(QEvent *event)
740 {
741     if (event->type() == QEvent::KeyPress && m_globalAccel) {
742         if (m_globalAccel->keyEvent(static_cast<QKeyEvent *>(event))) {
743             event->setAccepted(true);
744         }
745     }
746     return false;
747 }
748 
749 } // namespace
750