summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kdesktop/DESIGN13
-rw-r--r--kdesktop/KScreensaverIface.h18
-rw-r--r--kdesktop/lock/lockprocess.h3
-rw-r--r--kdesktop/lockeng.cpp1144
-rw-r--r--kdesktop/lockeng.h162
-rw-r--r--kdesktop/main.cpp18
6 files changed, 721 insertions, 637 deletions
diff --git a/kdesktop/DESIGN b/kdesktop/DESIGN
index 7e195378f..170a86a75 100644
--- a/kdesktop/DESIGN
+++ b/kdesktop/DESIGN
@@ -124,3 +124,16 @@ kdesktop_lock to kdesktop communication:
- TTIN: the lock process is ready. This is sent after the process has been created/respawned
- USR2: the lock/screensaver has been activated
- USR1: the lock/screensaver has been unlocked/stopped
+
+Communication is handled by the screen saver engine defined in 'lockeng.{h,cpp}'.
+The engine is split into two parts, the 'SaverEngine' running in the GUI thread and
+the 'SaverEngineEventHandler' running in a separate thread and eventloop.
+The 'SaverEngine' handles communication with X11, DCOP and DBUS while the
+'SaverEngineEventHandler' handles communication with the actual lock process.
+Several actions require cooperation of the two parts, so in various methods
+there will be inter-thread calls (using timers or by emitting signals) to
+trigger the other side remaining logic.
+This complex design is necessary to avoid blocking the main GUI application event loop,
+which has several tasks to manage and therefore can't affort to wait in a suspended state.
+This was previously leading to deadlock when DCOP calls where executed on the secondary
+thread/eventloop, for example when changing desktop while the lock process was restarting.
diff --git a/kdesktop/KScreensaverIface.h b/kdesktop/KScreensaverIface.h
index de5c19f2b..b6434738e 100644
--- a/kdesktop/KScreensaverIface.h
+++ b/kdesktop/KScreensaverIface.h
@@ -12,11 +12,10 @@ public:
KScreensaverIface() : DCOPObject("KScreensaverIface") {}
k_dcop:
- /** Lock the screen now even if the screensaver does not lock by default. */
+ /** Lock the screen now even if the screensaver does not lock by default */
virtual void lock() = 0;
- /** Save the screen now. If the user has locking enabled, the screen is
- * locked also. */
+ /** Start the screensaver now. If the user has locking enabled, the screen is locked also */
virtual void save() = 0;
/** Quit the screensaver if it is running */
@@ -29,22 +28,23 @@ k_dcop:
* Enable/disable the screensaver
* returns true if the action succeeded
*/
- virtual bool enable( bool e ) = 0;
+ virtual bool enable(bool e) = 0;
/** Is the screen currently blanked? */
virtual bool isBlanked() = 0;
- /** Reload the screensaver configuration. */
+ /** Reload the screensaver configuration */
virtual void configure() = 0;
- /** Only blank the screen (and possibly lock). Do not use a custom
- * screen saver in the interest of saving battery.
+ /**
+ * Set the screensaver to blank (and possibly lock).
+ * This method does not actually start the screensaver.
*/
- virtual void setBlankOnly( bool blankOnly ) = 0;
+ virtual void setBlankOnly(bool blankOnly) = 0;
/***
* @internal
- */
+ */
virtual void saverLockReady() = 0;
};
diff --git a/kdesktop/lock/lockprocess.h b/kdesktop/lock/lockprocess.h
index 5a6a3b4d4..1afc9bb46 100644
--- a/kdesktop/lock/lockprocess.h
+++ b/kdesktop/lock/lockprocess.h
@@ -106,9 +106,6 @@ class LockProcess : public TQWidget
TDECryptographicCardDevice* cryptographicCardDevice();
- signals:
- void terminateHelperThread();
-
public slots:
void quitSaver();
void preparePopup();
diff --git a/kdesktop/lockeng.cpp b/kdesktop/lockeng.cpp
index c4b781c2a..7216acc4f 100644
--- a/kdesktop/lockeng.cpp
+++ b/kdesktop/lockeng.cpp
@@ -6,7 +6,6 @@
// Copyright (c) 2012 Timothy Pearson <kb9vqf@pearsoncomputing.net>
//
-
#include <config.h>
#include <stdlib.h>
@@ -45,52 +44,49 @@
#include "lockeng.moc"
#include "kdesktopsettings.h"
-#define SYSTEMD_LOGIN1_SERVICE "org.freedesktop.login1"
-#define SYSTEMD_LOGIN1_PATH "/org/freedesktop/login1"
-#define SYSTEMD_LOGIN1_MANAGER_IFACE "org.freedesktop.login1.Manager"
-#define SYSTEMD_LOGIN1_SESSION_IFACE "org.freedesktop.login1.Session"
-#define SYSTEMD_LOGIN1_SEAT_IFACE "org.freedesktop.login1.Seat"
+#include "xautolock_c.h"
+
+#define SYSTEMD_LOGIN1_SERVICE "org.freedesktop.login1"
+#define SYSTEMD_LOGIN1_MANAGER_IFACE "org.freedesktop.login1.Manager"
+#define SYSTEMD_LOGIN1_SESSION_IFACE "org.freedesktop.login1.Session"
+#define SYSTEMD_LOGIN1_SEAT_IFACE "org.freedesktop.login1.Seat"
+#define SYSTEMD_LOGIN1_PATH "/org/freedesktop/login1"
#define DBUS_CONN_NAME "kdesktop_lock"
-#include "xautolock_c.h"
extern xautolock_corner_t xautolock_corners[ 4 ];
-
bool trinity_lockeng_sak_available = true;
-SaverEngine* m_masterSaverEngine = NULL;
+SaverEngineEventHandler *gbl_saverEngineEventHandler = nullptr;
+
static void sigusr1_handler(int)
{
- if (m_masterSaverEngine) {
- m_masterSaverEngine->m_threadHelperObject->slotLockProcessWaiting();
+ if (gbl_saverEngineEventHandler)
+ {
+ gbl_saverEngineEventHandler->lockProcessExited();
}
}
+
static void sigusr2_handler(int)
{
- if (m_masterSaverEngine) {
- m_masterSaverEngine->m_threadHelperObject->slotLockProcessFullyActivated();
+ if (gbl_saverEngineEventHandler)
+ {
+ gbl_saverEngineEventHandler->lockProcessFullyActivated();
}
}
+
static void sigttin_handler(int)
{
- if (m_masterSaverEngine) {
- m_masterSaverEngine->slotLockProcessReady();
+ if (gbl_saverEngineEventHandler)
+ {
+ gbl_saverEngineEventHandler->lockProcessReady();
}
}
-//===========================================================================
-//
-// Screen saver engine. Doesn't handle the actual screensaver window,
-// starting screensaver hacks, or password entry. That's done by
-// a newly started process.
-//
SaverEngine::SaverEngine()
- : TQWidget(),
+ : TQObject(),
KScreensaverIface(),
mBlankOnly(false),
- mSAKProcess(NULL),
- mTerminationRequested(false),
- mSaverProcessReady(false),
mNewVTAfterLockEngage(false),
mValidCryptoCardInserted(false),
mSwitchVTAfterLockEngage(-1),
@@ -99,7 +95,6 @@ SaverEngine::SaverEngine()
systemdSession(0)
{
// handle SIGUSR1
- m_masterSaverEngine = this;
mSignalAction.sa_handler= sigusr1_handler;
sigemptyset(&(mSignalAction.sa_mask));
sigaddset(&(mSignalAction.sa_mask), SIGUSR1);
@@ -107,7 +102,6 @@ SaverEngine::SaverEngine()
sigaction(SIGUSR1, &mSignalAction, 0L);
// handle SIGUSR2
- m_masterSaverEngine = this;
mSignalAction.sa_handler= sigusr2_handler;
sigemptyset(&(mSignalAction.sa_mask));
sigaddset(&(mSignalAction.sa_mask), SIGUSR2);
@@ -115,7 +109,6 @@ SaverEngine::SaverEngine()
sigaction(SIGUSR2, &mSignalAction, 0L);
// handle SIGTTIN
- m_masterSaverEngine = this;
mSignalAction.sa_handler= sigttin_handler;
sigemptyset(&(mSignalAction.sa_mask));
sigaddset(&(mSignalAction.sa_mask), SIGTTIN);
@@ -123,92 +116,52 @@ SaverEngine::SaverEngine()
sigaction(SIGTTIN, &mSignalAction, 0L);
// Save X screensaver parameters
- XGetScreenSaver(tqt_xdisplay(), &mXTimeout, &mXInterval,
- &mXBlanking, &mXExposures);
-
- mState = Waiting;
- mXAutoLock = 0;
+ XGetScreenSaver(tqt_xdisplay(), &mXTimeout, &mXInterval, &mXBlanking, &mXExposures);
+
+ // Create event handler thread, event loop and object
+ m_eventHandlerThread = new TQEventLoopThread;
+ m_eventHandlerThread->start();
+ m_saverEngineEventHandler = new SaverEngineEventHandler(this);
+ gbl_saverEngineEventHandler = m_saverEngineEventHandler;
+ m_saverEngineEventHandler->moveToThread(m_eventHandlerThread);
+ connect(this, TQ_SIGNAL(terminateEventHandlerThread()), m_saverEngineEventHandler, TQ_SLOT(terminateThread()));
+ connect(this, TQ_SIGNAL(lockScreenSignal(bool)), m_saverEngineEventHandler, TQ_SLOT(lockScreen(bool)));
+ connect(this, TQ_SIGNAL(activateSaverOrLockSignal(LockType)),
+ m_saverEngineEventHandler, TQ_SLOT(activateSaverOrLock(LockType)));
+
+ mXAutoLock = nullptr;
mEnabled = false;
- m_helperThread = new TQEventLoopThread;
- m_helperThread->start();
- m_threadHelperObject = new SaverEngineThreadHelperObject;
- m_threadHelperObject->moveToThread(m_helperThread);
- connect(this, TQ_SIGNAL(terminateHelperThread()), m_threadHelperObject, TQ_SLOT(terminateThread()));
- connect(m_threadHelperObject, TQ_SIGNAL(lockProcessWaiting()), this, TQ_SLOT(lockProcessWaiting()));
- connect(m_threadHelperObject, TQ_SIGNAL(lockProcessFullyActivated()), this, TQ_SLOT(lockProcessFullyActivated()));
-
- connect(&mLockProcess, TQ_SIGNAL(processExited(TDEProcess *)),
- TQ_SLOT(lockProcessExited()));
-
configure();
- // Create SAK process only if SAK is enabled
- KSimpleConfig *config;
- struct stat st;
- if (stat( KDE_CONFDIR "/tdm/tdmdistrc" , &st) == 0) {
- config = new KSimpleConfig( TQString::fromLatin1( KDE_CONFDIR "/tdm/tdmdistrc" ));
- }
- else {
- config = new KSimpleConfig( TQString::fromLatin1( KDE_CONFDIR "/tdm/tdmrc" ));
- }
- config->setGroup("X-:*-Greeter");
- bool useSAKProcess = false;
-#ifdef BUILD_TSAK
- useSAKProcess = config->readBoolEntry("UseSAK", false) && KDesktopSettings::useTDESAK();
-#endif
- if (useSAKProcess) {
- mSAKProcess = new TDEProcess;
- *mSAKProcess << "tdmtsak";
- connect(mSAKProcess, TQ_SIGNAL(processExited(TDEProcess*)), this, TQ_SLOT(slotSAKProcessExited()));
- TQTimer::singleShot( 0, this, TQ_SLOT(handleSecureDialog()) );
- }
-
- mLockProcess.clearArguments();
- TQString path = TDEStandardDirs::findExe( "kdesktop_lock" );
- if( path.isEmpty())
- {
- kdDebug( 1204 ) << "Can't find kdesktop_lock!" << endl;
- }
- mLockProcess << path;
- mLockProcess << TQString( "--internal" ) << TQString( "%1" ).arg(getpid());
- if (!mLockProcess.start())
- {
- kdDebug( 1204 ) << "Failed to start kdesktop_lock!" << endl;
- }
-
- // Prevent kdesktop_lock signals from being handled by the wrong (GUI) thread
- sigemptyset(&mThreadBlockSet);
- sigaddset(&mThreadBlockSet, SIGUSR1);
- sigaddset(&mThreadBlockSet, SIGUSR2);
- sigaddset(&mThreadBlockSet, SIGTTIN);
- pthread_sigmask(SIG_BLOCK, &mThreadBlockSet, NULL);
-
- // Wait for the saver process to signal ready...
- if (!waitForLockProcessStart()) {
- kdDebug( 1204 ) << "Failed to initialize kdesktop_lock (unexpected termination)!" << endl;
- }
-
- // lock the desktop if required
- config->setGroup("X-:0-Core");
- bool autoLoginEnable = config->readBoolEntry("AutoLoginEnable", false);
- bool autoLoginLocked = config->readBoolEntry("AutoLoginLocked", false);
- if (autoLoginEnable && autoLoginLocked) {
- mLockProcess.kill(SIGTTOU);
- mLockProcess.kill(SIGUSR1);
- }
- delete config;
- config = NULL;
+ // Prevent kdesktop_lock signals from being handled by the main GUI thread.
+ // Those signals will be handled by m_eventHandlerThread instead
+ //
+ // Make sure to keep this code after the constructor of `m_eventHandlerThread`, so that
+ // the new thread starts with the signals unblocked.
+ sigset_t sigBlockMask;
+ sigemptyset(&sigBlockMask);
+ sigaddset(&sigBlockMask, SIGUSR1);
+ sigaddset(&sigBlockMask, SIGUSR2);
+ sigaddset(&sigBlockMask, SIGTTIN);
+ sigaddset(&sigBlockMask, SIGCHLD);
+ pthread_sigmask(SIG_BLOCK, &sigBlockMask, NULL);
+
+ // Start SAK and lock processes
+ TQTimer::singleShot(0, m_saverEngineEventHandler, TQ_SLOT(restartLockProcess()));
#ifdef WITH_TDEHWLIB
// Initialize SmartCard readers
TDEGenericDevice *hwdevice;
TDEHardwareDevices *hwdevices = TDEGlobal::hardwareDevices();
TDEGenericHardwareList cardReaderList = hwdevices->listByDeviceClass(TDEGenericDeviceType::CryptographicCard);
- for (hwdevice = cardReaderList.first(); hwdevice; hwdevice = cardReaderList.next()) {
- TDECryptographicCardDevice* cdevice = static_cast<TDECryptographicCardDevice*>(hwdevice);
- connect(cdevice, TQ_SIGNAL(certificateListAvailable(TDECryptographicCardDevice*)), this, TQ_SLOT(cryptographicCardInserted(TDECryptographicCardDevice*)));
- connect(cdevice, TQ_SIGNAL(cardRemoved(TDECryptographicCardDevice*)), this, TQ_SLOT(cryptographicCardRemoved(TDECryptographicCardDevice*)));
+ for (hwdevice = cardReaderList.first(); hwdevice; hwdevice = cardReaderList.next())
+ {
+ TDECryptographicCardDevice *cdevice = static_cast<TDECryptographicCardDevice*>(hwdevice);
+ connect(cdevice, TQ_SIGNAL(certificateListAvailable(TDECryptographicCardDevice*)),
+ this, TQ_SLOT(cryptographicCardInserted(TDECryptographicCardDevice*)));
+ connect(cdevice, TQ_SIGNAL(cardRemoved(TDECryptographicCardDevice*)),
+ this, TQ_SLOT(cryptographicCardRemoved(TDECryptographicCardDevice*)));
cdevice->enableCardMonitoring(true);
}
@@ -216,9 +169,11 @@ SaverEngine::SaverEngine()
KUser userinfo;
TQString fileName = userinfo.homeDir() + "/.tde_card_login_state";
TQFile flagFile(fileName);
- if (flagFile.open(IO_ReadOnly)) {
+ if (flagFile.open(IO_ReadOnly))
+ {
TQTextStream stream(&flagFile);
- if (stream.readLine().startsWith("1")) {
+ if (stream.readLine().startsWith("1"))
+ {
// Card was likely used to log in
TQTimer::singleShot(5000, this, TQ_SLOT(cardStartupTimeout()));
}
@@ -229,70 +184,66 @@ SaverEngine::SaverEngine()
dBusConnect();
}
-//---------------------------------------------------------------------------
-//
-// Destructor - usual cleanups.
-//
SaverEngine::~SaverEngine()
{
- if (mState == Waiting) {
- kill(mLockProcess.pid(), SIGKILL);
- }
-
- mLockProcess.detach(); // don't kill it if we crash
+ m_saverEngineEventHandler->terminateLockProcess();
delete mXAutoLock;
-
dBusClose();
// Restore X screensaver parameters
- XSetScreenSaver(tqt_xdisplay(), mXTimeout, mXInterval, mXBlanking,
- mXExposures);
-
- terminateHelperThread();
- m_helperThread->wait();
- delete m_threadHelperObject;
- delete m_helperThread;
+ XSetScreenSaver(tqt_xdisplay(), mXTimeout, mXInterval, mXBlanking, mXExposures);
+ emit terminateEventHandlerThread();
+ m_eventHandlerThread->wait();
+ delete m_saverEngineEventHandler;
+ delete m_eventHandlerThread;
}
-void SaverEngine::cardStartupTimeout() {
- if (!mValidCryptoCardInserted) {
- // Restore saver timeout
- configure();
-
- // Force lock
- lockScreen();
+void SaverEngine::cardStartupTimeout()
+{
+ if (!mValidCryptoCardInserted)
+ {
+ configure(); // Restore saver timeout
+ lockScreen(); // Force lock
}
}
-void SaverEngine::cryptographicCardInserted(TDECryptographicCardDevice* cdevice) {
+void SaverEngine::cryptographicCardInserted(TDECryptographicCardDevice* cdevice)
+{
#ifdef WITH_TDEHWLIB
TQString login_name = TQString::null;
X509CertificatePtrList certList = cdevice->cardX509Certificates();
- if (certList.count() > 0) {
+ if (certList.count() > 0)
+ {
KSSLCertificate* card_cert = NULL;
card_cert = KSSLCertificate::fromX509(certList[0]);
TQStringList cert_subject_parts = TQStringList::split("/", card_cert->getSubject(), false);
- for (TQStringList::Iterator it = cert_subject_parts.begin(); it != cert_subject_parts.end(); ++it ) {
+ for (TQStringList::Iterator it = cert_subject_parts.begin(); it != cert_subject_parts.end(); ++it)
+ {
TQString lcpart = (*it).lower();
- if (lcpart.startsWith("cn=")) {
+ if (lcpart.startsWith("cn="))
+ {
login_name = lcpart.right(lcpart.length() - strlen("cn="));
}
}
delete card_cert;
}
- if (login_name != "") {
+ if (login_name != "")
+ {
KUser user;
- if (login_name == user.loginName()) {
+ if (login_name == user.loginName())
+ {
mValidCryptoCardInserted = true;
}
}
#endif
}
-void SaverEngine::cryptographicCardRemoved(TDECryptographicCardDevice* cdevice) {
+void SaverEngine::cryptographicCardRemoved(TDECryptographicCardDevice* cdevice)
+{
#ifdef WITH_TDEHWLIB
- if (mValidCryptoCardInserted) {
+ if (mValidCryptoCardInserted)
+ {
mValidCryptoCardInserted = false;
// Restore saver timeout
@@ -304,226 +255,166 @@ void SaverEngine::cryptographicCardRemoved(TDECryptographicCardDevice* cdevice)
#endif
}
-//---------------------------------------------------------------------------
-//
-// This should be called only using DCOP.
-//
+// DCOP interface method
void SaverEngine::lock()
{
lockScreen(true);
}
-//---------------------------------------------------------------------------
-//
-// Lock the screen
-//
-void SaverEngine::lockScreen(bool DCOP)
+void SaverEngine::lockScreen(bool dcop)
{
- if (mValidCryptoCardInserted) {
+ if (mValidCryptoCardInserted)
+ {
+ kdDebug(1204) << "SaverEngine: crypto card inserted, ignore lock request" << endl;
return;
}
+ emit lockScreenSignal(dcop);
+}
- bool ok = true;
- if (mState == Waiting)
- {
- ok = startLockProcess( ForceLock );
- // It takes a while for kdesktop_lock to start and lock the screen.
- // Therefore delay the DCOP call until it tells kdesktop that the locking is in effect.
- // This is done only for --forcelock .
- if( ok && mState != Saving )
- {
- if (DCOP) {
- DCOPClientTransaction* trans = tdeApp->dcopClient()->beginTransaction();
- if (trans) {
- mLockTransactions.append( trans );
- }
- }
- }
- }
- else
+void SaverEngine::lockScreenGUI()
+{
+ DCOPClientTransaction *trans = tdeApp->dcopClient()->beginTransaction();
+ if (trans)
{
- mLockProcess.kill( SIGHUP );
+ mLockTransactions.append(trans);
}
}
void SaverEngine::processLockTransactions()
{
- for( TQValueVector< DCOPClientTransaction* >::ConstIterator it = mLockTransactions.begin();
- it != mLockTransactions.end();
- ++it )
+ TQValueVector<DCOPClientTransaction*>::ConstIterator it = mLockTransactions.begin();
+ for (; it != mLockTransactions.end(); ++it)
{
TQCString replyType = "void";
TQByteArray arr;
- tdeApp->dcopClient()->endTransaction( *it, replyType, arr );
+ tdeApp->dcopClient()->endTransaction(*it, replyType, arr);
}
mLockTransactions.clear();
}
void SaverEngine::saverLockReady()
{
- if( mState != Engaging )
+ if (m_saverEngineEventHandler->getState() != SaverState::Engaging)
{
- kdDebug( 1204 ) << "Got unexpected saverReady()" << endl;
+ kdDebug(1204) << "Got unexpected saverLockReady()" << endl;
}
- kdDebug( 1204 ) << "Saver Lock Ready" << endl;
+
+ kdDebug(1204) << "Saver Lock Ready" << endl;
processLockTransactions();
}
-//---------------------------------------------------------------------------
+// DCOP interface method
void SaverEngine::save()
{
- if (!mValidCryptoCardInserted) {
- if (mState == Waiting) {
- startLockProcess( DefaultLock );
- }
+ if (mValidCryptoCardInserted)
+ {
+ kdDebug(1204) << "SaverEngine: crypto card inserted, ignore save request" << endl;
+ return;
}
+ TQTimer::singleShot(0, m_saverEngineEventHandler, TQ_SLOT(saveScreen()));
}
-//---------------------------------------------------------------------------
+// DCOP interface method
void SaverEngine::quit()
{
- if (mState == Saving || mState == Engaging)
- {
- stopLockProcess();
- }
+ TQTimer::singleShot(0, m_saverEngineEventHandler, TQ_SLOT(stopLockProcess()));
}
-//---------------------------------------------------------------------------
+// DCOP interface method
bool SaverEngine::isEnabled()
{
return mEnabled;
}
-//---------------------------------------------------------------------------
-bool SaverEngine::enable( bool e )
+// DCOP interface method
+bool SaverEngine::enable(bool e)
{
- if ( e == mEnabled )
- return true;
+ if (e == mEnabled)
+ return true;
// If we aren't in a suitable state, we will not reconfigure.
- if (mState != Waiting)
+ if (m_saverEngineEventHandler->getState() != SaverState::Waiting)
return false;
mEnabled = e;
- if (mEnabled) {
- if ( !mXAutoLock ) {
+ if (mEnabled)
+ {
+ if (!mXAutoLock)
+ {
mXAutoLock = new XAutoLock();
connect(mXAutoLock, TQ_SIGNAL(timeout()), TQ_SLOT(idleTimeout()));
}
mXAutoLock->setTimeout(mTimeout);
mXAutoLock->setDPMS(true);
- //mXAutoLock->changeCornerLockStatus( mLockCornerTopLeft, mLockCornerTopRight, mLockCornerBottomLeft, mLockCornerBottomRight);
// We'll handle blanking
XSetScreenSaver(tqt_xdisplay(), mTimeout + 10, mXInterval, PreferBlanking, mXExposures);
- kdDebug() << "XSetScreenSaver " << mTimeout + 10 << endl;
-
mXAutoLock->start();
-
- kdDebug(1204) << "Saver Engine started, timeout: " << mTimeout << endl;
+ kdDebug(1204) << "Saver engine started, timeout: " << mTimeout << endl;
}
- else {
- if (mXAutoLock) {
+ else
+ {
+ if (mXAutoLock)
+ {
delete mXAutoLock;
- mXAutoLock = 0;
+ mXAutoLock = nullptr;
}
- XForceScreenSaver(tqt_xdisplay(), ScreenSaverReset );
+ XForceScreenSaver(tqt_xdisplay(), ScreenSaverReset);
XSetScreenSaver(tqt_xdisplay(), 0, mXInterval, PreferBlanking, DontAllowExposures);
- kdDebug(1204) << "Saver Engine disabled" << endl;
+ kdDebug(1204) << "Saver engine disabled" << endl;
}
return true;
}
-//---------------------------------------------------------------------------
+// DCOP interface method
bool SaverEngine::isBlanked()
{
- return (mState != Waiting);
+ return (m_saverEngineEventHandler->getState() != SaverState::Waiting);
}
void SaverEngine::enableExports()
{
#ifdef TQ_WS_X11
- kdDebug(270) << k_lineinfo << "activating background exports.\n";
+ kdDebug(270) << k_lineinfo << "activating background exports" << endl;
DCOPClient *client = tdeApp->dcopClient();
- if (!client->isAttached()) {
+ if (!client->isAttached())
+ {
client->attach();
}
TQByteArray data;
- TQDataStream args( data, IO_WriteOnly );
+ TQDataStream args(data, IO_WriteOnly);
args << 1;
- TQCString appname( "kdesktop" );
+ TQCString appname("kdesktop");
int screen_number = DefaultScreen(tqt_xdisplay());
- if ( screen_number ) {
- appname.sprintf("kdesktop-screen-%d", screen_number );
+ if (screen_number)
+ {
+ appname.sprintf("kdesktop-screen-%d", screen_number);
}
- client->send( appname, "KBackgroundIface", "setExport(int)", data );
+ client->send(appname, "KBackgroundIface", "setExport(int)", data);
#endif
}
-//---------------------------------------------------------------------------
-void SaverEngine::handleSecureDialog()
-{
- // Wait for SAK press
- if (mSAKProcess && !mSAKProcess->isRunning()) {
- mSAKProcess->start();
- }
-}
-
-void SaverEngine::slotSAKProcessExited()
-{
- if (!mSAKProcess) {
- printf("[kdesktop] SAK process does not exist. Something went wrong. Ignoring...\n"); fflush(stdout);
- return;
- }
- int retcode = mSAKProcess->exitStatus();
- if ((retcode != 0) && (mSAKProcess->normalExit())) {
- trinity_lockeng_sak_available = false;
- printf("[kdesktop] SAK driven secure dialog is not available for use (retcode %d). Check tdmtsak for proper functionality.\n", retcode); fflush(stdout);
- }
-
- if (mState == Preparing) {
- return;
- }
-
- if (mSAKProcess->normalExit() && trinity_lockeng_sak_available) {
- bool ok = true;
- if (mState == Waiting)
- {
- ok = startLockProcess( SecureDialog );
- if( ok && mState != Saving )
- {
- }
- }
- else
- {
- mLockProcess.kill( SIGHUP );
- }
- }
-}
-
-//---------------------------------------------------------------------------
-//
// Read and apply configuration.
-//
void SaverEngine::configure()
{
// If we aren't in a suitable state, we will not reconfigure.
- if (mState != Waiting) {
+ if (m_saverEngineEventHandler->getState() != SaverState::Waiting)
+ {
return;
}
// create a new config obj to ensure we read the latest options
KDesktopSettings::self()->readConfig();
- bool e = KDesktopSettings::screenSaverEnabled();
mTimeout = KDesktopSettings::timeout();
-
- mEnabled = !e; // force the enable()
+ bool e = KDesktopSettings::screenSaverEnabled();
+ mEnabled = !e; // enable the screensaver by forcibly toggling it
+ enable(e);
int action;
action = KDesktopSettings::actionTopLeft();
@@ -534,320 +425,183 @@ void SaverEngine::configure()
xautolock_corners[2] = applyManualSettings(action);
action = KDesktopSettings::actionBottomRight();
xautolock_corners[3] = applyManualSettings(action);
-
- enable( e );
}
-//---------------------------------------------------------------------------
-//
-// Set a variable to indicate only using the blanker and not the saver.
-//
-void SaverEngine::setBlankOnly( bool blankOnly )
+// DCOP interface method
+// Set a variable to indicate only to blank the screen and not use the saver
+void SaverEngine::setBlankOnly(bool blankOnly)
{
mBlankOnly = blankOnly;
- // FIXME: if running, stop and restart? What about security
- // implications of this?
}
-bool SaverEngine::restartDesktopLockProcess()
+void SaverEngine::activateSaverOrLockGUI()
{
- if (!mLockProcess.isRunning()) {
- mSaverProcessReady = false;
- mLockProcess.clearArguments();
- TQString path = TDEStandardDirs::findExe( "kdesktop_lock" );
- if (path.isEmpty()) {
- kdDebug( 1204 ) << "Can't find kdesktop_lock!" << endl;
- return false;
- }
- mLockProcess << path;
- mLockProcess << TQString( "--internal" ) << TQString( "%1" ).arg(getpid());
- if (!mLockProcess.start()) {
- kdDebug( 1204 ) << "Failed to start kdesktop_lock!" << endl;
- return false;
- }
- // Wait for the saver process to signal ready...
- if (!waitForLockProcessStart()) {
- kdDebug( 1204 ) << "Failed to initialize kdesktop_lock (unexpected termination)!" << endl;
- return false;
- }
- }
- return true;
-}
-
-//---------------------------------------------------------------------------
-//
-// Start the screen saver.
-//
-bool SaverEngine::startLockProcess( LockType lock_type )
-{
- int ret;
-
- if (mState == Saving) {
- return true;
- }
-
- mState = Preparing;
- if (mSAKProcess) {
- mSAKProcess->kill(SIGTERM);
- }
-
- enableExports();
-
- kdDebug(1204) << "SaverEngine: starting saver" << endl;
- emitDCOPSignal("KDE_start_screensaver()", TQByteArray());
-
- if (!restartDesktopLockProcess()) {
- mState = Waiting;
- return false;
- }
-
- switch( lock_type )
- {
- case ForceLock:
- mLockProcess.kill(SIGUSR1); // Request forcelock
- break;
- case DontLock:
- mLockProcess.kill(SIGUSR2); // Request dontlock
- break;
- case SecureDialog:
- mLockProcess.kill(SIGWINCH); // Request secure dialog
- break;
- default:
- break;
- }
- if (mBlankOnly) {
- mLockProcess.kill(SIGTTIN); // Request blanking
- }
-
- ret = mLockProcess.kill(SIGTTOU); // Start lock
- if (!ret) {
- mState = Waiting;
- return false;
- }
XSetScreenSaver(tqt_xdisplay(), 0, mXInterval, PreferBlanking, mXExposures);
-
- mState = Engaging;
- if (mXAutoLock) {
+ if (mXAutoLock)
+ {
mXAutoLock->stop();
}
- return true;
+ emitDCOPSignal("KDE_start_screensaver()", TQByteArray());
}
-//---------------------------------------------------------------------------
-//
-// Stop the screen saver.
-//
-void SaverEngine::stopLockProcess()
+void SaverEngine::stopLockProcessGUI()
{
- if (mState == Waiting) {
- kdWarning(1204) << "SaverEngine::stopSaver() saver not active" << endl;
- return;
- }
- kdDebug(1204) << "SaverEngine: stopping lock" << endl;
emitDCOPSignal("KDE_stop_screensaver()", TQByteArray());
- mTerminationRequested = true;
- mLockProcess.kill();
-
- if (mEnabled) {
- if (mXAutoLock) {
+ if (mEnabled)
+ {
+ if (mXAutoLock)
+ {
mXAutoLock->start();
}
- XForceScreenSaver(tqt_xdisplay(), ScreenSaverReset );
+ XForceScreenSaver(tqt_xdisplay(), ScreenSaverReset);
XSetScreenSaver(tqt_xdisplay(), mTimeout + 10, mXInterval, PreferBlanking, mXExposures);
}
processLockTransactions();
- mState = Waiting;
- if( systemdSession && systemdSession->canSend() ) {
+ if (systemdSession && systemdSession->canSend())
+ {
TQValueList<TQT_DBusData> params;
params << TQT_DBusData::fromBool(false);
TQT_DBusMessage reply = systemdSession->sendWithReply("SetIdleHint", params);
}
}
-void SaverEngine::recoverFromHackingAttempt()
+void SaverEngine::terminateTDESession()
{
- // Try to relaunch saver with forcelock
- if (!startLockProcess(ForceLock)) {
- // Terminate the TDE session ASAP!
- // Values are explained at http://lists.kde.org/?l=kde-linux&m=115770988603387
- TQByteArray data;
- TQDataStream arg(data, IO_WriteOnly);
- arg << (int)0 << (int)0 << (int)2;
- if (!tdeApp->dcopClient()->send("ksmserver", "default", "logout(int,int,int)", data)) {
- // Someone got to DCOP before we did
- // Try an emergency system logout
- system("logout");
- }
- }
-}
-
-void SaverEngine::lockProcessExited()
-{
- bool abnormalExit = false;
- if (!mLockProcess.normalExit()) {
- abnormalExit = true;
- }
- else {
- if (mLockProcess.exitStatus() != 0) {
- abnormalExit = true;
- }
- }
- if (mTerminationRequested) {
- abnormalExit = false;
- mTerminationRequested = false;
- }
- if (abnormalExit) {
- // PROBABLE HACKING ATTEMPT DETECTED
- restartDesktopLockProcess();
- mState = Waiting;
- TQTimer::singleShot( 100, this, TQ_SLOT(recoverFromHackingAttempt()) );
- }
- else {
- // Restart the lock process
- restartDesktopLockProcess();
+ // Terminate the TDE session ASAP!
+ // Values are explained at http://lists.kde.org/?l=kde-linux&m=115770988603387
+ TQByteArray data;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << (int)0 << (int)0 << (int)2;
+ if (!tdeApp->dcopClient()->send("ksmserver", "default", "logout(int,int,int)", data))
+ {
+ // Someone got to DCOP before we did. Try an emergency system logout
+ system("logout");
}
}
-void SaverEngineThreadHelperObject::slotLockProcessWaiting()
+void SaverEngine::lockProcessFullyActivatedGUI()
{
- // lockProcessWaiting cannot be called directly from a signal handler, as it will hang in certain obscure circumstances
- // Instead we use a single-shot timer to immediately call lockProcessWaiting once control has returned to the Qt main loop
- lockProcessWaiting();
-}
-
-void SaverEngineThreadHelperObject::slotLockProcessFullyActivated()
-{
- lockProcessFullyActivated();
-}
-
-void SaverEngine::lockProcessFullyActivated()
-{
- mState = Saving;
-
- if( systemdSession && systemdSession->canSend() ) {
+ if (systemdSession && systemdSession->canSend())
+ {
TQValueList<TQT_DBusData> params;
params << TQT_DBusData::fromBool(true);
TQT_DBusMessage reply = systemdSession->sendWithReply("SetIdleHint", params);
}
- if (mNewVTAfterLockEngage) {
+ if (mNewVTAfterLockEngage)
+ {
DM().startReserve();
mNewVTAfterLockEngage = false;
}
- else if (mSwitchVTAfterLockEngage != -1) {
+ else if (mSwitchVTAfterLockEngage != -1)
+ {
DM().switchVT(mSwitchVTAfterLockEngage);
mSwitchVTAfterLockEngage = -1;
}
}
-void SaverEngine::slotLockProcessReady()
-{
- mSaverProcessReady = true;
-}
-
-void SaverEngine::lockProcessWaiting()
+void SaverEngine::lockProcessWaitingGUI()
{
- kdDebug(1204) << "SaverEngine: lock exited" << endl;
- if (trinity_lockeng_sak_available) {
- handleSecureDialog();
- }
- if( mState == Waiting ) {
- return;
- }
emitDCOPSignal("KDE_stop_screensaver()", TQByteArray());
- if (mEnabled) {
- if (mXAutoLock) {
+ if (mEnabled)
+ {
+ if (mXAutoLock)
+ {
mXAutoLock->start();
}
- XForceScreenSaver(tqt_xdisplay(), ScreenSaverReset );
+ XForceScreenSaver(tqt_xdisplay(), ScreenSaverReset);
XSetScreenSaver(tqt_xdisplay(), mTimeout + 10, mXInterval, PreferBlanking, mXExposures);
}
processLockTransactions();
- mState = Waiting;
- if( systemdSession && systemdSession->canSend() ) {
+ if (systemdSession && systemdSession->canSend())
+ {
TQValueList<TQT_DBusData> params;
params << TQT_DBusData::fromBool(false);
TQT_DBusMessage reply = systemdSession->sendWithReply("SetIdleHint", params);
}
}
-//---------------------------------------------------------------------------
-//
// XAutoLock has detected the required idle time.
-//
void SaverEngine::idleTimeout()
{
- if (!mValidCryptoCardInserted) {
+ if (!mValidCryptoCardInserted)
+ {
// disable X screensaver
- XForceScreenSaver(tqt_xdisplay(), ScreenSaverReset );
+ XForceScreenSaver(tqt_xdisplay(), ScreenSaverReset);
XSetScreenSaver(tqt_xdisplay(), 0, mXInterval, PreferBlanking, DontAllowExposures);
- startLockProcess( DefaultLock );
+ emit activateSaverOrLockSignal(DefaultLock);
}
}
xautolock_corner_t SaverEngine::applyManualSettings(int action)
{
- if (action == 0) {
+ if (action == 0)
+ {
kdDebug() << "no lock" << endl;
return ca_nothing;
}
- else if (action == 1) {
+ else if (action == 1)
+ {
kdDebug() << "lock screen" << endl;
return ca_forceLock;
}
- else if (action == 2) {
+ else if (action == 2)
+ {
kdDebug() << "prevent lock" << endl;
return ca_dontLock;
}
- else{
+ else
+ {
kdDebug() << "no lock nothing" << endl;
return ca_nothing;
}
}
-/*!
- * This function try a reconnect to D-Bus.
+/*
+ * This function try to reconnect to D-Bus.
* \return boolean with the result of the operation
* \retval true if successful reconnected to D-Bus
* \retval false if unsuccessful
*/
-bool SaverEngine::dBusReconnect() {
- // close D-Bus connection
- dBusClose();
- // init D-Bus conntection
- return (dBusConnect());
-}
+bool SaverEngine::dBusReconnect()
+{
+ dBusClose(); // close D-Bus connection
+ return (dBusConnect()); // init D-Bus conntection
+}
-/*!
- * This function is used to close D-Bus connection.
- */
-void SaverEngine::dBusClose() {
- if( dBusConn.isConnected() ) {
- if( dBusLocal ) {
+// This function is used to close D-Bus connection.
+void SaverEngine::dBusClose()
+{
+ if (dBusConn.isConnected())
+ {
+ if (dBusLocal)
+ {
delete dBusLocal;
- dBusLocal = 0;
+ dBusLocal = nullptr;
}
- if( dBusWatch ) {
+ if (dBusWatch)
+ {
delete dBusWatch;
- dBusWatch = 0;
+ dBusWatch = nullptr;
}
- if( systemdSession ) {
+ if (systemdSession)
+ {
delete systemdSession;
- systemdSession = 0;
+ systemdSession = nullptr;
}
}
dBusConn.closeConnection(DBUS_CONN_NAME);
}
-/*!
- * This function is used to connect to D-Bus.
- */
-bool SaverEngine::dBusConnect() {
+// This function is used to connect to D-Bus.
+bool SaverEngine::dBusConnect()
+{
dBusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus, DBUS_CONN_NAME);
- if( !dBusConn.isConnected() ) {
+ if (!dBusConn.isConnected())
+ {
kdError() << "Failed to open connection to system message bus: " << dBusConn.lastError().message() << endl;
TQTimer::singleShot(4000, this, TQ_SLOT(dBusReconnect()));
return false;
@@ -856,44 +610,49 @@ bool SaverEngine::dBusConnect() {
// watcher for Disconnect signal
dBusLocal = new TQT_DBusProxy(DBUS_SERVICE_DBUS, DBUS_PATH_LOCAL, DBUS_INTERFACE_LOCAL, dBusConn);
TQObject::connect(dBusLocal, TQ_SIGNAL(dbusSignal(const TQT_DBusMessage&)),
- this, TQ_SLOT(handleDBusSignal(const TQT_DBusMessage&)));
+ this, TQ_SLOT(handleDBusSignal(const TQT_DBusMessage&)));
// watcher for NameOwnerChanged signals
dBusWatch = new TQT_DBusProxy(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, dBusConn);
TQObject::connect(dBusWatch, TQ_SIGNAL(dbusSignal(const TQT_DBusMessage&)),
- this, TQ_SLOT(handleDBusSignal(const TQT_DBusMessage&)));
+ this, TQ_SLOT(handleDBusSignal(const TQT_DBusMessage&)));
// find already running SystemD
TQT_DBusProxy checkSystemD(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, dBusConn);
- if( checkSystemD.canSend() ) {
+ if (checkSystemD.canSend())
+ {
TQValueList<TQT_DBusData> params;
params << TQT_DBusData::fromString(SYSTEMD_LOGIN1_SERVICE);
TQT_DBusMessage reply = checkSystemD.sendWithReply("NameHasOwner", params);
- if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1 && reply[0].toBool() ) {
+ if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1 && reply[0].toBool())
+ {
onDBusServiceRegistered(SYSTEMD_LOGIN1_SERVICE);
}
}
return true;
}
-/*!
- * This function handles D-Bus service registering
- */
-void SaverEngine::onDBusServiceRegistered(const TQString& service) {
- if( service == SYSTEMD_LOGIN1_SERVICE ) {
+// This function handles D-Bus service registering
+void SaverEngine::onDBusServiceRegistered(const TQString& service)
+{
+ if (service == SYSTEMD_LOGIN1_SERVICE)
+ {
// get current systemd session
TQT_DBusProxy managerIface(SYSTEMD_LOGIN1_SERVICE, SYSTEMD_LOGIN1_PATH, SYSTEMD_LOGIN1_MANAGER_IFACE, dBusConn);
TQT_DBusObjectPath systemdSessionPath = TQT_DBusObjectPath();
- if( managerIface.canSend() ) {
+ if (managerIface.canSend())
+ {
TQValueList<TQT_DBusData> params;
- params << TQT_DBusData::fromUInt32( getpid() );
+ params << TQT_DBusData::fromUInt32(getpid());
TQT_DBusMessage reply = managerIface.sendWithReply("GetSessionByPID", params);
- if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1 ) {
+ if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1)
+ {
systemdSessionPath = reply[0].toObjectPath();
}
}
// wather for systemd session signals
- if( systemdSessionPath.isValid() ) {
+ if (systemdSessionPath.isValid())
+ {
systemdSession = new TQT_DBusProxy(SYSTEMD_LOGIN1_SERVICE, systemdSessionPath, SYSTEMD_LOGIN1_SESSION_IFACE, dBusConn);
TQObject::connect(systemdSession, TQ_SIGNAL(dbusSignal(const TQT_DBusMessage&)),
this, TQ_SLOT(handleDBusSignal(const TQT_DBusMessage&)));
@@ -902,41 +661,43 @@ void SaverEngine::onDBusServiceRegistered(const TQString& service) {
}
}
-/*!
- * This function handles D-Bus service unregistering
- */
-void SaverEngine::onDBusServiceUnregistered(const TQString& service) {
- if( service == SYSTEMD_LOGIN1_SERVICE ) {
- if( systemdSession ) {
+// This function handles D-Bus service unregistering
+void SaverEngine::onDBusServiceUnregistered(const TQString& service)
+{
+ if (service == SYSTEMD_LOGIN1_SERVICE)
+ {
+ if (systemdSession)
+ {
delete systemdSession;
- systemdSession = 0;
+ systemdSession = nullptr;
}
return;
}
}
-/*!
- * This function handles signals from the D-Bus daemon.
- */
-void SaverEngine::handleDBusSignal(const TQT_DBusMessage& msg) {
+// This function handles signals from the D-Bus daemon.
+void SaverEngine::handleDBusSignal(const TQT_DBusMessage& msg)
+{
// dbus terminated
- if( msg.path() == DBUS_PATH_LOCAL
- && msg.interface() == DBUS_INTERFACE_LOCAL
- && msg.member() == "Disconnected" ) {
+ if (msg.path() == DBUS_PATH_LOCAL && msg.interface() == DBUS_INTERFACE_LOCAL &&
+ msg.member() == "Disconnected")
+ {
dBusClose();
TQTimer::singleShot(1000, this, TQ_SLOT(dBusReconnect()));
return;
}
// service registered / unregistered
- if( msg.path() == DBUS_PATH_DBUS
- && msg.interface() == DBUS_INTERFACE_DBUS
- && msg.member() == "NameOwnerChanged" ) {
- if( msg[1].toString().isEmpty() ) {
+ if (msg.path() == DBUS_PATH_DBUS && msg.interface() == DBUS_INTERFACE_DBUS &&
+ msg.member() == "NameOwnerChanged")
+ {
+ if (msg[1].toString().isEmpty())
+ {
// old-owner is empty
onDBusServiceRegistered(msg[0].toString());
}
- if( msg[2].toString().isEmpty() ) {
+ if (msg[2].toString().isEmpty())
+ {
// new-owner is empty
onDBusServiceUnregistered(msg[0].toString());
}
@@ -944,69 +705,364 @@ void SaverEngine::handleDBusSignal(const TQT_DBusMessage& msg) {
}
// systemd signal Lock()
- if( systemdSession && systemdSession->canSend()
- && msg.path() == systemdSession->path()
- && msg.interface() == SYSTEMD_LOGIN1_SESSION_IFACE
- && msg.member() == "Lock") {
+ if (systemdSession && systemdSession->canSend() && msg.path() == systemdSession->path() &&
+ msg.interface() == SYSTEMD_LOGIN1_SESSION_IFACE && msg.member() == "Lock")
+ {
lockScreen();
return;
}
// systemd signal Unlock()
- if( systemdSession && systemdSession->canSend()
- && msg.path() == systemdSession->path()
- && msg.interface() == SYSTEMD_LOGIN1_SESSION_IFACE
- && msg.member() == "Unlock") {
+ if (systemdSession && systemdSession->canSend() && msg.path() == systemdSession->path() &&
+ msg.interface() == SYSTEMD_LOGIN1_SESSION_IFACE && msg.member() == "Unlock")
+ {
// unlock?
return;
}
}
-bool SaverEngine::waitForLockProcessStart() {
- sigset_t new_mask;
- sigset_t empty_mask;
- sigemptyset(&empty_mask);
+void SaverEngine::lockScreenAndDoNewSession()
+{
+ mNewVTAfterLockEngage = true;
+ lockScreen();
+}
- // ensure that SIGCHLD is not subject to a race condition
- sigemptyset(&new_mask);
- sigaddset(&new_mask, SIGCHLD);
+void SaverEngine::lockScreenAndSwitchSession(int vt)
+{
+ mSwitchVTAfterLockEngage = vt;
+ lockScreen();
+}
- pthread_sigmask(SIG_BLOCK, &new_mask, NULL);
- while ((mLockProcess.isRunning()) && (!mSaverProcessReady)) {
- // wait for any signal(s) to arrive
- sigsuspend(&empty_mask);
+SaverEngineEventHandler::SaverEngineEventHandler(SaverEngine *engine) :
+ m_state(Waiting), m_saverProcessReady(false), m_lockProcessRestarting(false),
+ m_terminationRequest(false), m_saverEngine(engine), m_SAKProcess(nullptr)
+{
+ connect(&m_lockProcess, TQ_SIGNAL(processExited(TDEProcess*)),
+ this, TQ_SLOT(slotLockProcessExited()));
+}
+
+void SaverEngineEventHandler::terminateLockProcess()
+{
+ if (m_state == Waiting)
+ {
+ kill(m_lockProcess.pid(), SIGKILL);
+ }
+ m_lockProcess.detach(); // don't kill it if we crash
+}
+
+void SaverEngineEventHandler::lockProcessExited()
+{
+ kdDebug(1204) << "SaverEngineEventHandler: lock exited" << endl;
+
+ if (trinity_lockeng_sak_available)
+ {
+ startSAKProcess();
+ }
+ if (m_state == Waiting)
+ {
+ return;
}
- pthread_sigmask(SIG_UNBLOCK, &new_mask, NULL);
- return mLockProcess.isRunning();
+ m_state = Waiting;
+ TQTimer::singleShot(0, m_saverEngine, TQ_SLOT(lockProcessWaitingGUI()));
}
-bool SaverEngine::waitForLockEngage() {
- sigset_t empty_mask;
- sigemptyset(&empty_mask);
+void SaverEngineEventHandler::lockProcessFullyActivated()
+{
+ m_state = Saving;
+ TQTimer::singleShot(0, m_saverEngine, TQ_SLOT(lockProcessFullyActivatedGUI()));
+}
- // wait for SIGUSR1, SIGUSR2, SIGTTIN
- while ((mLockProcess.isRunning()) && (mState != Waiting) && (mState != Saving)) {
- // wait for any signal(s) to arrive
- sigsuspend(&empty_mask);
+void SaverEngineEventHandler::lockProcessReady()
+{
+ m_saverProcessReady = true;
+}
+
+void SaverEngineEventHandler::lockScreen(bool dcop)
+{
+ if (m_lockProcessRestarting)
+ {
+ kdDebug(1204) << "SaverEngineEventHandler: lock process is restarting, can't handle lock request" << endl;
+ return;
}
- return mLockProcess.isRunning();
+ bool ok = true;
+ if (m_state == Waiting)
+ {
+ ok = activateSaverOrLock(ForceLock);
+ // It takes a while for kdesktop_lock to start and lock the screen.
+ // Therefore delay the DCOP call until it tells kdesktop that the locking is in effect.
+ // This is done only for --forcelock .
+ if (ok && m_state != Saving)
+ {
+ if (dcop)
+ {
+ TQTimer::singleShot(0, m_saverEngine, TQ_SLOT(lockScreenGUI()));
+ }
+ }
+ }
}
-void SaverEngine::lockScreenAndDoNewSession() {
- mNewVTAfterLockEngage = true;
- lockScreen();
+void SaverEngineEventHandler::saveScreen()
+{
+ if (m_lockProcessRestarting)
+ {
+ kdDebug(1204) << "SaverEngineEventHandler: lock process is restarting, can't handle save request" << endl;
+ return;
+ }
+
+ if (m_state == Waiting)
+ {
+ activateSaverOrLock(DefaultLock);
+ }
}
-void SaverEngine::lockScreenAndSwitchSession(int vt) {
- mSwitchVTAfterLockEngage = vt;
- lockScreen();
+void SaverEngineEventHandler::slotLockProcessExited()
+{
+ m_lockProcessRestarting = true;
+
+ bool abnormalExit = false;
+ if (!m_lockProcess.normalExit())
+ {
+ abnormalExit = true;
+ }
+ else if (m_lockProcess.exitStatus() != 0)
+ {
+ abnormalExit = true;
+ }
+ if (m_terminationRequest)
+ {
+ abnormalExit = false;
+ m_terminationRequest = false;
+ }
+
+ // Restart the lock process. This call blocks till
+ // the lock process has restarted.
+ restartLockProcess();
+
+ if (abnormalExit)
+ {
+ // Possible hacking attempt detected, try to relaunch the saver with force lock
+ m_state = Waiting;
+ if (!activateSaverOrLock(ForceLock))
+ {
+ TQTimer::singleShot(0, m_saverEngine, TQ_SLOT(terminateTDESession()));
+ }
+ }
+ m_lockProcessRestarting = false;
}
-void SaverEngineThreadHelperObject::terminateThread() {
- TQEventLoop* eventLoop = TQApplication::eventLoop();
- if (eventLoop) {
+/*
+ * Start or restart the lock process.
+ * On the very first invocation, launch the SAK process if required and
+ * auto lock the screen if the option has been enabled in the configuration.
+ */
+bool SaverEngineEventHandler::restartLockProcess()
+{
+ static bool firstStart = true;
+
+ bool autoLoginEnable = false;
+ bool autoLoginLocked = false;
+ if (firstStart)
+ {
+ firstStart = false;
+
+ // Create SAK process only if SAK is enabled
+ struct stat st;
+ KSimpleConfig *config;
+ if (stat(KDE_CONFDIR "/tdm/tdmdistrc" , &st) == 0)
+ {
+ config = new KSimpleConfig(TQString::fromLatin1(KDE_CONFDIR "/tdm/tdmdistrc"));
+ }
+ else
+ {
+ config = new KSimpleConfig(TQString::fromLatin1(KDE_CONFDIR "/tdm/tdmrc"));
+ }
+ config->setGroup("X-:*-Greeter");
+ bool useSAKProcess = false;
+#ifdef BUILD_TSAK
+ useSAKProcess = config->readBoolEntry("UseSAK", false) && KDesktopSettings::useTDESAK();
+#endif
+ if (useSAKProcess)
+ {
+ startSAKProcess();
+ }
+
+ // autolock the desktop if required
+ config->setGroup("X-:0-Core");
+ autoLoginEnable = config->readBoolEntry("AutoLoginEnable", false);
+ autoLoginLocked = config->readBoolEntry("AutoLoginLocked", false);
+ delete config;
+ }
+
+ // (Re)start the lock process
+ if (!m_lockProcess.isRunning())
+ {
+ m_lockProcess.clearArguments();
+ TQString path = TDEStandardDirs::findExe("kdesktop_lock");
+ if (path.isEmpty())
+ {
+ kdDebug(1204) << "Can't find kdesktop_lock!" << endl;
+ return false;
+ }
+ m_lockProcess << path;
+ m_lockProcess << TQString("--internal") << TQString("%1").arg(getpid());
+
+ m_saverProcessReady = false;
+ if (!m_lockProcess.start())
+ {
+ kdDebug(1204) << "Failed to start kdesktop_lock!" << endl;
+ return false;
+ }
+ // Wait for the lock process to signal that it is ready
+ sigset_t empty_mask;
+ sigemptyset(&empty_mask);
+ while (!m_saverProcessReady)
+ {
+ sigsuspend(&empty_mask);
+ }
+ if (!m_lockProcess.isRunning())
+ {
+ kdDebug(1204) << "Failed to initialize kdesktop_lock (unexpected termination)!" << endl;
+ return false;
+ }
+ }
+
+ if (autoLoginEnable && autoLoginLocked)
+ {
+ m_lockProcess.kill(SIGTTOU);
+ m_lockProcess.kill(SIGUSR1);
+ }
+ return true;
+}
+
+// Start the screen saver or lock screen
+bool SaverEngineEventHandler::activateSaverOrLock(LockType lock_type)
+{
+ if (m_state == Saving)
+ {
+ return true;
+ }
+
+ kdDebug(1204) << "SaverEngineEventHandler: starting saver" << endl;
+ m_state = Preparing;
+ if (m_SAKProcess)
+ {
+ m_SAKProcess->kill(SIGTERM);
+ }
+
+ m_saverEngine->enableExports();
+ if (!restartLockProcess())
+ {
+ m_state = Waiting;
+ return false;
+ }
+
+ switch (lock_type)
+ {
+ case ForceLock:
+ m_lockProcess.kill(SIGUSR1); // Request forcelock
+ break;
+ case DontLock:
+ m_lockProcess.kill(SIGUSR2); // Request dontlock
+ break;
+ case SecureDialog:
+ m_lockProcess.kill(SIGWINCH); // Request secure dialog
+ break;
+ default:
+ break;
+ }
+
+ if (m_saverEngine->mBlankOnly)
+ {
+ m_lockProcess.kill(SIGTTIN); // Request blanking
+ }
+
+ int ret = m_lockProcess.kill(SIGTTOU); // Start lock
+ if (!ret)
+ {
+ m_state = Waiting;
+ return false;
+ }
+ m_state = Engaging;
+
+ // Ask to the GUI thread to activate X11 saver
+ TQTimer::singleShot(0, m_saverEngine, TQ_SLOT(activateSaverOrLockGUI()));
+
+ return true;
+}
+
+// Stop the screen saver.
+void SaverEngineEventHandler::stopLockProcess()
+{
+ if (m_state == Waiting)
+ {
+ return;
+ }
+
+ kdDebug(1204) << "SaverEngineEventHandler: stopping lock process" << endl;
+
+ m_terminationRequest = true;
+ m_lockProcess.kill();
+ m_state = Waiting;
+
+ // Ask to the GUI thread to stop the X11 saver
+ TQTimer::singleShot(0, m_saverEngine, TQ_SLOT(stopLockProcessGUI()));
+}
+
+void SaverEngineEventHandler::startSAKProcess()
+{
+ if (!m_SAKProcess)
+ {
+ m_SAKProcess = new TDEProcess;
+ *m_SAKProcess << "tdmtsak";
+ connect(m_SAKProcess, TQ_SIGNAL(processExited(TDEProcess*)), this, TQ_SLOT(slotSAKProcessExited()));
+ }
+ if (!m_SAKProcess->isRunning())
+ {
+ m_SAKProcess->start();
+ }
+}
+
+void SaverEngineEventHandler::slotSAKProcessExited()
+{
+ if (!m_SAKProcess)
+ {
+ tqWarning("[kdesktop] SAK process does not exist. Something went wrong. Ignoring.");
+ return;
+ }
+
+ int retcode = m_SAKProcess->exitStatus();
+ if (retcode && m_SAKProcess->normalExit())
+ {
+ trinity_lockeng_sak_available = false;
+ tqWarning("[kdesktop] SAK driven secure dialog is not available for use (retcode %d). "
+ "Check tdmtsak for proper functionality.", retcode);
+ }
+
+ if (m_state == Preparing)
+ {
+ return;
+ }
+
+ if (m_SAKProcess->normalExit() && trinity_lockeng_sak_available)
+ {
+ if (m_state == Waiting)
+ {
+ activateSaverOrLock(SecureDialog);
+ }
+ else
+ {
+ m_lockProcess.kill(SIGHUP);
+ }
+ }
+}
+
+void SaverEngineEventHandler::terminateThread()
+{
+ TQEventLoop *eventLoop = TQApplication::eventLoop();
+ if (eventLoop)
+ {
eventLoop->exit(0);
}
}
diff --git a/kdesktop/lockeng.h b/kdesktop/lockeng.h
index d9285abc1..94d8f9e44 100644
--- a/kdesktop/lockeng.h
+++ b/kdesktop/lockeng.h
@@ -1,6 +1,5 @@
-//===========================================================================
//
-// This file is part of the KDE project
+// This file is part of the TDE project
//
// Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
//
@@ -8,7 +7,6 @@
#ifndef __LOCKENG_H__
#define __LOCKENG_H__
-#include <tqwidget.h>
#include <tqthread.h>
#include <tdeprocess.h>
#include <tqvaluevector.h>
@@ -23,31 +21,48 @@ class TDECryptographicCardDevice;
#else
#define TDECryptographicCardDevice void
#endif
+
+/**
+ * Screen saver engine. Handles communication with the lock process.
+ * The engine is split into two parts, the 'SaverEngine' running in the GUI thread and
+ * the 'SaverEngineEventHandler' running in a separate thread and eventloop.
+ * The 'SaverEngine' handles communication with X11, DCOP and DBUS while the
+ * 'SaverEngineEventHandler' handles communication with the actual lock process.
+ * Several actions require cooperation of the two parts, so in various methods
+ * there will be inter-thread calls (using timers or by emitting signals) to
+ * trigger the other side remaining logic.
+ * This complex design is necessary to avoid blocking the main GUI application event loop,
+ * which has several tasks to manage and therefore can't affort to wait in a suspended state.
+ * This was previously leading to deadlock when DCOP calls where executed on the secondary
+ * thread/eventloop, for example when changing desktop while the lock process was restarting.
+ */
+
class DCOPClientTransaction;
class TQT_DBusMessage;
class TQT_DBusProxy;
+class SaverEngineEventHandler;
-class SaverEngineThreadHelperObject : public TQObject
+// Type of lock screen
+enum LockType : int
{
- TQ_OBJECT
-
-public slots:
- void terminateThread();
- void slotLockProcessWaiting();
- void slotLockProcessFullyActivated();
+ DontLock = 0,
+ DefaultLock,
+ ForceLock,
+ SecureDialog
+};
-signals:
- void lockProcessWaiting();
- void lockProcessFullyActivated();
+enum SaverState
+{
+ Waiting,
+ Preparing,
+ Engaging,
+ Saving
};
-//===========================================================================
-/**
- * Screen saver engine. Handles screensaver window, starting screensaver
- * hacks, and password entry.
- */
-class SaverEngine : public TQWidget, public KScreensaverIface
+class SaverEngine : public TQObject, public KScreensaverIface
{
+ friend class SaverEngineEventHandler;
+
TQ_OBJECT
public:
SaverEngine();
@@ -100,80 +115,53 @@ public:
*/
virtual void saverLockReady();
- /**
- * @internal
- */
void lockScreen(bool DCOP = false);
- /**
- * Called by KDesktop to wait for saver engage
- * @internal
- */
- bool waitForLockEngage();
-
- /**
- * @internal
- */
void lockScreenAndDoNewSession();
-
- /**
- * @internal
- */
void lockScreenAndSwitchSession(int vt);
+ void enableExports(); // Enable wallpaper exports
+
signals:
- void terminateHelperThread();
- void asyncLock();
+ void activateSaverOrLockSignal(LockType lock_type);
+ void lockScreenSignal(bool);
+ void terminateEventHandlerThread();
public slots:
- void slotLockProcessReady();
- void lockProcessWaiting();
- void lockProcessFullyActivated();
void handleDBusSignal(const TQT_DBusMessage&);
+ void terminateTDESession();
protected slots:
void idleTimeout();
- void lockProcessExited();
private slots:
- void handleSecureDialog();
- void slotSAKProcessExited();
-
void cryptographicCardInserted(TDECryptographicCardDevice*);
void cryptographicCardRemoved(TDECryptographicCardDevice*);
-
- /**
- * Enable wallpaper exports
- */
- void enableExports();
- void recoverFromHackingAttempt();
void cardStartupTimeout();
-
bool dBusReconnect();
+ // The following slots are invoked by corresponding methods named without the 'GUI' suffix
+ // in 'SaverEngineEventHandler' to complete the remaining X11 part of the actions
+ void activateSaverOrLockGUI();
+ void lockProcessFullyActivatedGUI();
+ void lockProcessWaitingGUI();
+ void lockScreenGUI();
+ void stopLockProcessGUI();
+
private:
- bool restartDesktopLockProcess();
void dBusClose();
bool dBusConnect();
void onDBusServiceRegistered(const TQString&);
void onDBusServiceUnregistered(const TQString&);
protected:
- enum SaverState { Waiting, Preparing, Engaging, Saving };
- enum LockType { DontLock, DefaultLock, ForceLock, SecureDialog };
- bool startLockProcess( LockType lock_type );
- bool waitForLockProcessStart();
- void stopLockProcess();
- bool handleKeyPress(XKeyEvent *xke);
void processLockTransactions();
xautolock_corner_t applyManualSettings(int);
protected:
bool mEnabled;
- SaverState mState;
XAutoLock *mXAutoLock;
- TDEProcess mLockProcess;
int mTimeout;
// the original X screensaver parameters
@@ -182,26 +170,60 @@ protected:
int mXBlanking;
int mXExposures;
- bool mBlankOnly; // only use the blanker, not the defined saver
TQValueVector< DCOPClientTransaction* > mLockTransactions;
public:
- SaverEngineThreadHelperObject* m_threadHelperObject;
+ bool mBlankOnly; // only use the blanker, not the defined saver // protected
+ SaverEngineEventHandler *m_saverEngineEventHandler;
private:
- TQEventLoopThread* m_helperThread;
- sigset_t mThreadBlockSet;
- TDEProcess* mSAKProcess;
- bool mTerminationRequested;
- bool mSaverProcessReady;
+ TQEventLoopThread* m_eventHandlerThread;
bool mNewVTAfterLockEngage;
bool mValidCryptoCardInserted;
int mSwitchVTAfterLockEngage;
struct sigaction mSignalAction;
TQT_DBusConnection dBusConn;
- TQT_DBusProxy* dBusLocal;
- TQT_DBusProxy* dBusWatch;
- TQT_DBusProxy* systemdSession;
+ TQT_DBusProxy *dBusLocal;
+ TQT_DBusProxy *dBusWatch;
+ TQT_DBusProxy *systemdSession;
+};
+
+class SaverEngineEventHandler : public TQObject
+{
+ TQ_OBJECT
+
+public:
+ SaverEngineEventHandler(SaverEngine *engine);
+
+ SaverState getState() const { return m_state; }
+
+ void lockProcessExited();
+ void lockProcessFullyActivated();
+ void lockProcessReady();
+ void terminateLockProcess();
+
+public slots:
+ bool activateSaverOrLock(LockType lock_type);
+ void lockScreen(bool DCOP = false);
+ bool restartLockProcess();
+ void saveScreen();
+ void stopLockProcess();
+ void terminateThread();
+
+protected slots:
+ void slotLockProcessExited();
+ void slotSAKProcessExited();
+
+protected:
+ void startSAKProcess();
+
+ bool m_saverProcessReady;
+ bool m_lockProcessRestarting;
+ bool m_terminationRequest;
+ SaverState m_state;
+ SaverEngine *m_saverEngine;
+ TDEProcess *m_SAKProcess;
+ TDEProcess m_lockProcess;
};
#endif
diff --git a/kdesktop/main.cpp b/kdesktop/main.cpp
index f3e61e2f2..0465068b6 100644
--- a/kdesktop/main.cpp
+++ b/kdesktop/main.cpp
@@ -71,7 +71,7 @@ static TDECmdLineOptions options[] =
};
bool argb_visual = false;
-KDesktopApp *myApp = NULL;
+KDesktopApp *myApp = nullptr;
// -----------------------------------------------------------------------------
@@ -251,7 +251,7 @@ extern "C" TDE_EXPORT int kdemain( int argc, char **argv )
else
XCloseDisplay( dpy );
}
- if( myApp == NULL )
+ if (!myApp)
myApp = new KDesktopApp;
#else
myApp = new KDesktopApp;
@@ -260,9 +260,6 @@ extern "C" TDE_EXPORT int kdemain( int argc, char **argv )
KDesktopSettings::instance(kdesktop_name + "rc");
- bool x_root_hack = args->isSet("x-root");
- bool wait_for_kded = args->isSet("waitforkded");
-
// This MUST be created before any widgets are created
SaverEngine saver;
@@ -279,16 +276,15 @@ extern "C" TDE_EXPORT int kdemain( int argc, char **argv )
myApp->config()->reparseConfiguration();
}
- // for the KDE-already-running check in starttde
- TDESelectionOwner kde_running( "_KDE_RUNNING", 0 );
- kde_running.claim( false );
+ // for the TDE-already-running check in starttde
+ TDESelectionOwner tde_running( "_KDE_RUNNING", 0 );
+ tde_running.claim( false );
+ bool x_root_hack = args->isSet("x-root");
+ bool wait_for_kded = args->isSet("waitforkded");
KDesktop desktop( &saver, x_root_hack, wait_for_kded );
args->clear();
-
myApp->dcopClient()->setDefaultObject( "KDesktopIface" );
-
-
return myApp->exec();
}