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