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"