Merge branch 'central-widget'
[krunner.git] / saverengine.cpp
blob790eed2d9ea52fa5d87f16c27daf27cca1d8fa49
1 //===========================================================================
2 //
3 // This file is part of the KDE project
4 //
5 // Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
6 //
9 #include "saverengine.h"
10 #include "kscreensaversettings.h"
11 #include "screensaveradaptor.h"
13 #include <kstandarddirs.h>
14 #include <kapplication.h>
15 #include <kservicegroup.h>
16 #include <krandom.h>
17 #include <kdebug.h>
18 #include <klocale.h>
19 #include <QFile>
20 #include <QX11Info>
21 #include <assert.h>
22 #include <stdlib.h>
23 #include <time.h>
25 #include "xautolock_c.h"
26 extern xautolock_corner_t xautolock_corners[ 4 ];
28 //===========================================================================
30 // Screen saver engine. Doesn't handle the actual screensaver window,
31 // starting screensaver hacks, or password entry. That's done by
32 // a newly started process.
34 SaverEngine::SaverEngine()
35 : QWidget(),
36 screensaverService( QDBusConnection::connectToBus( QDBusConnection::SessionBus,
37 "org.freedesktop.ScreenSaver" ) )
39 (void) new ScreenSaverAdaptor( this );
40 screensaverService.registerService( "org.freedesktop.ScreenSaver" ) ;
41 screensaverService.registerObject( "/ScreenSaver", this );
43 // Save X screensaver parameters
44 XGetScreenSaver(QX11Info::display(), &mXTimeout, &mXInterval,
45 &mXBlanking, &mXExposures);
47 mState = Waiting;
48 mXAutoLock = 0;
49 mEnabled = false;
51 m_nr_throttled = 0;
52 m_nr_inhibited = 0;
53 m_actived_time = -1;
55 connect(&mLockProcess, SIGNAL(processExited(K3Process *)),
56 SLOT(lockProcessExited()));
58 QObject::connect(QDBusConnection::sessionBus().interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)),
59 SLOT(serviceOwnerChanged(QString,QString,QString)));
61 // I make it a really random number to avoid
62 // some assumptions in clients, but just increase
63 // while gnome-ss creates a random number every time
64 m_next_cookie = KRandom::random() % 20000;
65 configure();
68 //---------------------------------------------------------------------------
70 // Destructor - usual cleanups.
72 SaverEngine::~SaverEngine()
74 mLockProcess.detach(); // don't kill it if we crash
75 delete mXAutoLock;
77 // Restore X screensaver parameters
78 XSetScreenSaver(QX11Info::display(), mXTimeout, mXInterval, mXBlanking,
79 mXExposures);
82 //---------------------------------------------------------------------------
84 // This should be called only using DBus.
85 void SaverEngine::Lock()
87 bool ok = true;
88 if (mState == Waiting)
90 ok = startLockProcess( ForceLock );
91 // It takes a while for krunner_lock to start and lock the screen.
92 // Therefore delay the DBus call until it tells krunner that the locking is in effect.
93 // This is done only for --forcelock .
94 if( ok && mState != Saving )
96 #ifdef __GNUC__
97 #warning port dcop transactions to dbus
98 #endif
99 #if 0
100 DCOPClientTransaction* trans = kapp->dcopClient()->beginTransaction();
101 mLockTransactions.append( trans );
102 #endif
105 else
107 mLockProcess.kill( SIGHUP );
111 void SaverEngine::processLockTransactions()
113 #ifdef __GNUC__
114 #warning port dcop transactions to dbus
115 #endif
116 #if 0
117 for( QVector< DCOPClientTransaction* >::ConstIterator it = mLockTransactions.begin();
118 it != mLockTransactions.end();
119 ++it )
121 DCOPCString replyType = "void";
122 QByteArray arr;
123 kapp->dcopClient()->endTransaction( *it, replyType, arr );
125 mLockTransactions.clear();
126 #endif
129 void SaverEngine::saverLockReady()
131 if( mState != Preparing )
133 kDebug() << "Got unexpected saverReady()" << endl;
135 kDebug() << "Saver Lock Ready" << endl;
136 processLockTransactions();
139 void SaverEngine::SimulateUserActivity()
141 if ( mState == Waiting )
143 // disable
144 XSetScreenSaver(QX11Info::display(), 0, mXInterval, PreferBlanking, mXExposures);
145 mXAutoLock->resetTrigger();
146 // reenable
147 XSetScreenSaver(QX11Info::display(), mTimeout + 10, mXInterval, PreferBlanking, mXExposures);
151 //---------------------------------------------------------------------------
152 bool SaverEngine::save()
154 if (mState == Waiting)
156 return startLockProcess( DefaultLock );
158 return false;
161 //---------------------------------------------------------------------------
162 bool SaverEngine::quit()
164 if (mState == Saving || mState == Preparing)
166 stopLockProcess();
167 return true;
169 return false;
172 //---------------------------------------------------------------------------
173 bool SaverEngine::isEnabled()
175 return mEnabled;
178 //---------------------------------------------------------------------------
179 bool SaverEngine::enable( bool e )
181 if ( e == mEnabled )
182 return true;
184 // If we aren't in a suitable state, we will not reconfigure.
185 if (mState != Waiting)
186 return false;
188 mEnabled = e;
190 if (mEnabled)
192 if ( !mXAutoLock ) {
193 mXAutoLock = new XAutoLock();
194 connect(mXAutoLock, SIGNAL(timeout()), SLOT(idleTimeout()));
196 mXAutoLock->setTimeout(mTimeout);
197 mXAutoLock->setDPMS(mDPMS);
198 //mXAutoLock->changeCornerLockStatus( mLockCornerTopLeft, mLockCornerTopRight, mLockCornerBottomLeft, mLockCornerBottomRight);
200 // We'll handle blanking
201 XSetScreenSaver(QX11Info::display(), mTimeout + 10, mXInterval, PreferBlanking, mXExposures);
202 kDebug() << "XSetScreenSaver " << mTimeout + 10 << endl;
204 mXAutoLock->start();
206 kDebug() << "Saver Engine started, timeout: " << mTimeout << endl;
208 else
210 if (mXAutoLock)
212 delete mXAutoLock;
213 mXAutoLock = 0;
216 XForceScreenSaver(QX11Info::display(), ScreenSaverReset );
217 XSetScreenSaver(QX11Info::display(), 0, mXInterval, PreferBlanking, DontAllowExposures);
218 kDebug() << "Saver Engine disabled" << endl;
221 return true;
224 //---------------------------------------------------------------------------
225 bool SaverEngine::isBlanked()
227 return (mState != Waiting);
230 //---------------------------------------------------------------------------
232 // Read and apply configuration.
234 void SaverEngine::configure()
236 // If we aren't in a suitable state, we will not reconfigure.
237 if (mState != Waiting)
238 return;
240 // create a new config obj to ensure we read the latest options
241 KScreenSaverSettings::self()->readConfig();
243 bool e = KScreenSaverSettings::screenSaverEnabled();
244 kDebug() << "enabled " << e << endl;
245 mTimeout = KScreenSaverSettings::timeout();
246 mDPMS = KScreenSaverSettings::dpmsDependent();
248 mEnabled = !e; // force the enable()
250 int action;
251 action = KScreenSaverSettings::actionTopLeft();
252 xautolock_corners[0] = applyManualSettings(action);
253 action = KScreenSaverSettings::actionTopRight();
254 xautolock_corners[1] = applyManualSettings(action);
255 action = KScreenSaverSettings::actionBottomLeft();
256 xautolock_corners[2] = applyManualSettings(action);
257 action = KScreenSaverSettings::actionBottomRight();
258 xautolock_corners[3] = applyManualSettings(action);
260 enable( e );
263 //---------------------------------------------------------------------------
265 // Start the screen saver.
267 bool SaverEngine::startLockProcess( LockType lock_type )
269 if (mState != Waiting)
270 return true;
272 kDebug() << "SaverEngine: starting saver" << endl;
273 emit ActiveChanged(true); // DBus signal
275 if (mLockProcess.isRunning())
277 stopLockProcess();
279 mLockProcess.clearArguments();
280 QString path = KStandardDirs::findExe( "krunner_lock" );
281 if( path.isEmpty())
283 kDebug() << "Can't find krunner_lock!" << endl;
284 return false;
286 mLockProcess << path;
287 switch( lock_type )
289 case ForceLock:
290 mLockProcess << QString( "--forcelock" );
291 break;
292 case DontLock:
293 mLockProcess << QString( "--dontlock" );
294 break;
295 default:
296 break;
298 if (m_nr_throttled)
299 mLockProcess << QString( "--blank" );
301 m_actived_time = time( 0 );
302 if (mLockProcess.start() == false )
304 kDebug() << "Failed to start krunner_lock!" << endl;
305 m_actived_time = -1;
306 return false;
309 XSetScreenSaver(QX11Info::display(), 0, mXInterval, PreferBlanking, mXExposures);
310 mState = Preparing;
311 if (mXAutoLock)
313 mXAutoLock->stop();
315 return true;
318 //---------------------------------------------------------------------------
320 // Stop the screen saver.
322 void SaverEngine::stopLockProcess()
324 m_actived_time = -1;
325 if (mState == Waiting)
327 kWarning() << "SaverEngine::stopSaver() saver not active" << endl;
328 return;
330 kDebug() << "SaverEngine: stopping lock" << endl;
331 emit ActiveChanged(false); // DBus signal
333 mLockProcess.kill();
335 if (mXAutoLock)
337 mXAutoLock->start();
339 processLockTransactions();
340 mState = Waiting;
341 XForceScreenSaver(QX11Info::display(), ScreenSaverReset );
342 XSetScreenSaver(QX11Info::display(), mTimeout + 10, mXInterval, PreferBlanking, mXExposures);
345 void SaverEngine::lockProcessExited()
347 m_actived_time = -1;
348 kDebug() << "SaverEngine: lock exited" << endl;
349 if( mState == Waiting )
350 return;
351 emit ActiveChanged(false); // DBus signal
352 if (mXAutoLock)
354 mXAutoLock->start();
356 processLockTransactions();
357 mState = Waiting;
358 XForceScreenSaver(QX11Info::display(), ScreenSaverReset );
359 XSetScreenSaver(QX11Info::display(), mTimeout + 10, mXInterval, PreferBlanking, mXExposures);
362 //---------------------------------------------------------------------------
364 // XAutoLock has detected the required idle time.
366 void SaverEngine::idleTimeout()
368 // disable X screensaver
369 XForceScreenSaver(QX11Info::display(), ScreenSaverReset );
370 XSetScreenSaver(QX11Info::display(), 0, mXInterval, PreferBlanking, DontAllowExposures);
371 startLockProcess( DefaultLock );
374 xautolock_corner_t SaverEngine::applyManualSettings(int action)
376 if (action == 0)
378 kDebug() << "no lock" << endl;
379 return ca_nothing;
381 else if (action == 1)
383 kDebug() << "lock screen" << endl;
384 return ca_forceLock;
386 else if (action == 2)
388 kDebug() << "prevent lock" << endl;
389 return ca_dontLock;
391 else
393 kDebug() << "no lock nothing" << endl;
394 return ca_nothing;
398 uint SaverEngine::GetSessionIdleTime()
400 return mXAutoLock->idleTime();
403 bool SaverEngine::GetSessionIdle()
405 // pointless?
406 return ( GetSessionIdleTime() > 0 );
409 uint SaverEngine::GetActiveTime()
411 if ( m_actived_time == -1 )
412 return 0;
413 return time( 0 ) - m_actived_time;
416 bool SaverEngine::GetActive()
418 return ( mState != Waiting );
421 bool SaverEngine::SetActive(bool state)
423 if ( state )
424 return save();
425 else
426 return quit();
429 uint SaverEngine::Inhibit(const QString &application_name, const QString &reason_for_inhibit)
431 ScreenSaverRequest sr;
432 sr.appname = application_name;
433 sr.reasongiven = reason_for_inhibit;
434 sr.cookie = m_next_cookie++;
435 sr.dbusid = "unknown"; // see below for throttle
436 sr.type = ScreenSaverRequest::Inhibit;
437 m_requests.append( sr );
438 m_nr_inhibited++;
439 enable( false );
440 return sr.cookie;
443 void SaverEngine::UnInhibit(uint cookie)
445 QMutableListIterator<ScreenSaverRequest> it( m_requests );
446 while ( it.hasNext() )
448 if ( it.next().cookie == cookie ) {
449 it.remove();
450 m_nr_inhibited--;
451 if ( m_nr_inhibited <= 0 )
452 enable( true );
457 uint SaverEngine::Throttle(const QString &application_name, const QString &reason_for_inhibit)
459 ScreenSaverRequest sr;
460 sr.appname = application_name;
461 sr.reasongiven = reason_for_inhibit;
462 sr.cookie = m_next_cookie++;
463 sr.type = ScreenSaverRequest::Throttle;
464 #warning thiago says Qt 4.3 can query the dbus connection id in adaptors - waiting
465 sr.dbusid = "unknown"; // see above for inhibit
466 m_requests.append( sr );
467 m_nr_throttled++;
468 mLockProcess.suspend();
469 return sr.cookie;
472 void SaverEngine::UnThrottle(uint cookie)
474 QMutableListIterator<ScreenSaverRequest> it( m_requests );
475 while ( it.hasNext() )
477 if ( it.next().cookie == cookie ) {
478 it.remove();
479 m_nr_throttled--;
480 if ( m_nr_throttled <= 0 )
481 mLockProcess.resume();
486 void SaverEngine::serviceOwnerChanged(const QString& name,const QString &oldOwner,const QString &newOwner)
488 Q_UNUSED( oldOwner );
490 if ( !newOwner.isEmpty() ) // looking for deaths
491 return;
493 QListIterator<ScreenSaverRequest> it( m_requests );
494 while ( it.hasNext() )
496 ScreenSaverRequest r = it.next();
497 if ( r.dbusid == name )
499 if ( r.type == ScreenSaverRequest::Throttle )
500 UnThrottle( r.cookie );
501 else
502 UnInhibit( r.cookie );
507 #include "saverengine.moc"