Monday, August 31, 2009

Idle Detector / C++ / Linux

It's been very difficult to find information, or a sample code, of an Idle detection implementation in C for Linux, I tried a lot of combinations but none of them lead me to a final implementation, finally I managed to solve this problem.

The main problem is: "How to know when the user has been idle (or away) for some minutes and I want to do something in that case?"

The first attempt that came to my mind was to do a "system hook", but after several tries I finally realized that you cannot apply a "windows like" solution in linux... Linux is... just different. So here's how I did the trick:

1. You need to use the "libxss-dev" library, you can install it using:

sudo apt-get install libxss-dev

2. Create the following class:

#include "idledetector.h"

#include
#include
#include
#include

IdleDetector::IdleDetector(int idleMaxSecs)
{
m_idleMaxSecs = idleMaxSecs;
}

void IdleDetector::start() {
timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
timer->start(1000);
}

void IdleDetector::stop() {
timer->stop();
}

void IdleDetector::timeout() {
bool _idleDetectionPossible;
XScreenSaverInfo *_mit_info;

int event_base, error_base;
if(XScreenSaverQueryExtension(QX11Info::display(), &event_base, &error_base))
_idleDetectionPossible = true;
else
_idleDetectionPossible = false;
_mit_info = XScreenSaverAllocInfo();

XScreenSaverQueryInfo(QX11Info::display(), QX11Info::appRootWindow(), _mit_info);

long idlesecs = (_mit_info->idle/1000);

if (idlesecs > m_idleMaxSecs) {
timer->stop();
idleTimeOut();
}
}


The "idledetector.h" will be as follows:


#ifndef IDLEDETECTOR_H
#define IDLEDETECTOR_H

#include
#include

class IdleDetector : public QObject
{
Q_OBJECT

public:
IdleDetector(int idleMax);
void start();
void stop();

signals:
void idleTimeOut();

private:
int m_idleMaxSecs;
QTimer* timer;

private slots:
void timeout();

};

#endif // IDLEDETECTOR_H


I'm using Qt to expose the signals and use a signal/slot architecture, but I'm sure the reader is smart enough to convert this class to whatever he wants.

The main idea in here is that every x seconds (1000 ms to be exact) the timeout will check how much time the user has been idle (away) and if it matches the m_maxsecs a signal will be send to any subscriber.

Use this solution as you want, but will be great if you put a link to this site in order to improve the google counter xD

If you need help on how to use it, let me know and I will post the sample code.