add 'spinner' (non-idle detection)
authorFelix Domke <tmbinc@elitedvb.net>
Fri, 25 May 2007 00:51:08 +0000 (00:51 +0000)
committerFelix Domke <tmbinc@elitedvb.net>
Fri, 25 May 2007 00:51:08 +0000 (00:51 +0000)
lib/base/ebase.cpp
lib/base/ebase.h
lib/gdi/grc.cpp
lib/gdi/grc.h
main/enigma.cpp

index 93bfd34..08c1561 100644 (file)
@@ -197,12 +197,17 @@ int eMainloop::processOneEvent(unsigned int twisted_timeout, PyObject **res, ePy
                }
        }
 
+       m_is_idle = 1;
+
        if (this == eApp)
+       {
                Py_BEGIN_ALLOW_THREADS
                ret = ::poll(pfd, fdcount, poll_timeout);
                Py_END_ALLOW_THREADS
-       else
+       else
                ret = ::poll(pfd, fdcount, poll_timeout);
+       
+       m_is_idle = 0;
 
                        /* ret > 0 means that there are some active poll entries. */
        if (ret > 0)
index f14d07a..27e4ec8 100644 (file)
@@ -191,6 +191,7 @@ class eMainloop
        int processOneEvent(unsigned int user_timeout, PyObject **res=0, ePyObject additional=ePyObject());
        int retval;
        int time_offset;
+       int m_is_idle;
        pthread_mutex_t recalcLock;
        
        int m_interrupt_requested;
@@ -211,7 +212,7 @@ public:
 #endif
 
        eMainloop()
-               :app_quit_now(0),loop_level(0),retval(0), m_interrupt_requested(0)
+               :app_quit_now(0),loop_level(0),retval(0), m_is_idle(0), m_interrupt_requested(0)
        {
                existing_loops.push_back(this);
                pthread_mutex_init(&recalcLock, 0);
@@ -242,6 +243,9 @@ public:
        PyObject *poll(SWIG_PYOBJECT(ePyObject) dict, SWIG_PYOBJECT(ePyObject) timeout);
        void interruptPoll();
        void reset();
+       
+               /* m_is_idle needs to be atomic, but it doesn't really matter much, as it's read-only from outside */
+       int isIdle() { return m_is_idle; }
 };
 
 /**
index 736630a..b3ad2cc 100644 (file)
@@ -32,6 +32,7 @@ gRC::gRC(): rp(0), wp(0)
        else
                eDebug("RC thread created successfully");
 #endif
+       m_spinner_enabled = 0;
 }
 
 DEFINE_REF(gRC);
@@ -131,8 +132,46 @@ void *gRC::thread()
                        }
 #ifndef SYNC_PAINT
                        while(rp == wp)
-                               pthread_cond_wait(&cond, &mutex);
-                       pthread_mutex_unlock(&mutex);
+                       {
+                       
+                                       /* when the main thread is non-idle for a too long time without any display output,
+                                          we want to display a spinner. */
+
+                               struct timeval time;
+                               struct timespec timeout;
+                               gettimeofday(&time, NULL);
+                               timeout.tv_sec = time.tv_sec;
+                               timeout.tv_nsec = time.tv_usec * 1000;
+                               
+                               if (m_spinner_enabled)
+                                       timeout.tv_nsec += 100*1000*1000;
+                               else
+                                       timeout.tv_nsec += 500*1000*1000;
+
+                                       /* yes, this is required. */
+                               if (timeout.tv_nsec > 1000*1000*1000)
+                               {
+                                       timeout.tv_nsec -= 1000*1000*1000;
+                                       timeout.tv_sec++;
+                               }
+
+                               int idle = 1;
+
+                               if (pthread_cond_timedwait(&cond, &mutex, &timeout) == ETIMEDOUT)
+                               {
+                                       if (eApp && !eApp->isIdle())
+                                               idle = 0;
+                               }
+                               
+                               pthread_mutex_unlock(&mutex);
+
+                               if (!idle)
+                               {
+                                       enableSpinner();
+                                       eDebug("main thread is non-idle! display spinner!");
+                               } else
+                                       disableSpinner();
+                       }
 #endif
                }
        }
@@ -152,6 +191,39 @@ gRC *gRC::getInstance()
        return instance;
 }
 
+void gRC::enableSpinner()
+{
+       if (!m_spinner_dc)
+       {
+               eDebug("no spinner DC!");
+               return;
+       }
+
+       m_spinner_enabled = 1;
+
+       gOpcode o;
+       o.opcode = m_spinner_enabled ? gOpcode::incrementSpinner : gOpcode::enableSpinner;
+       m_spinner_dc->exec(&o);
+}
+
+void gRC::disableSpinner()
+{
+       if (!m_spinner_enabled)
+               return;
+
+       if (!m_spinner_dc)
+       {
+               eDebug("no spinner DC!");
+               return;
+       }
+
+       m_spinner_enabled = 0;
+       
+       gOpcode o;
+       o.opcode = gOpcode::disableSpinner;
+       m_spinner_dc->exec(&o);
+}
+
 static int gPainter_instances;
 
 gPainter::gPainter(gDC *dc, eRect rect): m_dc(dc), m_rc(gRC::getInstance())
@@ -678,6 +750,12 @@ void gDC::exec(gOpcode *o)
                break;
        case gOpcode::flush:
                break;
+       case gOpcode::enableSpinner:
+               break;
+       case gOpcode::disableSpinner:
+               break;
+       case gOpcode::incrementSpinner:
+               break;
        default:
                eFatal("illegal opcode %d. expect memory leak!", o->opcode);
        }
index fb9e2ea..9f32e91 100644 (file)
@@ -58,6 +58,8 @@ struct gOpcode
                flip,
                notify,
                
+               enableSpinner, disableSpinner, incrementSpinner,
+               
                shutdown
        } opcode;
 
@@ -161,6 +163,13 @@ private:
 
        eFixedMessagePump<int> m_notify_pump;
        void recv_notify(const int &i);
+
+       ePtr<gDC> m_spinner_dc;
+       int m_spinner_enabled;
+       
+       void enableSpinner();
+       void disableSpinner();
+
 public:
        gRC();
        virtual ~gRC();
@@ -168,7 +177,9 @@ public:
        void submit(const gOpcode &o);
 
        Signal0<void> notify;
-
+       
+       void setSpinnerDC(gDC *dc) { m_spinner_dc = dc; }
+       
        static gRC *getInstance();
 };
 
index cc9781c..4af7ca0 100644 (file)
@@ -189,6 +189,8 @@ int main(int argc, char **argv)
                /* redrawing is done in an idle-timer, so we have to set the context */
        dsk.setRedrawTask(main);
        dsk_lcd.setRedrawTask(main);
+       
+       gRC::getInstance()->setSpinnerDC(my_dc);
 
        eRCInput::getInstance()->keyEvent.connect(slot(keyEvent));