Results 1 to 16 of 16

Thread: Timer to find out if app id idle not working as expected

  1. #1
    Join Date
    May 2014
    Posts
    136
    Thanks
    72
    Qt products
    Qt3 Qt4 PyQt3 PyQt4
    Platforms
    MacOS X Windows

    Default Timer to find out if app id idle not working as expected

    I need to find out when my app is idle for say 20 seconds, and then do something. The logic I thought of is this: run a timer constantly with timeout set to 20 seconds, on any user action, cancel the timer and start it again. Then I found this code here do the same thing. This is the code:

    Qt Code:
    1. #include "IdleTimer.hpp"
    2.  
    3. // Static initialisers
    4. IdleTimer *IdleTimer::m_Instance = 0;
    5. QTimer *IdleTimer::m_timer = new QTimer();
    6. int IdleTimer::m_timeout = 0;
    7. QMutex IdleTimer::m_timeoutMutex;
    8.  
    9. /*!
    10. * Class constructor
    11. */
    12. IdleTimer::IdleTimer(QObject *parent, int seconds) :
    13. QObject(parent)
    14. {
    15. m_timeoutMutex.lock();
    16.  
    17. if (seconds)
    18. m_timeout = seconds;
    19.  
    20. Q_ASSERT(parent);
    21. Q_ASSERT_X(m_timeout, "IdleTimer Constructor", "The timeout must be specified in the first call to instance.");
    22.  
    23. parent->installEventFilter(this);
    24. m_timer->singleShot(m_timeout*1000, this, SLOT(idleTimeout()));
    25.  
    26. m_timeoutMutex.unlock();
    27. }
    28.  
    29. /*!
    30. * Either reset the timeout to a different value to restart the timer
    31. */
    32. void IdleTimer::start(int seconds/*=0*/) {
    33. m_timeoutMutex.lock();
    34.  
    35. if(seconds)
    36. m_timeout = seconds;
    37.  
    38. Q_ASSERT_X(m_timeout, "IdleTimer reset", "A timeout must be specified either in this call or in the first call to instance.");
    39.  
    40. m_timer->start(m_timeout*1000);
    41.  
    42. m_timeoutMutex.unlock();
    43. }
    44.  
    45. void IdleTimer::stop() {
    46. m_timeoutMutex.lock();
    47. m_timer->stop();
    48. m_timeoutMutex.unlock();
    49. }
    50.  
    51. /*!
    52. * The vent filter
    53. */
    54. bool IdleTimer::eventFilter(QObject *obj, QEvent *ev)
    55. {
    56. qDebug() << "Ah, caught!" << endl;
    57. if(ev->type() == QEvent::KeyPress ||
    58. ev->type() == QEvent::MouseMove)
    59. // now reset your timer, for example
    60. IdleTimer::m_timer->start();
    61.  
    62. // Must return to allow further processing
    63. return QObject::eventFilter(obj, ev);
    64. }
    65.  
    66. // Must return to allow further processing
    67. return QObject::eventFilter(obj, ev);
    68. }
    69.  
    70. /*slot*/
    71. void IdleTimer::idleTimeout() {
    72. qDebug("Application has been idle, emitting idle signal ...");
    73. emit idle();
    74. }
    To copy to clipboard, switch view to plain text mode 

    Header:

    Qt Code:
    1. #ifndef IDLETIMER_H
    2. #define IDLETIMER_H
    3.  
    4. #include <qobject>
    5. #include <qmutex>
    6. #include <qevent>
    7. #include <qtimer>
    8.  
    9. class IdleTimer : public QObject
    10. {
    11. Q_OBJECT
    12. public:
    13. // Singleton class stuff
    14. static IdleTimer* instance(QObject *parent=0, int seconds=0) {
    15. static QMutex mutex;
    16. if (!m_Instance) {
    17. mutex.lock();
    18. m_Instance = new IdleTimer(parent, seconds);
    19. mutex.unlock();
    20. }
    21. return m_Instance;
    22. }
    23.  
    24. static void drop() {
    25. qDebug("IdleTimer dropped ...");
    26. static QMutex mutex;
    27. mutex.lock();
    28.  
    29. m_timer->stop();
    30. if(m_timer) delete m_timer;
    31.  
    32. if (m_Instance)
    33. delete m_Instance;
    34. m_Instance = 0;
    35. mutex.unlock();
    36. }
    37.  
    38. void start(int seconds = 0);
    39. void stop();
    40.  
    41. private:
    42. explicit IdleTimer(QObject *parent, int seconds);
    43. explicit IdleTimer() {}
    44. ~IdleTimer() {}
    45.  
    46. IdleTimer(const IdleTimer &); // hide copy constructor
    47. IdleTimer& operator=(const IdleTimer &); // hide assign op
    48.  
    49. static IdleTimer *m_Instance;
    50. static QTimer *m_timer;
    51.  
    52. static QMutex m_timeoutMutex;
    53. static int m_timeout;
    54.  
    55. signals:
    56. void idle();
    57.  
    58. private slots:
    59. void idleTimeout();
    60.  
    61. protected:
    62. bool eventFilter(QObject *obj, QEvent *ev);
    63. };
    64.  
    65. #endif // IDLETIMER_H
    To copy to clipboard, switch view to plain text mode 

    This is how I am using this (MyApplication extends QApplication)

    Qt Code:
    1. MyApplication:: MyApplication()
    2. {
    3. IdleTimer* timer = IdleTimer::instance(this,20);
    4. }
    To copy to clipboard, switch view to plain text mode 

    The problem is on app launch, whatever happens, whether I am active or idle, the Application has been idle, emitting idle signal ... gets printed after the first 20 seconds. Moving the mouse, clicking somewhere does not cancel the timer and restart it. But the qDebug within event-filter works correctly on moving/clicking, which means the event filter is working fine, code is coming upto that point, but somehow I am not able to restart the timer as expected.

    How do I fix this?
    Last edited by Cupidvogel; 29th December 2015 at 16:25.

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Timer to find out if app id idle not working as expected

    You are not passing a parent to getInstance() so you are not installing an event filter.

    This all looks really complicated, why all the mutexes?

    Just create the IdleTimer object in main() and install it as an event filter on the Qt application object.

    Btw, there is also http://inqlude.org/libraries/kidletime.html if you want a tested solution.

    Cheers,
    _

  3. The following user says thank you to anda_skoa for this useful post:

    Cupidvogel (29th December 2015)

  4. #3
    Join Date
    May 2014
    Posts
    136
    Thanks
    72
    Qt products
    Qt3 Qt4 PyQt3 PyQt4
    Platforms
    MacOS X Windows

    Default Re: Timer to find out if app id idle not working as expected

    Ah. I am sorry. That was posted by mistake. Yes I am passing this and 20 as parameters (otherwise the code won't compile!). And it ensures that the debug statement is printed out 20 seconds after the app launches no matter what!

    Yes, the mutex makes it complicated. I removed them and kept it minimal to see if that is causing any problem. Same result.

  5. #4
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,318
    Thanks
    315
    Thanked 870 Times in 857 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Timer to find out if app id idle not working as expected

    The IdleTimer constructor requires a non-NULL QObject parent, on which it installs the event filter to watch for mouse move and key press events. You don't provide one.

    MyApplication:: MyApplication()
    {
    IdleTimer* timer = IdleTimer::getInstance();
    }
    And this isn't your real code. IdleTimer has no getInstance() method. Even if you meant to write instance() instead, this code would crash and burn because the IdleTimer constructor requires a non-NULL parent pointer in order for this code to execute:

    parent->installEventFilter(this);
    I see I type more slowly than you and anda_skoa...

    This IdleTimer class is a little messed up anyway - as a singleton, you can have only one of them. If you call instance() a second time, with a different parent, nothing actually happens; because the singleton already exists, it doesn't create a new instance, which means an event filter is never installed on the new parent. The only way it really works is if you install it on the application object where it can filter all events for everything in the app.
    Last edited by d_stranz; 29th December 2015 at 16:27.

  6. The following user says thank you to d_stranz for this useful post:

    Cupidvogel (29th December 2015)

  7. #5
    Join Date
    May 2014
    Posts
    136
    Thanks
    72
    Qt products
    Qt3 Qt4 PyQt3 PyQt4
    Platforms
    MacOS X Windows

    Default Re: Timer to find out if app id idle not working as expected

    Yep. That I posted by mistake (I was experimenting with different constructors and copy pasted disjoint versions of the files). I mentioned it above as well..

  8. #6
    Join Date
    May 2014
    Posts
    136
    Thanks
    72
    Qt products
    Qt3 Qt4 PyQt3 PyQt4
    Platforms
    MacOS X Windows

    Default Re: Timer to find out if app id idle not working as expected

    I tried this in main.cpp of my app:

    Qt Code:
    1. Application app(argc, argv);
    2.  
    3. IdleTimer *timer = IdleTimer::instance(&app,5);
    4. app.installEventFilter(timer);
    To copy to clipboard, switch view to plain text mode 

    Still same result. The debug message always comes 20 seconds after the app launches, no mater what I do, like clicking or moving the mouse.

  9. #7
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Timer to find out if app id idle not working as expected

    Does the eventFilter method get called?

    Cheers,
    _

  10. #8
    Join Date
    May 2014
    Posts
    136
    Thanks
    72
    Qt products
    Qt3 Qt4 PyQt3 PyQt4
    Platforms
    MacOS X Windows

    Default Re: Timer to find out if app id idle not working as expected

    Yes, that's the problem, it does! If I put a simple qDebug in the event filter if conditional, it prints out all the time when I move my mouse or click anything! I cannot understand how it just fails to clear the timer!

  11. #9
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Timer to find out if app id idle not working as expected

    Weird.
    Have you tried stop/start?

    Cheers,
    _

  12. #10
    Join Date
    May 2014
    Posts
    136
    Thanks
    72
    Qt products
    Qt3 Qt4 PyQt3 PyQt4
    Platforms
    MacOS X Windows

    Default Re: Timer to find out if app id idle not working as expected

    Wait, I will try to post the exact code I am currently using. Gimme 5 minutes.


    Added after 11 minutes:


    IdleTimer.cpp:

    Qt Code:
    1. #include "IdleTimer.hpp"
    2.  
    3. // Static initialisers
    4. IdleTimer *IdleTimer::m_Instance = 0;
    5. QTimer *IdleTimer::m_timer = new QTimer();
    6. int IdleTimer::m_timeout = 0;
    7.  
    8. /*!
    9. * Class constructor
    10. */
    11. IdleTimer::IdleTimer(QObject *parent, int seconds) :
    12. QObject(parent)
    13. {
    14. if (seconds)
    15. m_timeout = seconds;
    16.  
    17. Q_ASSERT(parent);
    18. Q_ASSERT_X(m_timeout, "IdleTimer Constructor", "The timeout must be specified in the first call to instance.");
    19.  
    20. parent->installEventFilter(this);
    21. m_timer->singleShot(m_timeout*1000, this, SLOT(idleTimeout()));
    22.  
    23. }
    24.  
    25. /*!
    26. * Either reset the timeout to a different value to restart the timer
    27. */
    28. void IdleTimer::start(int seconds/*=0*/) {
    29.  
    30. if(seconds)
    31. m_timeout = seconds;
    32.  
    33. Q_ASSERT_X(m_timeout, "IdleTimer reset", "A timeout must be specified either in this call or in the first call to instance.");
    34.  
    35. m_timer->start(m_timeout*1000);
    36.  
    37. }
    38.  
    39. void IdleTimer::stop() {
    40. m_timer->stop();
    41. }
    42.  
    43. /*!
    44. * The vent filter
    45. */
    46. bool IdleTimer::eventFilter(QObject *obj, QEvent *ev)
    47. {
    48. if(ev->type() == QEvent::KeyPress ||
    49. ev->type() == QEvent::MouseMove)
    50. {
    51. IdleTimer::m_timer->stop();
    52. return QObject::eventFilter(obj, ev);
    53. }
    54.  
    55. // Must return to allow further processing
    56. return QObject::eventFilter(obj, ev);
    57. }
    58.  
    59. /*slot*/
    60. void IdleTimer::idleTimeout() {
    61. qDebug("Application has been idle, emitting idle signal ...");
    62. emit idle();
    63. }
    To copy to clipboard, switch view to plain text mode 

    IdleTimer.hpp:

    Qt Code:
    1. #ifndef IDLETIMER_H
    2. #define IDLETIMER_H
    3.  
    4. #include <qobject>
    5. #include <qevent>
    6. #include <qtimer>
    7.  
    8. class IdleTimer : public QObject
    9. {
    10. Q_OBJECT
    11. public:
    12. // Singleton class stuff
    13. static IdleTimer* instance(QObject *parent=0, int seconds=0) {
    14. if (!m_Instance) {
    15. m_Instance = new IdleTimer(parent, seconds);
    16. }
    17. return m_Instance;
    18. }
    19.  
    20. static void drop() {
    21. qDebug("IdleTimer dropped ...");
    22.  
    23. m_timer->stop();
    24. if(m_timer) delete m_timer;
    25.  
    26. if (m_Instance)
    27. delete m_Instance;
    28. m_Instance = 0;
    29. }
    30.  
    31. void start(int seconds = 0);
    32. void stop();
    33.  
    34. private:
    35. explicit IdleTimer(QObject *parent, int seconds);
    36. explicit IdleTimer() {}
    37. ~IdleTimer() {}
    38.  
    39. IdleTimer(const IdleTimer &); // hide copy constructor
    40. IdleTimer& operator=(const IdleTimer &); // hide assign op
    41.  
    42. static IdleTimer *m_Instance;
    43. static QTimer *m_timer;
    44.  
    45. static int m_timeout;
    46.  
    47. signals:
    48. void idle();
    49.  
    50. private slots:
    51. void idleTimeout();
    52.  
    53. protected:
    54. bool eventFilter(QObject *obj, QEvent *ev);
    55. };
    56.  
    57. #endif // IDLETIMER_H
    To copy to clipboard, switch view to plain text mode 

    main.cpp:

    Qt Code:
    1. int main(int argc, char *argv[])
    2. {
    3. Application app(argc, argv);
    4.  
    5. IdleTimer *timer = IdleTimer::instance(&app,5);
    6. app.installEventFilter(timer);
    7. //other stuff
    8. }
    To copy to clipboard, switch view to plain text mode 

    I think the explicit installEventFilter call in main is not required, since it does it anyway in the IdleTimer constructor. But either way, it doesn't work. Right 5 seconds after app launches, it prints out the message Application has been idle, emitting idle signal ..., even though I am constantly moving the mouse, clicking around..
    Last edited by Cupidvogel; 30th December 2015 at 17:46.

  13. #11
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,318
    Thanks
    315
    Thanked 870 Times in 857 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Timer to find out if app id idle not working as expected

    Just a hunch - when you create the timer, your event loop isn't running yet. What if you create a one-shot zero-timeout timer, and in its timeout slot create your idle timer and start it running? By doing that, you ensure that the event loop is already running when your idle timer gets instantiated.

    I agree that your manual call to installEventFilter() in main() is superfluous.

  14. The following user says thank you to d_stranz for this useful post:

    Cupidvogel (30th December 2015)

  15. #12
    Join Date
    May 2014
    Posts
    136
    Thanks
    72
    Qt products
    Qt3 Qt4 PyQt3 PyQt4
    Platforms
    MacOS X Windows

    Default Re: Timer to find out if app id idle not working as expected

    That's interesting. But doesn't work. I tried this:

    Qt Code:
    1. #include "IdleTimer.hpp"
    2.  
    3. // Static initialisers
    4. IdleTimer *IdleTimer::m_Instance = 0;
    5. QTimer *IdleTimer::m_timer = new QTimer();
    6. QTimer *IdleTimer::test_timer = new QTimer();
    7. int IdleTimer::m_timeout = 0;
    8.  
    9. /*!
    10. * Class constructor
    11. */
    12. IdleTimer::IdleTimer(QObject *parent, int seconds) :
    13. QObject(parent)
    14. {
    15. fParent = parent;
    16. if (seconds)
    17. m_timeout = seconds;
    18.  
    19. Q_ASSERT(parent);
    20. Q_ASSERT_X(m_timeout, "IdleTimer Constructor", "The timeout must be specified in the first call to instance.");
    21.  
    22.  
    23. test_timer->singleShot(10*1000, this, SLOT(createTimer()));
    24.  
    25.  
    26. }
    27.  
    28. void IdleTimer::createTimer()
    29. {
    30. qDebug() << "Creating my timer" << endl;
    31. fParent->installEventFilter(this);
    32. m_timer->singleShot(m_timeout*1000, this, SLOT(idleTimeout()));
    33. }
    34.  
    35. /*!
    36. * Either reset the timeout to a different value to restart the timer
    37. */
    38. void IdleTimer::start(int seconds/*=0*/) {
    39.  
    40. if(seconds)
    41. m_timeout = seconds;
    42.  
    43. Q_ASSERT_X(m_timeout, "IdleTimer reset", "A timeout must be specified either in this call or in the first call to instance.");
    44.  
    45. m_timer->start(m_timeout*1000);
    46.  
    47. }
    48.  
    49. void IdleTimer::stop() {
    50. m_timer->stop();
    51. }
    52.  
    53. /*!
    54. * The vent filter
    55. */
    56. bool IdleTimer::eventFilter(QObject *obj, QEvent *ev)
    57. {
    58. if(ev->type() == QEvent::KeyPress ||
    59. ev->type() == QEvent::MouseMove)
    60. {
    61. IdleTimer::m_timer->stop();
    62. return QObject::eventFilter(obj, ev);
    63. }
    64.  
    65. // Must return to allow further processing
    66. return QObject::eventFilter(obj, ev);
    67. }
    68.  
    69. /*slot*/
    70. void IdleTimer::idleTimeout() {
    71. qDebug("Application has been idle, emitting idle signal ...");
    72. emit idle();
    73. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. #ifndef IDLETIMER_H
    2. #define IDLETIMER_H
    3.  
    4. #include <qobject>
    5. #include <qevent>
    6. #include <qtimer>
    7.  
    8. class IdleTimer : public QObject
    9. {
    10. Q_OBJECT
    11. public:
    12. // Singleton class stuff
    13. static IdleTimer* instance(QObject *parent=0, int seconds=0) {
    14. if (!m_Instance) {
    15. m_Instance = new IdleTimer(parent, seconds);
    16. }
    17. return m_Instance;
    18. }
    19.  
    20. static void drop() {
    21. qDebug("IdleTimer dropped ...");
    22.  
    23. m_timer->stop();
    24. if(m_timer) delete m_timer;
    25.  
    26. if (m_Instance)
    27. delete m_Instance;
    28. m_Instance = 0;
    29. }
    30.  
    31. void start(int seconds = 0);
    32. void stop();
    33.  
    34. private:
    35. explicit IdleTimer(QObject *parent, int seconds);
    36. explicit IdleTimer() {}
    37. ~IdleTimer() {}
    38.  
    39. IdleTimer(const IdleTimer &); // hide copy constructor
    40. IdleTimer& operator=(const IdleTimer &); // hide assign op
    41.  
    42. static IdleTimer *m_Instance;
    43. static QTimer *m_timer;
    44. static QTimer *test_timer;
    45.  
    46. static int m_timeout;
    47. QObject* fParent;
    48.  
    49. signals:
    50. void idle();
    51.  
    52. private slots:
    53. void idleTimeout();
    54. void createTimer();
    55.  
    56. protected:
    57. bool eventFilter(QObject *obj, QEvent *ev);
    58. };
    59.  
    60. #endif // IDLETIMER_H
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. int main(int argc, char *argv[])
    2. {
    3. Application app(argc, argv);
    4.  
    5. IdleTimer *timer = IdleTimer::instance(&app,5);
    6. }
    To copy to clipboard, switch view to plain text mode 

    It prints out the creating timer statement after 10 seconds, but then the timeout message 5 seconds after that, even with clicks and mousemove..

  16. #13
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,318
    Thanks
    315
    Thanked 870 Times in 857 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Timer to find out if app id idle not working as expected

    Umm, that wasn't exactly what I was thinking. More like this:

    Qt Code:
    1. int main( int argc, char * argv[] )
    2. {
    3. QApplication app( argc, argv );
    4. MyMainWindow mainWindow;
    5.  
    6. mainWindow.show();
    7. app.exec();
    8. }
    9.  
    10. MyMainWindow::MyMainWindow( QWidget * parent ) : QMainWindow( parent )
    11. {
    12. // setupUi, etc.
    13.  
    14. QTimer::singleShot( 0, this, SLOT( onSSTimeout() ) );
    15. }
    16.  
    17. void MyMainWindow::onSSTimeout()
    18. {
    19. IdleTimer::instance( qApp, 20 );
    20. }
    To copy to clipboard, switch view to plain text mode 

  17. The following user says thank you to d_stranz for this useful post:

    Cupidvogel (30th December 2015)

  18. #14
    Join Date
    May 2014
    Posts
    136
    Thanks
    72
    Qt products
    Qt3 Qt4 PyQt3 PyQt4
    Platforms
    MacOS X Windows

    Default Re: Timer to find out if app id idle not working as expected

    Oh okay. I thought that as well, but then went on with the other way. Lemme try it out..


    Added after 19 minutes:


    Nope. Still doesn't work. I suspected as much. If it were the event loop problem, then the timer won't even start. Something else is wrong here..
    Last edited by Cupidvogel; 30th December 2015 at 19:08.

  19. #15
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,318
    Thanks
    315
    Thanked 870 Times in 857 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Timer to find out if app id idle not working as expected

    I would strip it down to the bare minimum. Forget the IdleTimer code - you don't need a singleton, you just need a timer that resets itself on a mouse or keyboard event. Derive from QTimer, add the event filter to it, add the timeout slot, and create it in main().

  20. The following user says thank you to d_stranz for this useful post:

    Cupidvogel (30th December 2015)

  21. #16
    Join Date
    May 2014
    Posts
    136
    Thanks
    72
    Qt products
    Qt3 Qt4 PyQt3 PyQt4
    Platforms
    MacOS X Windows

    Default Re: Timer to find out if app id idle not working as expected

    Yep. Doing that..

Similar Threads

  1. MVC - canFetchMore() is not working as expected
    By prasad_N in forum Qt Programming
    Replies: 6
    Last Post: 13th October 2015, 11:41
  2. QDir not working as expected
    By BettaUseYoNikes in forum Qt Programming
    Replies: 2
    Last Post: 24th August 2011, 16:55
  3. Replies: 2
    Last Post: 22nd December 2010, 10:37
  4. keyPressevent not working with timer.
    By T1001 in forum Newbie
    Replies: 5
    Last Post: 9th December 2010, 04:55
  5. QTableView not working as expected.
    By junxuan in forum Qt Programming
    Replies: 7
    Last Post: 30th July 2009, 08:17

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Qt is a trademark of The Qt Company.