You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
669 lines
20 KiB
669 lines
20 KiB
/******************************************************************** |
|
KSld - the KDE Screenlocker Daemon |
|
This file is part of the KDE project. |
|
|
|
Copyright 1999 Martin R. Jones <mjones@kde.org> |
|
Copyright 2003 Oswald Buddenhagen <ossi@kde.org> |
|
Copyright 2008 Chani Armitage <chanika@gmail.com> |
|
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org> |
|
|
|
This program is free software; you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation; either version 2 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
*********************************************************************/ |
|
#include "ksldapp.h" |
|
#include "interface.h" |
|
#include "globalaccel.h" |
|
#include "x11locker.h" |
|
#include "waylandlocker.h" |
|
#include "logind.h" |
|
#include "kscreensaversettings.h" |
|
#include <config-kscreenlocker.h> |
|
#include <config-X11.h> |
|
#include "waylandserver.h" |
|
// KDE |
|
#include <KActionCollection> |
|
#include <KAuthorized> |
|
#include <KIdleTime> |
|
#include <KLocalizedString> |
|
#include <KNotification> |
|
#include <KGlobalAccel> |
|
#include <KCrash> |
|
// Qt |
|
#include <QAction> |
|
#include <QTimer> |
|
#include <QProcess> |
|
#include <QX11Info> |
|
#include <QDBusReply> |
|
#include <QGuiApplication> |
|
// X11 |
|
#include <X11/Xlib.h> |
|
#include <xcb/xcb.h> |
|
#ifdef X11_Xinput_FOUND |
|
#include <X11/extensions/XInput2.h> |
|
#endif |
|
// other |
|
#include <unistd.h> |
|
#include <signal.h> |
|
|
|
namespace ScreenLocker |
|
{ |
|
|
|
static KSldApp * s_instance = 0; |
|
|
|
KSldApp* KSldApp::self() |
|
{ |
|
if (!s_instance) { |
|
s_instance = new KSldApp(); |
|
} |
|
|
|
return s_instance; |
|
} |
|
|
|
KSldApp::KSldApp(QObject * parent) |
|
: QObject(parent) |
|
, m_actionCollection(NULL) |
|
, m_lockState(Unlocked) |
|
, m_lockProcess(NULL) |
|
, m_lockWindow(NULL) |
|
, m_waylandServer(new WaylandServer(this)) |
|
, m_lockedTimer(QElapsedTimer()) |
|
, m_idleId(0) |
|
, m_lockGrace(0) |
|
, m_inGraceTime(false) |
|
, m_graceTimer(new QTimer(this)) |
|
, m_inhibitCounter(0) |
|
, m_logind(nullptr) |
|
{ |
|
m_isX11 = QX11Info::isPlatformX11(); |
|
m_isWayland = QGuiApplication::platformName().startsWith( QLatin1String("wayland"), Qt::CaseInsensitive); |
|
|
|
initialize(); |
|
} |
|
|
|
KSldApp::~KSldApp() |
|
{ |
|
} |
|
|
|
static int s_XTimeout; |
|
static int s_XInterval; |
|
static int s_XBlanking; |
|
static int s_XExposures; |
|
|
|
void KSldApp::cleanUp() |
|
{ |
|
if (m_lockProcess && m_lockProcess->state() != QProcess::NotRunning) { |
|
m_lockProcess->terminate(); |
|
} |
|
delete m_actionCollection; |
|
delete m_lockProcess; |
|
delete m_lockWindow; |
|
|
|
// Restore X screensaver parameters |
|
XSetScreenSaver(QX11Info::display(), s_XTimeout, s_XInterval, s_XBlanking, s_XExposures); |
|
} |
|
|
|
static bool s_graceTimeKill = false; |
|
static bool s_logindExit = false; |
|
|
|
static bool hasXInput() |
|
{ |
|
#ifdef X11_Xinput_FOUND |
|
Display *dpy = QX11Info::display(); |
|
int xi_opcode, event, error; |
|
// init XInput extension |
|
if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error)) { |
|
return false; |
|
} |
|
|
|
// verify that the XInput extension is at at least version 2.0 |
|
int major = 2, minor = 0; |
|
int result = XIQueryVersion(dpy, &major, &minor); |
|
if (result == BadImplementation) { |
|
// Xinput 2.2 returns BadImplementation if checked against 2.0 |
|
major = 2; |
|
minor = 2; |
|
return XIQueryVersion(dpy, &major, &minor) == Success; |
|
} |
|
return result == Success; |
|
#else |
|
return false; |
|
#endif |
|
} |
|
|
|
void KSldApp::initializeX11() |
|
{ |
|
m_hasXInput2 = hasXInput(); |
|
// Save X screensaver parameters |
|
XGetScreenSaver(QX11Info::display(), &s_XTimeout, &s_XInterval, &s_XBlanking, &s_XExposures); |
|
// And disable it. The internal X screensaver is not used at all, but we use its |
|
// internal idle timer (and it is also used by DPMS support in X). This timer must not |
|
// be altered by this code, since e.g. resetting the counter after activating our |
|
// screensaver would prevent DPMS from activating. We use the timer merely to detect |
|
// user activity. |
|
XSetScreenSaver(QX11Info::display(), 0, s_XInterval, s_XBlanking, s_XExposures); |
|
} |
|
|
|
void KSldApp::initialize() |
|
{ |
|
KCrash::setFlags(KCrash::AutoRestart); |
|
if (m_isX11) { |
|
initializeX11(); |
|
} |
|
|
|
// Global keys |
|
m_actionCollection = new KActionCollection(this); |
|
|
|
if (KAuthorized::authorizeKAction(QStringLiteral("lock_screen"))) { |
|
qDebug() << "Configuring Lock Action"; |
|
QAction *a = m_actionCollection->addAction(QStringLiteral("Lock Session")); |
|
a->setText(i18n("Lock Session")); |
|
KGlobalAccel::self()->setGlobalShortcut(a, QList<QKeySequence>() << Qt::ALT+Qt::CTRL+Qt::Key_L << Qt::Key_ScreenSaver ); |
|
connect(a, &QAction::triggered, this, |
|
[this]() { |
|
lock(EstablishLock::Immediate); |
|
} |
|
); |
|
} |
|
m_actionCollection->readSettings(); |
|
|
|
// idle support |
|
auto idleTimeSignal = static_cast<void (KIdleTime:: *)(int)>(&KIdleTime::timeoutReached); |
|
connect(KIdleTime::instance(), idleTimeSignal, this, |
|
[this](int identifier) { |
|
if (identifier != m_idleId) { |
|
// not our identifier |
|
return; |
|
} |
|
if (lockState() != Unlocked) { |
|
return; |
|
} |
|
if (m_inhibitCounter // either we got a direct inhibit request thru our outdated o.f.Screensaver iface ... |
|
|| isFdoPowerInhibited()) { // ... or the newer one at o.f.PowerManagement.Inhibit |
|
// there is at least one process blocking the auto lock of screen locker |
|
return; |
|
} |
|
if (m_lockGrace) { // short-circuit if grace time is zero |
|
m_inGraceTime = true; |
|
} else if (m_lockGrace == -1) { |
|
m_inGraceTime = true; // if no timeout configured, grace time lasts forever |
|
} |
|
|
|
lock(EstablishLock::Delayed); |
|
} |
|
); |
|
|
|
m_lockProcess = new QProcess(); |
|
m_lockProcess->setReadChannel(QProcess::StandardOutput); |
|
auto finishedSignal = static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished); |
|
connect(m_lockProcess, finishedSignal, this, |
|
[this](int exitCode, QProcess::ExitStatus exitStatus) { |
|
if ((!exitCode && exitStatus == QProcess::NormalExit) || s_graceTimeKill || s_logindExit) { |
|
// unlock process finished successfully - we can remove the lock grab |
|
s_graceTimeKill = false; |
|
s_logindExit = false; |
|
doUnlock(); |
|
return; |
|
} |
|
// failure, restart lock process |
|
m_greeterCrashedCounter++; |
|
if (m_greeterCrashedCounter < 4) { |
|
startLockProcess(EstablishLock::Immediate); |
|
} else if (m_lockWindow) { |
|
m_lockWindow->emergencyShow(); |
|
} |
|
} |
|
); |
|
connect(m_lockProcess, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), this, |
|
[this](QProcess::ProcessError error) { |
|
if (error == QProcess::FailedToStart) { |
|
doUnlock(); |
|
m_waylandServer->stop(); |
|
qCritical() << "Greeter Process not available"; |
|
} |
|
} |
|
); |
|
m_lockedTimer.invalidate(); |
|
m_graceTimer->setSingleShot(true); |
|
connect(m_graceTimer, &QTimer::timeout, this, &KSldApp::endGraceTime); |
|
// create our D-Bus interface |
|
new Interface(this); |
|
|
|
// connect to logind |
|
m_logind = new LogindIntegration(this); |
|
connect(m_logind, &LogindIntegration::requestLock, this, |
|
[this]() { |
|
lock(EstablishLock::Immediate); |
|
} |
|
); |
|
connect(m_logind, &LogindIntegration::requestUnlock, this, |
|
[this]() { |
|
if (lockState() == Locked) { |
|
if (m_lockProcess->state() != QProcess::NotRunning) { |
|
s_logindExit = true; |
|
m_lockProcess->kill(); |
|
} else { |
|
doUnlock(); |
|
} |
|
} |
|
} |
|
); |
|
connect(m_logind, &LogindIntegration::prepareForSleep, this, |
|
[this](bool goingToSleep) { |
|
if (!goingToSleep) { |
|
// not interested in doing anything on wakeup |
|
return; |
|
} |
|
if (KScreenSaverSettings::lockOnResume()) { |
|
lock(EstablishLock::Immediate); |
|
} |
|
} |
|
); |
|
connect(m_logind, &LogindIntegration::inhibited, this, |
|
[this]() { |
|
// if we are already locked, we immediatelly remove the inhibition lock |
|
if (m_lockState == KSldApp::Locked) { |
|
m_logind->uninhibit(); |
|
} |
|
} |
|
); |
|
connect(m_logind, &LogindIntegration::connectedChanged, this, |
|
[this]() { |
|
if (m_logind->isConnected() && m_lockState == ScreenLocker::KSldApp::Unlocked && KScreenSaverSettings::lockOnResume()) { |
|
m_logind->inhibit(); |
|
} |
|
} |
|
); |
|
connect(this, &KSldApp::locked, this, |
|
[this]() { |
|
m_logind->uninhibit(); |
|
if (m_lockGrace > 0 && m_inGraceTime) { |
|
m_graceTimer->start(m_lockGrace); |
|
} |
|
} |
|
); |
|
connect(this, &KSldApp::unlocked, this, |
|
[this]() { |
|
if (KScreenSaverSettings::lockOnResume()) { |
|
m_logind->inhibit(); |
|
} |
|
} |
|
); |
|
|
|
m_globalAccel = new GlobalAccel(this); |
|
connect(this, &KSldApp::locked, m_globalAccel, &GlobalAccel::prepare); |
|
connect(this, &KSldApp::unlocked, m_globalAccel, &GlobalAccel::release); |
|
|
|
// fallback for non-logind systems: |
|
// connect to signal emitted by Solid. This is emitted unconditionally also on logind enabled systems |
|
// ksld ignores it in case logind is used |
|
QDBusConnection::sessionBus().connect(QStringLiteral("org.kde.Solid.PowerManagement"), |
|
QStringLiteral("/org/kde/Solid/PowerManagement/Actions/SuspendSession"), |
|
QStringLiteral("org.kde.Solid.PowerManagement.Actions.SuspendSession"), |
|
QStringLiteral("aboutToSuspend"), |
|
this, SLOT(solidSuspend())); |
|
|
|
configure(); |
|
} |
|
|
|
void KSldApp::configure() |
|
{ |
|
KScreenSaverSettings::self()->load(); |
|
// idle support |
|
if (m_idleId) { |
|
KIdleTime::instance()->removeIdleTimeout(m_idleId); |
|
m_idleId = 0; |
|
} |
|
const int timeout = KScreenSaverSettings::timeout(); |
|
// screen saver enabled means there is an auto lock timer |
|
// timeout > 0 is for backwards compatibility with old configs |
|
if (KScreenSaverSettings::autolock() && timeout > 0) { |
|
// timeout stored in minutes |
|
m_idleId = KIdleTime::instance()->addIdleTimeout(timeout*1000*60); |
|
} |
|
if (KScreenSaverSettings::lock()) { |
|
// lockGrace is stored in seconds |
|
m_lockGrace = KScreenSaverSettings::lockGrace() * 1000; |
|
} else { |
|
m_lockGrace = -1; |
|
} |
|
if (m_logind && m_logind->isConnected()) { |
|
if (KScreenSaverSettings::lockOnResume() && !m_logind->isInhibited()) { |
|
m_logind->inhibit(); |
|
} else if (!KScreenSaverSettings::lockOnResume() && m_logind->isInhibited()) { |
|
m_logind->uninhibit(); |
|
} |
|
} |
|
} |
|
|
|
void KSldApp::lock(EstablishLock establishLock) |
|
{ |
|
if (lockState() != Unlocked) { |
|
// already locked or acquiring lock, no need to lock again |
|
// but make sure it's really locked |
|
endGraceTime(); |
|
if (establishLock == EstablishLock::Immediate) { |
|
// signal the greeter to switch to immediateLock mode |
|
kill(m_lockProcess->pid(), SIGUSR1); |
|
} |
|
return; |
|
} |
|
|
|
qDebug() << "lock called"; |
|
if (!establishGrab()) { |
|
qCritical() << "Could not establish screen lock"; |
|
return; |
|
} |
|
|
|
KNotification::event(QStringLiteral("locked"), |
|
i18n("Screen locked"), |
|
QPixmap(), |
|
nullptr, |
|
KNotification::CloseOnTimeout, |
|
QStringLiteral("ksmserver")); |
|
|
|
// blank the screen |
|
showLockWindow(); |
|
|
|
m_lockState = AcquiringLock; |
|
|
|
// start unlock screen process |
|
startLockProcess(establishLock); |
|
} |
|
|
|
KActionCollection *KSldApp::actionCollection() |
|
{ |
|
return m_actionCollection; |
|
} |
|
|
|
/* |
|
* Forward declarations: |
|
* Only called from KSldApp::establishGrab(). Using from somewhere else is incorrect usage! |
|
**/ |
|
static bool grabKeyboard(); |
|
static bool grabMouse(); |
|
|
|
class XServerGrabber |
|
{ |
|
public: |
|
XServerGrabber() { |
|
xcb_grab_server(QX11Info::connection()); |
|
} |
|
~XServerGrabber() { |
|
xcb_ungrab_server(QX11Info::connection()); |
|
xcb_flush(QX11Info::connection()); |
|
} |
|
}; |
|
|
|
bool KSldApp::establishGrab() |
|
{ |
|
if (!m_isX11) { |
|
return true; |
|
} |
|
XSync(QX11Info::display(), False); |
|
XServerGrabber serverGrabber; |
|
if (!grabKeyboard()) { |
|
return false; |
|
} |
|
|
|
if (!grabMouse()) { |
|
XUngrabKeyboard(QX11Info::display(), CurrentTime); |
|
XFlush(QX11Info::display()); |
|
return false; |
|
} |
|
|
|
#ifdef X11_Xinput_FOUND |
|
if (m_hasXInput2) { |
|
// get all devices |
|
Display *dpy = QX11Info::display(); |
|
int numMasters; |
|
XIDeviceInfo *masters = XIQueryDevice(dpy, XIAllMasterDevices, &numMasters); |
|
bool success = true; |
|
for (int i = 0; i < numMasters; ++i) { |
|
// ignoring core pointer and core keyboard as we already grabbed them |
|
if (qstrcmp(masters[i].name, "Virtual core pointer") == 0) { |
|
continue; |
|
} |
|
if (qstrcmp(masters[i].name, "Virtual core keyboard") == 0) { |
|
continue; |
|
} |
|
XIEventMask mask; |
|
uchar bitmask[] = { 0, 0 }; |
|
mask.deviceid = masters[i].deviceid; |
|
mask.mask = bitmask; |
|
mask.mask_len = sizeof(bitmask); |
|
XISetMask(bitmask, XI_ButtonPress); |
|
XISetMask(bitmask, XI_ButtonRelease); |
|
XISetMask(bitmask, XI_Motion); |
|
XISetMask(bitmask, XI_Enter); |
|
XISetMask(bitmask, XI_Leave); |
|
const int result = XIGrabDevice(dpy, masters[i].deviceid, QX11Info::appRootWindow(), |
|
XCB_TIME_CURRENT_TIME, XCB_CURSOR_NONE, XIGrabModeAsync, |
|
XIGrabModeAsync, True, &mask); |
|
if (result != XIGrabSuccess) { |
|
success = false; |
|
break; |
|
} |
|
} |
|
if (!success) { |
|
// ungrab all devices again |
|
for (int i = 0; i < numMasters; ++i) { |
|
XIUngrabDevice(dpy, masters[i].deviceid, XCB_TIME_CURRENT_TIME); |
|
} |
|
xcb_connection_t *c = QX11Info::connection(); |
|
xcb_ungrab_keyboard(c, XCB_CURRENT_TIME); |
|
xcb_ungrab_pointer(c, XCB_CURRENT_TIME); |
|
} |
|
XIFreeDeviceInfo(masters); |
|
XFlush(dpy); |
|
return success; |
|
} |
|
#endif |
|
|
|
return true; |
|
} |
|
|
|
static bool grabKeyboard() |
|
{ |
|
int rv = XGrabKeyboard( QX11Info::display(), QX11Info::appRootWindow(), |
|
True, GrabModeAsync, GrabModeAsync, CurrentTime ); |
|
|
|
return (rv == GrabSuccess); |
|
} |
|
|
|
static bool grabMouse() |
|
{ |
|
#define GRABEVENTS ButtonPressMask | ButtonReleaseMask | PointerMotionMask | \ |
|
EnterWindowMask | LeaveWindowMask |
|
int rv = XGrabPointer( QX11Info::display(), QX11Info::appRootWindow(), |
|
True, GRABEVENTS, GrabModeAsync, GrabModeAsync, None, |
|
None, CurrentTime ); |
|
#undef GRABEVENTS |
|
|
|
return (rv == GrabSuccess); |
|
} |
|
|
|
void KSldApp::doUnlock() |
|
{ |
|
qDebug() << "Grab Released"; |
|
if (m_isX11) { |
|
xcb_connection_t *c = QX11Info::connection(); |
|
xcb_ungrab_keyboard(c, XCB_CURRENT_TIME); |
|
xcb_ungrab_pointer(c, XCB_CURRENT_TIME); |
|
xcb_flush(c); |
|
#ifdef X11_Xinput_FOUND |
|
if (m_hasXInput2) { |
|
// get all devices |
|
Display *dpy = QX11Info::display(); |
|
int numMasters; |
|
XIDeviceInfo *masters = XIQueryDevice(dpy, XIAllMasterDevices, &numMasters); |
|
// ungrab all devices again |
|
for (int i = 0; i < numMasters; ++i) { |
|
XIUngrabDevice(dpy, masters[i].deviceid, XCB_TIME_CURRENT_TIME); |
|
} |
|
XIFreeDeviceInfo(masters); |
|
XFlush(dpy); |
|
} |
|
#endif |
|
} |
|
hideLockWindow(); |
|
// delete the window again, to get rid of event filter |
|
delete m_lockWindow; |
|
m_lockWindow = NULL; |
|
m_lockState = Unlocked; |
|
m_lockedTimer.invalidate(); |
|
m_greeterCrashedCounter = 0; |
|
endGraceTime(); |
|
m_waylandServer->stop(); |
|
KNotification::event(QStringLiteral("unlocked"), |
|
i18n("Screen unlocked"), |
|
QPixmap(), |
|
nullptr, |
|
KNotification::CloseOnTimeout, |
|
QStringLiteral("ksmserver")); |
|
emit unlocked(); |
|
} |
|
|
|
bool KSldApp::isFdoPowerInhibited() const |
|
{ |
|
QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.Solid.PowerManagement.PolicyAgent"), |
|
QStringLiteral("/org/kde/Solid/PowerManagement/PolicyAgent"), |
|
QStringLiteral("org.kde.Solid.PowerManagement.PolicyAgent"), |
|
QStringLiteral("HasInhibition")); |
|
msg << (uint) 5; // PowerDevil::PolicyAgent::RequiredPolicy::ChangeScreenSettings | PowerDevil::PolicyAgent::RequiredPolicy::InterruptSession |
|
QDBusReply<bool> reply = QDBusConnection::sessionBus().asyncCall(msg); |
|
|
|
return reply.isValid() && reply.value(); |
|
} |
|
|
|
void KSldApp::startLockProcess(EstablishLock establishLock) |
|
{ |
|
QStringList args; |
|
if (establishLock == EstablishLock::Immediate) { |
|
args << QStringLiteral("--immediateLock"); |
|
} |
|
if (m_lockGrace > 0) { |
|
args << QStringLiteral("--graceTime"); |
|
args << QString::number(m_lockGrace); |
|
} |
|
if (m_lockGrace == -1) { |
|
args << QStringLiteral("--nolock"); |
|
} |
|
|
|
// start the Wayland server |
|
int fd = m_waylandServer->start(); |
|
if (fd == -1) { |
|
emit m_lockProcess->error(QProcess::FailedToStart); |
|
return; |
|
} |
|
|
|
args << QStringLiteral("--ksldfd"); |
|
args << QString::number(fd); |
|
|
|
m_lockProcess->start(QStringLiteral(KSCREENLOCKER_GREET_BIN), args); |
|
close(fd); |
|
} |
|
|
|
void KSldApp::showLockWindow() |
|
{ |
|
if (!m_lockWindow) { |
|
if (m_isX11) { |
|
m_lockWindow = new X11Locker(); |
|
} |
|
if (m_isWayland) { |
|
m_lockWindow = new WaylandLocker(); |
|
} |
|
if (!m_lockWindow) { |
|
return; |
|
} |
|
m_lockWindow->setGlobalAccel(m_globalAccel); |
|
connect(m_lockWindow, &AbstractLocker::userActivity, this, |
|
[this]() { |
|
if (isGraceTime()) { |
|
unlock(); |
|
} |
|
}, |
|
Qt::QueuedConnection |
|
); |
|
connect(m_lockWindow, &AbstractLocker::lockWindowShown, this, |
|
[this] { |
|
m_lockState = Locked; |
|
m_lockedTimer.restart(); |
|
emit locked(); |
|
}, Qt::QueuedConnection |
|
); |
|
connect(m_waylandServer, &WaylandServer::x11WindowAdded, m_lockWindow, &AbstractLocker::addAllowedWindow); |
|
} |
|
m_lockWindow->showLockWindow(); |
|
if (m_isX11) { |
|
XSync(QX11Info::display(), False); |
|
} |
|
} |
|
|
|
void KSldApp::hideLockWindow() |
|
{ |
|
if (!m_lockWindow) { |
|
return; |
|
} |
|
m_lockWindow->hideLockWindow(); |
|
} |
|
|
|
uint KSldApp::activeTime() const |
|
{ |
|
if (m_lockedTimer.isValid()) { |
|
return m_lockedTimer.elapsed(); |
|
} |
|
return 0; |
|
} |
|
|
|
bool KSldApp::isGraceTime() const |
|
{ |
|
return m_inGraceTime; |
|
} |
|
|
|
void KSldApp::endGraceTime() |
|
{ |
|
m_graceTimer->stop(); |
|
m_inGraceTime = false; |
|
} |
|
|
|
void KSldApp::unlock() |
|
{ |
|
if (!isGraceTime()) { |
|
return; |
|
} |
|
s_graceTimeKill = true; |
|
m_lockProcess->terminate(); |
|
} |
|
|
|
void KSldApp::inhibit() |
|
{ |
|
++m_inhibitCounter; |
|
} |
|
|
|
void KSldApp::uninhibit() |
|
{ |
|
--m_inhibitCounter; |
|
} |
|
|
|
void KSldApp::solidSuspend() |
|
{ |
|
// ignore in case that we use logind |
|
if (m_logind && m_logind->isConnected()) { |
|
return; |
|
} |
|
if (KScreenSaverSettings::lockOnResume()) { |
|
lock(EstablishLock::Immediate); |
|
} |
|
} |
|
|
|
} // namespace
|
|
|