DriverSDL: Add support for timeouts.
authorRadek Brich <radek.brich@devl.cz>
Tue, 08 Jan 2013 01:12:07 +0100
changeset 57 911927edbdde
parent 56 282a07d20680
child 58 50308ed5e4f9
DriverSDL: Add support for timeouts.
sdlterm/cython/sdlterm.pyx
sdlterm/demo.cc
sdlterm/src/sdlterm.cc
sdlterm/src/sdlterm.h
tuikit/application.py
tuikit/driver_curses.py
tuikit/driver_dummy.py
tuikit/driver_sdl.py
--- a/sdlterm/cython/sdlterm.pyx	Mon Jan 07 23:15:17 2013 +0100
+++ b/sdlterm/cython/sdlterm.pyx	Tue Jan 08 01:12:07 2013 +0100
@@ -48,7 +48,7 @@
         void show_cursor(int x, int y)
         void hide_cursor()
 
-        void get_next_event(Event event)
+        bool wait_event(Event event, int timeout) except +
 
         int get_width()
         int get_height()
@@ -85,8 +85,10 @@
     def hide_cursor(self):
         self.thisptr.hide_cursor()
 
-    def get_next_event(self):
-        self.thisptr.get_next_event(self.event)
+    def wait_event(self, timeout):
+        if not self.thisptr.wait_event(self.event, timeout or 0):
+            # timeout
+            return None
         event = self.event
         if event.type == event.MOUSEMOVE:
             return ('mousemove', event.mouse.x, event.mouse.y)
--- a/sdlterm/demo.cc	Mon Jan 07 23:15:17 2013 +0100
+++ b/sdlterm/demo.cc	Tue Jan 08 01:12:07 2013 +0100
@@ -39,7 +39,7 @@
 void Application::wait_and_process_event()
 {
     Event event;
-    term.get_next_event(event);
+    term.wait_event(event, 0);
 
     switch (event.type)
     {
--- a/sdlterm/src/sdlterm.cc	Mon Jan 07 23:15:17 2013 +0100
+++ b/sdlterm/src/sdlterm.cc	Tue Jan 08 01:12:07 2013 +0100
@@ -310,7 +310,7 @@
  : _screen(), _attr(7), _cursor_x(0), _cursor_y(0), _cursor_visible(false),
    _mousemove_last_x(-1), _mousemove_last_y(-1)
 {
-    if (SDL_Init(SDL_INIT_VIDEO) == -1)
+    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1)
     {
         fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());
         throw std::exception();
@@ -341,22 +341,41 @@
     }
 }
 
-void Terminal::get_next_event(Event &event)
+
+bool Terminal::wait_event(Event &event, Uint32 timeout)
 {
     static SDL_Event sdl_event;
 
+    // use timer to simulate SDL_WaitEventTimeout, which is not available in SDL 1.2
+    SDL_TimerID timer_id = NULL;
+    if (timeout)
+    {
+        timer_id = SDL_AddTimer(timeout, _wait_event_callback, NULL);
+    }
+
     while (SDL_WaitEvent(&sdl_event))
     {
+        if (timer_id)
+        {
+            if (sdl_event.type == SDL_USEREVENT && sdl_event.user.code == 1)
+            {
+                // timeout
+                return false;
+            }
+            // some event came before timeout...
+            SDL_RemoveTimer(timer_id);
+            timer_id = NULL;
+        }
         switch (sdl_event.type)
         {
             case SDL_QUIT:
                 event.type = Event::QUIT;
-                return;
+                return true;
 
             case SDL_VIDEORESIZE:
                 event.type = Event::RESIZE;
                 _screen.resize(sdl_event.resize.w, sdl_event.resize.h);
-                return;
+                return true;
 
             case SDL_VIDEOEXPOSE:
                 _screen.redraw();
@@ -380,7 +399,7 @@
                     if (!event.key.unicode)
                         break; // continue loop (unknown key)
                 }
-                return;
+                return true;
             }
 
             case SDL_MOUSEBUTTONDOWN:
@@ -396,7 +415,7 @@
                     event.type = Event::MOUSEWHEEL;
                 }
                 _mousemove_last_x = -1;
-                return;
+                return true;
 
             case SDL_MOUSEMOTION:
                 if (sdl_event.motion.state == 0)
@@ -409,7 +428,7 @@
                 {
                     _mousemove_last_x = event.mouse.x;
                     _mousemove_last_y = event.mouse.y;
-                    return;
+                    return true;
                 }
                 break; // continue loop when mouse position did not change
 
@@ -417,6 +436,8 @@
                 break; // continue loop
         }
     }
+    fprintf(stderr, "SDL_WaitEvent error: %s\n", SDL_GetError());
+    throw std::exception();
 }
 
 
@@ -458,3 +479,13 @@
     }
 }
 
+
+Uint32 Terminal::_wait_event_callback(Uint32 interval, void *param)
+{
+    SDL_Event event;
+    event.type = SDL_USEREVENT;
+    event.user.code = 1;
+    SDL_PushEvent(&event);
+    return 0;
+}
+
--- a/sdlterm/src/sdlterm.h	Mon Jan 07 23:15:17 2013 +0100
+++ b/sdlterm/src/sdlterm.h	Tue Jan 08 01:12:07 2013 +0100
@@ -199,7 +199,12 @@
     void show_cursor(int x, int y) { _cursor_x = x; _cursor_y = y; _cursor_visible = true; };
     void hide_cursor() { _cursor_visible = false; };
 
-    void get_next_event(Event &event);
+    /* Wait for an event.
+     *
+     * Timeout is in miliseconds, zero means wait indefinitely.
+     * Returns false on timeout, true on event.
+     */
+    bool wait_event(Event &event, Uint32 timeout);
 
     int get_width() const { return _screen.get_width(); };
     int get_height() const { return _screen.get_height(); };
@@ -215,5 +220,6 @@
     int _mousemove_last_y;
 
     const char *_translate_keyname(SDLKey sym);
+    static Uint32 _wait_event_callback(Uint32 interval, void *param);
 };
 
--- a/tuikit/application.py	Mon Jan 07 23:15:17 2013 +0100
+++ b/tuikit/application.py	Tue Jan 08 01:12:07 2013 +0100
@@ -42,18 +42,21 @@
 
 
     def has_timeout(self):
-        return len(self.timeout) and True or False
+        return len(self.timeout) > 0
 
 
     def nearest_timeout(self):
+        if not self.has_timeout():
+            return None
         return min(self.timeout)[0]
 
 
     def process_timeout(self):
+        if not self.has_timeout():
+            return
         now = time.time()
         lasted = now - self.timelast
         self.timelast = now
-
         for to in self.timeout[:]:
             newt = to[0] - lasted
             if newt <= 0.0:
@@ -104,14 +107,9 @@
             self.top.draw(self.driver)
             self.driver.commit()
 
-            timeout = None
-            if self.top.has_timeout():
-                timeout = int(math.ceil(self.top.nearest_timeout() * 10))
-
+            timeout = self.top.nearest_timeout()
             events = self.driver.getevents(timeout)
-
-            if self.top.has_timeout():
-                self.top.process_timeout()
+            self.top.process_timeout()
 
             for event in events:
                 if event[0] == 'quit':
--- a/tuikit/driver_curses.py	Mon Jan 07 23:15:17 2013 +0100
+++ b/tuikit/driver_curses.py	Tue Jan 08 01:12:07 2013 +0100
@@ -2,7 +2,7 @@
 
 import curses.wrapper
 import curses.ascii
-import locale
+import math
 import logging
 
 from tuikit.driver import Driver
@@ -185,6 +185,11 @@
     ## input ##
 
     def inputqueue_fill(self, timeout=None):
+        """Wait for curses input, add it to inputqueue.
+
+        timeout -- int, tenths of second (None=infinite)
+
+        """
         if timeout is None:
             # wait indefinitely
             c = self.screen.getch()
@@ -241,8 +246,15 @@
 
 
     def getevents(self, timeout=None):
+        '''Process input, return list of events.
+
+        timeout -- float, in seconds
+
+        '''
         # empty queue -> fill
         if len(self.inputqueue) == 0:
+            if timeout is not None:
+                timeout = math.ceil(timeout * 10)
             self.inputqueue_fill(timeout)
 
         res = []
--- a/tuikit/driver_dummy.py	Mon Jan 07 23:15:17 2013 +0100
+++ b/tuikit/driver_dummy.py	Tue Jan 08 01:12:07 2013 +0100
@@ -31,6 +31,8 @@
     def getevents(self, timeout=None):
         '''Process input, return list of events.
 
+        timeout -- float, in seconds
+
         This dummy implementation just returns 'q' and Escape key presses.
 
         '''
--- a/tuikit/driver_sdl.py	Mon Jan 07 23:15:17 2013 +0100
+++ b/tuikit/driver_sdl.py	Tue Jan 08 01:12:07 2013 +0100
@@ -66,8 +66,16 @@
     ## input ##
 
     def getevents(self, timeout=None):
-        '''Process input, return list of events.'''
-        event = self.sdlterm.get_next_event()
+        '''Process input, return list of events.
+
+        timeout -- float, in seconds
+
+        '''
+        if timeout is not None:
+            timeout = int(timeout*1000)
+        event = self.sdlterm.wait_event(timeout)
+        if not event:
+            return []
         if event[0] == 'resize':
             self.size.w, self.size.h = self.sdlterm.width, self.sdlterm.height
         return [event]