The Patient Management System we are writing required a timeout for logins after a certain period had elapsed. So we needed to detect application idle. A couple of examples exist on the the web, but seemed incomplete and not thread safe. I also wanted a singleton class model so that I could have notifications of idle in any of my QObjects. So here is my implementation. Comments and improvements will be appreciated.
Header File:
#ifndef IDLETIMER_H #define IDLETIMER_H #include <qobject> #include <qmutex> #include <qevent> #include <qtimer> class IdleTimer : public QObject { Q_OBJECT public: // Singleton class stuff static IdleTimer* instance(QObject *parent=0, int seconds=0) { static QMutex mutex; if (!m_Instance) { mutex.lock(); m_Instance = new IdleTimer(parent, seconds); mutex.unlock(); } return m_Instance; } static void drop() { qDebug("IdleTimer dropped ..."); static QMutex mutex; mutex.lock(); m_timer->stop(); if(m_timer) delete m_timer; if (m_Instance) delete m_Instance; m_Instance = 0; mutex.unlock(); } void start(int seconds = 0); void stop(); private: explicit IdleTimer(QObject *parent, int seconds); explicit IdleTimer() {} ~IdleTimer() {} IdleTimer(const IdleTimer &); // hide copy constructor IdleTimer& operator=(const IdleTimer &); // hide assign op static IdleTimer *m_Instance; static QTimer *m_timer; static QMutex m_timeoutMutex; static int m_timeout; signals: void idle(); private slots: void idleTimeout(); protected: bool eventFilter(QObject *obj, QEvent *ev); }; #endif // IDLETIMER_H
And the implementation
/*! * Small class for detecting idle in the applcation */ #include "IdleTimer.h" // Static initialisers IdleTimer *IdleTimer::m_Instance = 0; QTimer *IdleTimer::m_timer = new QTimer(); int IdleTimer::m_timeout = 0; QMutex IdleTimer::m_timeoutMutex; /*! * Class constructor */ IdleTimer::IdleTimer(QObject *parent, int seconds) : QObject(parent) { m_timeoutMutex.lock(); if (seconds) m_timeout = seconds; Q_ASSERT(parent); Q_ASSERT_X(m_timeout, "IdleTimer Constructor", "The timeout must be specified in the first call to instance."); parent->installEventFilter(this); m_timer->singleShot(m_timeout*1000, this, SLOT(idleTimeout())); m_timeoutMutex.unlock(); } /*! * Either reset the timeout to a different value to restart the timer */ void IdleTimer::start(int seconds/*=0*/) { m_timeoutMutex.lock(); if(seconds) m_timeout = seconds; Q_ASSERT_X(m_timeout, "IdleTimer reset", "A timeout must be specified either in this call or in the first call to instance."); m_timer->start(m_timeout*1000); m_timeoutMutex.unlock(); } void IdleTimer::stop() { m_timeoutMutex.lock(); m_timer->stop(); m_timeoutMutex.unlock(); } /*! * The vent filter */ bool IdleTimer::eventFilter(QObject *obj, QEvent *ev) { if(ev->type() == QEvent::KeyPress || ev->type() == QEvent::MouseMove) // now reset your timer, for example IdleTimer::m_timer->start(); // Must return to allow further processing return QObject::eventFilter(obj, ev); } /*slot*/ void IdleTimer::idleTimeout() { qDebug("Application has been idle, emitting idle signal ..."); emit idle(); }
4 comments:
Looks very useful, and I would like to adopt this class for use in my software library. I will give you full credit, of course.
The source code listing for the header file contains four #include statements that appear to be incomplete. Is this a glitch or an omission?
Sorry, classic HTML problem with less than / great than sign. Corrected now ...
This doesn't work. Even when I move the mouse, it still prints out the alert after 20 seconds. This is how I am using it:
IdleTimer* t = IdleTimer::instance(this,20);
connect(t,SIGNAL(idle()),this,SLOT(print()));
Hi @AttitudeMonger. I am not sure from your code what this points to but we use QApplication so that application wide events are captured by the idle timer. By allowing a parent to be passed though idle on any particular window for example can be detected.
I hope this helps
Post a Comment