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