~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to krunner/screensaver/xautolock.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//----------------------------------------------------------------------------
 
2
//
 
3
// This file is part of the KDE project
 
4
//
 
5
// Copyright 1999 Martin R. Jones <mjones@kde.org>
 
6
// Copyright 2003 Lubos Lunak <l.lunak@kde.org>
 
7
//
 
8
// KDE screensaver engine
 
9
//
 
10
 
 
11
#include <config-workspace.h>
 
12
 
 
13
#include "xautolock.h"
 
14
#include "xautolock_c.h"
 
15
 
 
16
#include <kapplication.h>
 
17
#include <kdebug.h>
 
18
 
 
19
#include <QTimerEvent>
 
20
#include <QX11Info>
 
21
 
 
22
#include <X11/Xlib.h>
 
23
#include <X11/Xutil.h>
 
24
 
 
25
#ifdef HAVE_DPMS
 
26
extern "C" {
 
27
#include <X11/Xmd.h>
 
28
#ifndef Bool
 
29
#define Bool BOOL
 
30
#endif
 
31
#include <X11/extensions/dpms.h>
 
32
 
 
33
#ifndef HAVE_DPMSINFO_PROTO
 
34
Status DPMSInfo ( Display *, CARD16 *, BOOL * );
 
35
#endif
 
36
}
 
37
#endif
 
38
 
 
39
#include <ctime>
 
40
 
 
41
xautolock_corner_t xautolock_corners[ 4 ];
 
42
 
 
43
static XAutoLock* self = NULL;
 
44
 
 
45
extern "C" {
 
46
static int catchFalseAlarms(Display *, XErrorEvent *)
 
47
{
 
48
    return 0;
 
49
}
 
50
}
 
51
 
 
52
//===========================================================================
 
53
//
 
54
// Detect user inactivity.
 
55
// Named XAutoLock after the program that it is based on.
 
56
//
 
57
XAutoLock::XAutoLock()
 
58
{
 
59
    self = this;
 
60
#ifdef HAVE_XSCREENSAVER
 
61
    mMitInfo = 0;
 
62
    int dummy;
 
63
    if (XScreenSaverQueryExtension( QX11Info::display(), &dummy, &dummy ))
 
64
    {
 
65
        mMitInfo = XScreenSaverAllocInfo();
 
66
    }
 
67
    else
 
68
#endif
 
69
    {
 
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);
 
77
    }
 
78
 
 
79
    mTimeout = DEFAULT_TIMEOUT;
 
80
    mDPMS = true;
 
81
    resetTrigger();
 
82
 
 
83
    mActive = false;
 
84
 
 
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.
 
89
    mElapsed = 0;
 
90
}
 
91
 
 
92
//---------------------------------------------------------------------------
 
93
//
 
94
// Destructor.
 
95
//
 
96
XAutoLock::~XAutoLock()
 
97
{
 
98
    stop();
 
99
    self = NULL;
 
100
}
 
101
 
 
102
//---------------------------------------------------------------------------
 
103
//
 
104
// The time in seconds of continuous inactivity.
 
105
//
 
106
void XAutoLock::setTimeout(int t)
 
107
{
 
108
    mTimeout = t;
 
109
}
 
110
 
 
111
void XAutoLock::setDPMS(bool s)
 
112
{
 
113
#ifdef HAVE_DPMS
 
114
    BOOL on;
 
115
    CARD16 state;
 
116
    DPMSInfo( QX11Info::display(), &state, &on );
 
117
    if (!on)
 
118
        s = false;
 
119
#endif
 
120
    mDPMS = s;
 
121
}
 
122
 
 
123
//---------------------------------------------------------------------------
 
124
//
 
125
// Start watching Activity
 
126
//
 
127
void XAutoLock::start()
 
128
{
 
129
    mActive = true;
 
130
    resetTrigger();
 
131
}
 
132
 
 
133
//---------------------------------------------------------------------------
 
134
//
 
135
// Stop watching Activity
 
136
//
 
137
void XAutoLock::stop()
 
138
{
 
139
    mActive = false;
 
140
    resetTrigger();
 
141
}
 
142
 
 
143
//---------------------------------------------------------------------------
 
144
//
 
145
// Reset the trigger time.
 
146
//
 
147
void XAutoLock::resetTrigger()
 
148
{
 
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
 
155
    mLastIdle = 0;
 
156
#endif
 
157
    // Do not reset the internal X screensaver here (no XForceScreenSaver())
 
158
}
 
159
 
 
160
//---------------------------------------------------------------------------
 
161
//
 
162
// Move the trigger time in order to postpone (repeat) emitting of timeout().
 
163
//
 
164
void XAutoLock::postpone()
 
165
{
 
166
    mTrigger = mElapsed + 60; // delay by 60sec
 
167
}
 
168
 
 
169
//---------------------------------------------------------------------------
 
170
//
 
171
// Set the remaining time to 't', if it's shorter than already set.
 
172
//
 
173
void XAutoLock::setTrigger( int t )
 
174
{
 
175
    time_t newT = mElapsed + qMax(t, 0);
 
176
    if (mTrigger > newT)
 
177
        mTrigger = newT;
 
178
}
 
179
 
 
180
//---------------------------------------------------------------------------
 
181
//
 
182
// Process new windows and check the mouse.
 
183
//
 
184
void XAutoLock::timerEvent(QTimerEvent *ev)
 
185
{
 
186
    if (ev->timerId() != mTimerId)
 
187
    {
 
188
        return;
 
189
    }
 
190
    mElapsed += CHECK_INTERVAL / 1000;
 
191
 
 
192
#ifdef HAVE_XSCREENSAVER
 
193
    if (!mMitInfo)
 
194
#endif
 
195
    { // only the diy way needs special X handler
 
196
        XSync( QX11Info::display(), False );
 
197
        int (*oldHandler)(Display *, XErrorEvent *) =
 
198
                XSetErrorHandler(catchFalseAlarms);
 
199
 
 
200
        xautolock_processQueue();
 
201
 
 
202
        XSetErrorHandler(oldHandler);
 
203
    }
 
204
 
 
205
#ifdef HAVE_XSCREENSAVER
 
206
    if (mMitInfo)
 
207
    {
 
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;
 
215
        else
 
216
            resetTrigger();
 
217
    }
 
218
#endif /* HAVE_XSCREENSAVER */
 
219
 
 
220
    // This needs to be after the above check, so it overrides it.
 
221
    xautolock_queryPointer( QX11Info::display());
 
222
 
 
223
    bool activate = false;
 
224
 
 
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
 
227
    // again), activate.
 
228
    if (mElapsed >= mTrigger)
 
229
        activate = true;
 
230
 
 
231
#ifdef HAVE_DPMS
 
232
    BOOL on;
 
233
    CARD16 state;
 
234
    CARD16 timeout1, timeout2, timeout3;
 
235
    DPMSInfo( QX11Info::display(), &state, &on );
 
236
    DPMSGetTimeouts( QX11Info::display(), &timeout1, &timeout2, &timeout3 );
 
237
 
 
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)
 
246
        activate = true;
 
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
 
249
    // screensavers).
 
250
    if(mDPMS && (!on || (timeout1 == 0 && timeout2 == 0 && timeout3 == 0 ))) {
 
251
        activate = false;
 
252
        resetTrigger();
 
253
    }
 
254
#endif
 
255
 
 
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.
 
265
 
 
266
    if(mActive && activate)
 
267
        emit timeout();
 
268
}
 
269
 
 
270
bool XAutoLock::x11Event( XEvent* ev )
 
271
{
 
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
 
276
        && !mMitInfo
 
277
#endif
 
278
        && !QWidget::find( ev->xkey.window ))
 
279
        return true;
 
280
    return false;
 
281
}
 
282
 
 
283
bool XAutoLock::ignoreWindow( WId w )
 
284
{
 
285
    if( w != QX11Info::appRootWindow() && QWidget::find( w ))
 
286
        return true;
 
287
    return false;
 
288
}
 
289
 
 
290
time_t XAutoLock::idleTime()
 
291
{
 
292
#ifdef HAVE_XSCREENSAVER
 
293
    if (mMitInfo)
 
294
        return mMitInfo->idle / 1000;
 
295
#endif
 
296
    return mElapsed - mLastReset;
 
297
}
 
298
 
 
299
extern "C"
 
300
void xautolock_resetTriggers()
 
301
{
 
302
  self->resetTrigger();
 
303
}
 
304
 
 
305
extern "C"
 
306
void xautolock_setTrigger( int t )
 
307
{
 
308
  self->setTrigger( t );
 
309
}
 
310
 
 
311
extern "C"
 
312
int xautolock_ignoreWindow( Window w )
 
313
{
 
314
   return self->ignoreWindow( w );
 
315
}
 
316
 
 
317
#include "xautolock.moc"