From: Felix Domke Date: Thu, 20 Jan 2005 14:35:19 +0000 (+0000) Subject: - redraw now in idle X-Git-Url: http://code.vuplus.com/gitweb/?p=vuplus_dvbapp;a=commitdiff_plain;h=9202d4248dd7df2f6e5eb53b4154c8297ec9b1d1 - redraw now in idle - mainloop called from python (could be changed) - clock components manages timer - timer usuable from python --- diff --git a/components.py b/components.py index 7c79323..8ae4806 100644 --- a/components.py +++ b/components.py @@ -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): diff --git a/configure.ac b/configure.ac index 7768a97..ca870fd 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/lib/base/ebase.cpp b/lib/base/ebase.cpp index 3babc2e..b62452d 100644 --- a/lib/base/ebase.cpp +++ b/lib/base/ebase.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -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::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++; diff --git a/lib/base/ebase.h b/lib/base/ebase.h index b929cb6..187f954 100644 --- a/lib/base/ebase.h +++ b/lib/base/ebase.h @@ -9,6 +9,7 @@ #include #include +#include #include class eApplication; @@ -158,7 +159,7 @@ public: eSocketNotifier(eMainloop *context, int fd, int req, bool startnow=true); ~eSocketNotifier(); - Signal1 activated; + PSignal1 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 timeout; + PSignal0 timeout; void activate(); bool isActive() { return bActive; } diff --git a/lib/gdi/fb.cpp b/lib/gdi/fb.cpp index e792204..fb0cc03 100644 --- a/lib/gdi/fb.cpp +++ b/lib/gdi/fb.cpp @@ -59,7 +59,7 @@ fbClass::fbClass(const char *fb) goto nolfb; } - showConsole(0); +// showConsole(0); return; nolfb: lfb=0; diff --git a/lib/gui/ewidgetdesktop.cpp b/lib/gui/ewidgetdesktop.cpp index ff91368..bb6c7c3 100644 --- a/lib/gui/ewidgetdesktop.cpp +++ b/lib/gui/ewidgetdesktop.cpp @@ -1,5 +1,6 @@ #include #include +#include void eWidgetDesktop::addRootWidget(eWidget *root, int top) { @@ -50,6 +51,8 @@ void eWidgetDesktop::recalcClipRegions() void eWidgetDesktop::invalidate(const gRegion ®ion) { + 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) { } diff --git a/lib/gui/ewidgetdesktop.h b/lib/gui/ewidgetdesktop.h index 42e6b61..1354a86 100644 --- a/lib/gui/ewidgetdesktop.h +++ b/lib/gui/ewidgetdesktop.h @@ -5,8 +5,10 @@ #include 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 ®ion); void paint(); void setDC(gDC *dc); + + void setRedrawTask(eMainloop &ml); private: ePtrList m_root; void calcWidgetClipRegion(eWidget *widget, gRegion &parent_visible); + + eMainloop *m_mainloop; + eTimer *m_timer; }; #endif diff --git a/lib/gui/ewindowstyle.cpp b/lib/gui/ewindowstyle.cpp index 778291c..8599cfd 100644 --- a/lib/gui/ewindowstyle.cpp +++ b/lib/gui/ewindowstyle.cpp @@ -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(); } diff --git a/lib/python/Makefile.am b/lib/python/Makefile.am index c3d98c0..e82cb65 100644 --- a/lib/python/Makefile.am +++ b/lib/python/Makefile.am @@ -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 diff --git a/lib/python/enigma_python.i b/lib/python/enigma_python.i index 15bc16e..c621bb6 100644 --- a/lib/python/enigma_python.i +++ b/lib/python/enigma_python.i @@ -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 #include #include #include @@ -14,6 +51,8 @@ #include #include #include + +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 timeout; + + void start(long msec, bool singleShot=false); + void stop(); + void changeInterval(long msek); +}; + +/************** debug **************/ + +void runMainloop(); diff --git a/lib/python/python.cpp b/lib/python/python.cpp index 9e7e5c2..14e32af 100644 --- a/lib/python/python.cpp +++ b/lib/python/python.cpp @@ -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 { diff --git a/main/Makefile.am b/main/Makefile.am index 6b0fb41..46ce98b 100644 --- a/main/Makefile.am +++ b/main/Makefile.am @@ -1,5 +1,6 @@ INCLUDES = \ - -I$(top_srcdir)/include + -I$(top_srcdir)/include \ + -I/usr/include/python2.3 bin_PROGRAMS = enigma2 diff --git a/main/enigma.cpp b/main/enigma.cpp index d350f44..faff4d8 100644 --- a/main/enigma.cpp +++ b/main/enigma.cpp @@ -19,6 +19,7 @@ #include #include +#include #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 ®ion) { @@ -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 printer; - int i; - for (i=1; iexec(); +} diff --git a/mytest.py b/mytest.py index 53a398e..0cbeac0 100644 --- 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