- redraw now in idle
authorFelix Domke <tmbinc@elitedvb.net>
Thu, 20 Jan 2005 14:35:19 +0000 (14:35 +0000)
committerFelix Domke <tmbinc@elitedvb.net>
Thu, 20 Jan 2005 14:35:19 +0000 (14:35 +0000)
 - mainloop called from python (could be changed)
 - clock components manages timer
 - timer usuable from python

14 files changed:
components.py
configure.ac
lib/base/ebase.cpp
lib/base/ebase.h
lib/gdi/fb.cpp
lib/gui/ewidgetdesktop.cpp
lib/gui/ewidgetdesktop.h
lib/gui/ewindowstyle.cpp
lib/python/Makefile.am
lib/python/enigma_python.i
lib/python/python.cpp
main/Makefile.am
main/enigma.cpp
mytest.py

index 7c79323..8ae4806 100644 (file)
@@ -82,6 +82,10 @@ class Clock(HTMLComponent, GUIComponent, VariableText):
                VariableText.__init__(self)
                GUIComponent.__init__(self)
                self.doClock()
+               
+               self.clockTimer = eTimer()
+               self.clockTimer.timeout.get().append(self.doClock)
+               self.clockTimer.start(1000)
 
 # "funktionalitaet"    
        def doClock(self):
index 7768a97..ca870fd 100644 (file)
@@ -20,7 +20,8 @@ TUXBOX_APPS_LIB_PKGCONFIG(PNG,libpng)
 TUXBOX_APPS_LIB_PKGCONFIG(SIGC,sigc++-1.2)
 TUXBOX_APPS_LIB_PKGCONFIG(XMLTREE,tuxbox-xmltree)
 
-CPPFLAGS="$CPPFLAGS $FREETYPE_CFLAGS $FRIBIDI_CFLAGS $ID3TAG_CFLAGS $MAD_CFLAGS $PLUGINS_CFLAGS $PNG_CFLAGS $SIGC_CFLAGS $XMLTREE_CFLAGS"
+# fixme: decent python stuff
+CPPFLAGS="$CPPFLAGS $FREETYPE_CFLAGS $FRIBIDI_CFLAGS $ID3TAG_CFLAGS $MAD_CFLAGS $PLUGINS_CFLAGS $PNG_CFLAGS $SIGC_CFLAGS $XMLTREE_CFLAGS -I/usr/include/python2.3"
 CXXFLAGS="$CXXFLAGS -fno-rtti -fno-exceptions -Wall"
 
 TUXBOX_APPS_GETTEXT
index 3babc2e..b62452d 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <fcntl.h>
 #include <unistd.h>
+#include <errno.h>
 
 #include <lib/base/eerror.h>
 
@@ -50,7 +51,8 @@ void eTimer::start(long msek, bool singleShot)
 }
 
 void eTimer::stop()
-{
+{      
+       eDebug("stop timer");
        if (bActive)
        {
                bActive=false;
@@ -74,7 +76,7 @@ void eTimer::changeInterval(long msek)
        context.addTimer(this);                         // add Timer to context TimerList
 }
 
-void eTimer::activate()   // Internal Funktion... called from eApplication
+void eTimer::activate()   // Internal Function... called from eApplication
 {
        timeval now;
        gettimeofday(&now, 0);
@@ -107,16 +109,47 @@ void eMainloop::removeSocketNotifier(eSocketNotifier *sn)
 
 void eMainloop::processOneEvent()
 {
-// process pending timers...
+               /* notes:
+                 - we should use epoll(4)
+                 - timer are checked twice. there was a strong reason for it, but i can't remember. (FIXME)
+                 - for each time, we gettimeofday() and check wether the timer should fire.
+                   we should do this all better - we know how long the poll last, so we know which
+                   timers should fire. Problem is that a timer handler could have required so
+                   much time that another timer fired.
+                   
+                   A probably structure could look
+                   
+                   while (1)
+                   {
+                           time = gettimeofday()
+                           timeout = calculate_pending_timers(time);
+                   
+                     doPoll(timeout or infinite);
+                       
+                       if (poll_had_results)
+                               handle_poll_handler();
+                       else
+                                   fire_timers(time + timeout)
+                         }
+                         
+                         the gettimeofday() call is required because fire_timers could last more
+                         than nothing.
+                         
+                         when poll did no timeout, we don't handle timers, as this will be done
+                         in the next iteration (without adding overhead - we had to get the new
+                         time anyway
+               */
+
+               // first, process pending timers...
        long usec=0;
 
        while (TimerList && (usec = timeout_usec( TimerList.begin()->getNextActivation() ) ) <= 0 )
                TimerList.begin()->activate();
 
+               // build the poll aray
        int fdAnz = notifiers.size();
        pollfd* pfd = new pollfd[fdAnz];  // make new pollfd array
 
-// fill pfd array
        std::map<int,eSocketNotifier*>::iterator it(notifiers.begin());
        for (int i=0; i < fdAnz; i++, it++)
        {
@@ -124,11 +157,11 @@ void eMainloop::processOneEvent()
                pfd[i].events = it->second->getRequested();
        }
 
-       int ret=poll(pfd, fdAnz, TimerList ? usec / 1000 : -1);  // milli .. not micro seks
+               // to the poll. When there are no timers, we have an infinite timeout
+       int ret=poll(pfd, fdAnz, TimerList ? usec / 1000 : -1);  // convert to us
 
        if (ret>0)
        {
-//             eDebug("bin aussem poll raus und da war was");
                for (int i=0; i < fdAnz ; i++)
                {
                        if( notifiers.find(pfd[i].fd) == notifiers.end())
@@ -143,13 +176,17 @@ void eMainloop::processOneEvent()
                                if (!--ret)
                                        break;
                        } else if (pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL))
-                               eDebug("poll: unhandled POLLERR/HUP/NVAL for fd %d(%d)", pfd[i].fd,pfd[i].revents);
+                               eFatal("poll: unhandled POLLERR/HUP/NVAL for fd %d(%d) -> FIX YOUR CODE", pfd[i].fd,pfd[i].revents);
                }
-       }
-       else if (ret<0)
-               eDebug("poll made error");
+       } else if (ret<0)
+       {
+                       /* when we got a signal, we get EINTR. we do not care, 
+                          because we check current time in timers anyway. */
+               if (errno != EINTR)
+                       eDebug("poll made error (%m)");
+       } 
 
-               // check Timers...
+               // check timer...
        while ( TimerList && timeout_usec( TimerList.begin()->getNextActivation() ) <= 0 )
                TimerList.begin()->activate();
 
@@ -167,6 +204,8 @@ int eMainloop::exec()
        return retval;
 }
 
+       /* use with care! better: don't use it anymore. it was used for gui stuff, but 
+                doesn't allow multiple paths (or active dialogs, if you want it that way.) */
 void eMainloop::enter_loop()
 {
        loop_level++;
index b929cb6..187f954 100644 (file)
@@ -9,6 +9,7 @@
 #include <time.h>
 
 #include <lib/base/eptrlist.h>
+#include <lib/python/connections.h>
 #include <libsig_comp.h>
 
 class eApplication;
@@ -158,7 +159,7 @@ public:
        eSocketNotifier(eMainloop *context, int fd, int req, bool startnow=true);
        ~eSocketNotifier();
 
-       Signal1<void, int> activated;
+       PSignal1<void, int> activated;
        void activate(int what) { /*emit*/ activated(what); }
 
        void start();
@@ -193,7 +194,7 @@ public:
        eTimer(eMainloop *context): context(*context), bActive(false) { }
        ~eTimer()       { if (bActive) stop(); }
 
-       Signal0<void> timeout;
+       PSignal0<void> timeout;
        void activate();
 
        bool isActive() { return bActive; }
index e792204..fb0cc03 100644 (file)
@@ -59,7 +59,7 @@ fbClass::fbClass(const char *fb)
                goto nolfb;
        }
 
-       showConsole(0);
+//     showConsole(0);
        return;
 nolfb:
        lfb=0;
index ff91368..bb6c7c3 100644 (file)
@@ -1,5 +1,6 @@
 #include <lib/gui/ewidgetdesktop.h>
 #include <lib/gui/ewidget.h>
+#include <lib/base/ebase.h>
 
 void eWidgetDesktop::addRootWidget(eWidget *root, int top)
 {
@@ -50,6 +51,8 @@ void eWidgetDesktop::recalcClipRegions()
 
 void eWidgetDesktop::invalidate(const gRegion &region)
 {
+       if (m_timer && m_dirty_region.empty())
+               m_timer->start(0, 1); // start singleshot redraw timer
        m_dirty_region |= region;
 }
 
@@ -67,7 +70,23 @@ void eWidgetDesktop::setDC(gDC *dc)
        m_dc = dc;
 }
 
-eWidgetDesktop::eWidgetDesktop(eSize size): m_screen_size(size)
+void eWidgetDesktop::setRedrawTask(eMainloop &ml)
+{
+       if (m_mainloop)
+       {
+               delete m_timer;
+               m_timer = 0;
+               m_mainloop = 0;
+       }
+       m_mainloop = &ml;
+       m_timer = new eTimer(m_mainloop);
+       CONNECT(m_timer->timeout, eWidgetDesktop::paint);
+       
+       if (!m_dirty_region.empty())
+               m_timer->start(0, 1);
+}
+
+eWidgetDesktop::eWidgetDesktop(eSize size): m_screen_size(size), m_mainloop(0), m_timer(0)
 {
 }
 
index 42e6b61..1354a86 100644 (file)
@@ -5,8 +5,10 @@
 #include <lib/base/eptrlist.h>
 
 class eWidget;
+class eMainloop;
+class eTimer;
 
-class eWidgetDesktop
+class eWidgetDesktop: public Object
 {
 public: // weil debug
        eSize m_screen_size;
@@ -22,9 +24,14 @@ public:
        void invalidate(const gRegion &region);
        void paint();
        void setDC(gDC *dc);
+       
+       void setRedrawTask(eMainloop &ml);
 private:
        ePtrList<eWidget> m_root;
        void calcWidgetClipRegion(eWidget *widget, gRegion &parent_visible);
+       
+       eMainloop *m_mainloop;
+       eTimer *m_timer;
 };
 
 #endif
index 778291c..8599cfd 100644 (file)
@@ -53,7 +53,6 @@ void eWindowStyleSimple::paintWindowDecoration(eWindow *wnd, gPainter &painter,
 
 void eWindowStyleSimple::paintBackground(gPainter &painter, const ePoint &offset, const eSize &size)
 {
-       eDebug("eWindowStyleSimple::paintBackground");
        painter.setBackgroundColor(m_background_color);
        painter.clear();
 }
index c3d98c0..e82cb65 100644 (file)
@@ -1,12 +1,11 @@
 INCLUDES = \
        -I$(top_srcdir)/include \
-       -I$(top_srcdir)/src \
-       -I/usr/include/python2.3
+       -I$(top_srcdir)/src
 
 noinst_LIBRARIES = libenigma_python.a
 
 libenigma_python_a_SOURCES = \
-       python.cpp enigma_python_wrap.cxx
+       python.cpp enigma_python_wrap.cxx connections.cpp
 
 enigma_python_wrap.cxx: enigma_python.i
        swig -I$(top_srcdir)/ -c++ -python enigma_python.i
index 15bc16e..c621bb6 100644 (file)
@@ -1,6 +1,43 @@
+/*
+  NOTE: you have two options when adding classes so that
+  they are callable *from* python.
+  
+   - either you %include the header file
+   - or you re-declare it
+   
+  In both cases, you must #include the required
+  header file (i.e. the header file itself), otherwise
+  enigma_python_wrap.cxx won't build.
+  
+       In case you import the whole header file,
+       please make sure that no unimportant stuff
+       is wrapped, as this makes the wrapper stuff
+       much more complex and it can probably break 
+       very easily because of missing typemaps etc.
+       
+       you could make use of dizzy macros to ensure
+       that some stuff is left out when parsed as SWIG
+       definitions, but be sure to not modify the binary 
+       representation. DON'T USE #ifdef SWIG_COMPILE
+       for leaving out stuff (unless you *really* know
+       what you are doing,of course!). you WILL break it.
+               
+       The better way (with more work) is to re-declare
+       the class. It won't be compiled, so you can
+       leave out stuff as you like.
+
+
+
+Oh, things like "operator= is private in this context" etc.
+is usually caused by not marking PSignals as immutable.
+
+*/
+
+
 %module enigma
 %{
 #define SWIG_COMPILE
+#include <lib/base/ebase.h>
 #include <lib/base/smartptr.h>
 #include <lib/base/eerror.h>
 #include <lib/base/econfig.h>
@@ -14,6 +51,8 @@
 #include <lib/gui/ewidgetdesktop.h>
 #include <lib/gui/eslider.h>
 #include <lib/python/connections.h>
+
+extern void runMainloop();
 %}
 
 #define DEBUG
@@ -69,3 +108,22 @@ public:
        $1 = $input->get();
 }
 
+
+/**************  base  **************/
+
+%immutable eTimer::timeout;
+
+class eTimer
+{
+public:
+       eTimer(eMainloop *context = eApp);
+       PSignal0<void> timeout;
+
+       void start(long msec, bool singleShot=false);
+       void stop();
+       void changeInterval(long msek);
+};
+
+/**************  debug  **************/
+
+void runMainloop();
index 9e7e5c2..14e32af 100644 (file)
@@ -103,7 +103,7 @@ void ePython::call(PyObject *pFunc, PyObject *pArgs)
                pValue = PyObject_CallObject(pFunc, pArgs);
                if (pValue != NULL)
                {
-                       printf("Result of call: %ld\n", PyInt_AsLong(pValue));
+//                     printf("Result of call: %ld\n", PyInt_AsLong(pValue));
                        Py_DECREF(pValue);
                } else
                {
index 6b0fb41..46ce98b 100644 (file)
@@ -1,5 +1,6 @@
 INCLUDES = \
-       -I$(top_srcdir)/include
+       -I$(top_srcdir)/include \
+       -I/usr/include/python2.3
 
 bin_PROGRAMS = enigma2
 
index d350f44..faff4d8 100644 (file)
@@ -19,6 +19,7 @@
 #include <lib/gui/ewindow.h>
 
 #include <lib/python/python.h>
+#include <lib/python/connections.h>
 
 #ifdef OBJECT_DEBUG
 int object_total_remaining;
@@ -28,11 +29,6 @@ void object_dump()
        printf("%d items left\n", object_total_remaining);
 }
 #endif
-using namespace std;
-       void print(const string &str, const char *c)
-       {
-               printf("%s (%s)\n", str.c_str(), c);
-       }
 
 void dumpRegion(const gRegion &region)
 {
@@ -66,6 +62,13 @@ public:
 
 eWidgetDesktop *wdsk;
 
+// typedef struct _object PyObject;
+
+void print(int i)
+{
+       printf("C++ says: it's a %d!!!\n", i);
+}
+
 int main(int argc, char **argv)
 {
 #ifdef OBJECT_DEBUG
@@ -103,63 +106,15 @@ int main(int argc, char **argv)
        
        wdsk = &dsk;
        dsk.setDC(my_dc);
-
-       eWindow *wnd = new eWindow(&dsk);
-       wnd->move(ePoint(100, 100));
-       wnd->resize(eSize(200, 200));
-       wnd->show();
-
-       eLabel *label = new eButton(wnd);
-       label->setText("Hello!!");
-       label->move(ePoint(40, 40));
-       label->resize(eSize(100, 40));
-
-       label = new eButton(wnd);
-       label->setText("2nd!!");
-       label->move(ePoint(40, 90));
-       label->resize(eSize(100, 40));
-
-#if 0  
-       eWidget *bla2 = new eWidget(0);
-       dsk.addRootWidget(bla2, 0);
-       
-       bla2->move(ePoint(160, 160));
-       bla2->resize(eSize(200, 200));
-       bla2->show();
 #endif
 
-//     dsk.recalcClipRegions();
-//     dsk.paint();
-//     dsk.invalidate(gRegion(eRect(0, 0, 720, 576)));
-
-//     dumpRegion(wnd->m_visible_region);
-//     dumpRegion(label->m_visible_region);
-//     dumpRegion(label->m_visible_region);
+               /* redrawing is done in an idle-timer, so we have to set the context */
+       dsk.setRedrawTask(main);
        
-       eDebug("painting!");
-       
-
        ePython python;
        
-       printf("about to execute TEST :)\n");
-       python.execute("mytest", "test");
-
-       sleep(2);
-#endif
-
-#if 0
-
-               // connections mit parametern: geht! :)
-       using namespace std;
-       using namespace SigC;
-
-       
-       Signal1<void,const string &> printer;
-       int i;
-       for (i=1; i<argc; ++i)
-               printer.connect(bind(slot(print), argv[i]));
-       printer("hello world\n");
-#endif
+       printf("executing main\n");
+       python.execute("mytest", "__main__");
 
        return 0;
 }
@@ -169,3 +124,7 @@ eWidgetDesktop *getDesktop()
        return wdsk;
 }
 
+void runMainloop()
+{
+       eApp->exec();
+}
index 53a398e..0cbeac0 100644 (file)
--- a/mytest.py
+++ b/mytest.py
@@ -55,93 +55,30 @@ class GUIOutputDevice(OutputDevice):
        def create(self, comp):
                comp.createGUIScreen(self.parent)
 
-
-
-def test():
+def runScreenTest():
        desktop = getDesktop()
-       print "desktop: " + str(desktop)
 
        wnd = eWindow(desktop)
-       print "window " + str(wnd)
-       wnd.setTitle("python")
+       mainwnd = wnd
+       wnd.setTitle("Screen from python!")
        wnd.move(ePoint(300, 100))
        wnd.resize(eSize(300, 300))
 
        gui = GUIOutputDevice()
        gui.parent = wnd
        gui.create(components["$002"])
-#      for (x,y) in components["$001"].data.items():
-#              print str(x) + " -> " + str(y) + " (" + y["instance"].getText() + ")"
 
-#      print components["$001"].data["okbutton"]["instance"].doClick()
-
-# diese sachen gehoeren in den skin! :)
        applyGUIskin(components["$002"], None, "clockDialog")
-       
-# das ist dann schon die echte funktionalitaet ;)
-       components["clock"].doClock()
-       components["clock"].doClock()
-
-
-# output as html
-       print "--------------------------------------"
-       html.create(components["$001"])
-       print "--------------------------------------"
-       html.create(components["$002"])
-       print "--------------------------------------"
-       
-       
-# direkter test der GUI aus python:
-#      label1 = eLabel(wnd)
-#      label1.setText("hello world!\nfrom python!")
-#      label1.move(ePoint(10, 10))
-#      label1.resize(eSize(80, 50))
-#
-#      label2 = eLabel(wnd)
-#      label2.setText("the second\nlabel works\nas well!")
-#      label2.move(ePoint(90, 10))
-#      label2.resize(eSize(80, 50))
-#
-#      button = eButton(wnd)
-#      button.setText("OK")
-#      button.move(ePoint(200, 10))
-#      button.resize(eSize(80, 50)) 
 
        wnd.show()
        
-       components["$002"].data["okbutton"]["instance"].push()  
-
-       for x in range(200):
-               time.sleep(0.1)
-               components["clock"].doClock()
-               if x > 100:
-                       r = 200 - x
-               else:
-                       r = x
-#              components["$002"]["okbutton"].setValue(r)
-               desktop.paint()
-       
-#      
-#      print "delete label1"
-#      del button
-#      del label2
-#      del label1
-#      print "delete wnd"
-#      del wnd
-#      print "bye"
-
-       
+#      components["$002"].data["okbutton"]["instance"].push()
+       runMainloop()
        
        return 0
 
-def testI2(a):
-       print "PYTHON says: it's a " + str(a) + "!!!"
-       return 0
 
-def testI(a = 0):
-       print "magic integer is " + str(a)
-       
-       list = testsignal.get()
-       print "list -> " + str(list)
-       list.append(testI2)
-       return 1
+# first, setup a screen
+runScreenTest()
+
+# now, run the mainloop