1
//----------------------------------------------------------------------------
3
// This file is part of the KDE project
5
// Copyright 1999 Martin R. Jones <mjones@kde.org>
6
// Copyright 2003 Lubos Lunak <l.lunak@kde.org>
8
// KDE screensaver engine
11
#include <config-workspace.h>
13
#include "xautolock.h"
14
#include "xautolock_c.h"
16
#include <kapplication.h>
19
#include <QTimerEvent>
23
#include <X11/Xutil.h>
31
#include <X11/extensions/dpms.h>
33
#ifndef HAVE_DPMSINFO_PROTO
34
Status DPMSInfo ( Display *, CARD16 *, BOOL * );
41
xautolock_corner_t xautolock_corners[ 4 ];
43
static XAutoLock* self = NULL;
46
static int catchFalseAlarms(Display *, XErrorEvent *)
52
//===========================================================================
54
// Detect user inactivity.
55
// Named XAutoLock after the program that it is based on.
57
XAutoLock::XAutoLock()
60
#ifdef HAVE_XSCREENSAVER
63
if (XScreenSaverQueryExtension( QX11Info::display(), &dummy, &dummy ))
65
mMitInfo = XScreenSaverAllocInfo();
70
kapp->installX11EventFilter( this );
71
int (*oldHandler)(Display *, XErrorEvent *);
72
oldHandler = XSetErrorHandler(catchFalseAlarms);
73
XSync(QX11Info::display(), False );
74
xautolock_initDiy( QX11Info::display());
75
XSync(QX11Info::display(), False );
76
XSetErrorHandler(oldHandler);
79
mTimeout = DEFAULT_TIMEOUT;
85
mTimerId = startTimer( CHECK_INTERVAL );
86
// This is an internal clock timer (in seconds), used instead of querying system time.
87
// It is incremented manually, preventing from problems with clock jumps.
88
// In other words, this is the 'now' time and the reference point for other times here.
92
//---------------------------------------------------------------------------
96
XAutoLock::~XAutoLock()
102
//---------------------------------------------------------------------------
104
// The time in seconds of continuous inactivity.
106
void XAutoLock::setTimeout(int t)
111
void XAutoLock::setDPMS(bool s)
116
DPMSInfo( QX11Info::display(), &state, &on );
123
//---------------------------------------------------------------------------
125
// Start watching Activity
127
void XAutoLock::start()
133
//---------------------------------------------------------------------------
135
// Stop watching Activity
137
void XAutoLock::stop()
143
//---------------------------------------------------------------------------
145
// Reset the trigger time.
147
void XAutoLock::resetTrigger()
149
// Time of the last user activity (used only when the internal XScreensaver
150
// idle counter is not available).
151
mLastReset = mElapsed;
152
// Time when screensaver should be activated.
153
mTrigger = mElapsed + mTimeout;
154
#ifdef HAVE_XSCREENSAVER
157
// Do not reset the internal X screensaver here (no XForceScreenSaver())
160
//---------------------------------------------------------------------------
162
// Move the trigger time in order to postpone (repeat) emitting of timeout().
164
void XAutoLock::postpone()
166
mTrigger = mElapsed + 60; // delay by 60sec
169
//---------------------------------------------------------------------------
171
// Set the remaining time to 't', if it's shorter than already set.
173
void XAutoLock::setTrigger( int t )
175
time_t newT = mElapsed + qMax(t, 0);
180
//---------------------------------------------------------------------------
182
// Process new windows and check the mouse.
184
void XAutoLock::timerEvent(QTimerEvent *ev)
186
if (ev->timerId() != mTimerId)
190
mElapsed += CHECK_INTERVAL / 1000;
192
#ifdef HAVE_XSCREENSAVER
195
{ // only the diy way needs special X handler
196
XSync( QX11Info::display(), False );
197
int (*oldHandler)(Display *, XErrorEvent *) =
198
XSetErrorHandler(catchFalseAlarms);
200
xautolock_processQueue();
202
XSetErrorHandler(oldHandler);
205
#ifdef HAVE_XSCREENSAVER
208
Display *d = QX11Info::display();
209
// Check user idle time. If it is smaller than before, it is either
210
// clock jump or user activity, so reset the trigger time. Checking whether
211
// there is user inactivity timeout is done below using mTrigger and mElapsed.
212
XScreenSaverQueryInfo(d, DefaultRootWindow(d), mMitInfo);
213
if (mLastIdle < mMitInfo->idle)
214
mLastIdle = mMitInfo->idle;
218
#endif /* HAVE_XSCREENSAVER */
220
// This needs to be after the above check, so it overrides it.
221
xautolock_queryPointer( QX11Info::display());
223
bool activate = false;
225
// This is the test whether to activate screensaver. If we have reached the time
226
// and for the whole timeout period there was no activity (which would change mTrigger
228
if (mElapsed >= mTrigger)
234
CARD16 timeout1, timeout2, timeout3;
235
DPMSInfo( QX11Info::display(), &state, &on );
236
DPMSGetTimeouts( QX11Info::display(), &timeout1, &timeout2, &timeout3 );
238
// kDebug() << "DPMSInfo " << state << on;
239
// If DPMS is active, it makes XScreenSaverQueryInfo() report idle time
240
// that is always smaller than DPMS timeout (X bug I guess). So if DPMS
241
// saving is active, simply always activate our saving too, otherwise
242
// this could prevent locking from working.
243
// X.Org 7.4: With this version activating DPMS resets the screensaver idle timer,
244
// so keep this. It probably makes sense to always do this anyway.
245
if(state == DPMSModeStandby || state == DPMSModeSuspend || state == DPMSModeOff)
247
// If we are DPMS-dependent and either DPMS is turned off completely or all
248
// three DPMS modes are turned off, don't activate (apps use this to turn off
250
if(mDPMS && (!on || (timeout1 == 0 && timeout2 == 0 && timeout3 == 0 ))) {
256
// Do not check whether internal X screensaver is enabled or disabled, since we
257
// have disabled it ourselves. Some apps might try to disable it too to prevent
258
// screensavers, but then our logic breaks[*]. Those apps need to disable DPMS anyway,
259
// or they will still have problems, so the DPMS code above should be enough.
260
// Besides, I doubt other screensaver implementations check this either.
261
// [*] We can't run with X screensaver enabled, since then sooner or later
262
// the internal screensaver will activate instead of our screensaver and we cannot
263
// prevent its activation by resetting the idle counter since that would also
264
// reset DPMS saving.
266
if(mActive && activate)
270
bool XAutoLock::x11Event( XEvent* ev )
272
xautolock_processEvent( ev );
273
// don't futher process key events that were received only because XAutoLock wants them
274
if( ev->type == KeyPress && !ev->xkey.send_event
275
#ifdef HAVE_XSCREENSAVER
278
&& !QWidget::find( ev->xkey.window ))
283
bool XAutoLock::ignoreWindow( WId w )
285
if( w != QX11Info::appRootWindow() && QWidget::find( w ))
290
time_t XAutoLock::idleTime()
292
#ifdef HAVE_XSCREENSAVER
294
return mMitInfo->idle / 1000;
296
return mElapsed - mLastReset;
300
void xautolock_resetTriggers()
302
self->resetTrigger();
306
void xautolock_setTrigger( int t )
308
self->setTrigger( t );
312
int xautolock_ignoreWindow( Window w )
314
return self->ignoreWindow( w );
317
#include "xautolock.moc"