Update sdlterm: Optimize commit() - use two cell buffers, redraw only dirty cells, not everything. Fix keypress event, filter mousemove.
--- a/sdlterm/cython/sdlterm.pyx Sat Jan 05 12:40:32 2013 +0100
+++ b/sdlterm/cython/sdlterm.pyx Sat Jan 05 16:47:30 2013 +0100
@@ -3,7 +3,7 @@
# distutils: include_dirs = /usr/include/SDL src
# distutils: libraries = SDL SDL_ttf
# distutils: define_macros = _GNU_SOURCE=1 _REENTRANT
-# distutils: extra_compile_args = --std=c++0x
+# distutils: extra_compile_args = --std=c++11
# cython: language_level=3
from libcpp cimport bool
@@ -35,8 +35,8 @@
cdef cppclass Terminal:
Terminal() except +
- void select_font(char *fname_regular, char *fname_bold, int ptsize)
- void resize(int pxwidth, int pxheight)
+ void select_font(char *fname_regular, char *fname_bold, int ptsize) except +
+ void resize(int pxwidth, int pxheight) except +
void erase()
void putch(int x, int y, Py_UNICODE ch)
@@ -56,6 +56,7 @@
cdef class SDLTerminal:
cdef Terminal *thisptr # hold a C++ instance which we're wrapping
+ cdef Event event
def __cinit__(self):
self.thisptr = new Terminal()
@@ -77,8 +78,8 @@
self.thisptr.commit()
def get_next_event(self):
- cdef Event event
- self.thisptr.get_next_event(event)
+ self.thisptr.get_next_event(self.event)
+ event = self.event
if event.type == event.MOUSEMOVE:
return ('mousemove', event.mouse.x, event.mouse.y)
if event.type == event.MOUSEDOWN:
--- a/sdlterm/src/sdlterm.cc Sat Jan 05 12:40:32 2013 +0100
+++ b/sdlterm/src/sdlterm.cc Sat Jan 05 16:47:30 2013 +0100
@@ -1,6 +1,7 @@
#include "sdlterm.h"
-#include <stdexcept>
+#include <exception>
+#include <algorithm>
SDL_Surface *GlyphCache::lookup_glyph(Uint16 ch)
@@ -122,12 +123,7 @@
}
TTF_Font *font = _font_regular;
- SDL_Color color={0xff,0xff,0xff}, bgcolor={0,100,100};
- if (ch != 'W')
- {
- bgcolor.g = 0;
- bgcolor.b = 0;
- }
+ SDL_Color color={0xff,0xff,0xff}, bgcolor={0,0,0};
// create surface for whole cell and fill it with bg color
cell_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
@@ -141,28 +137,29 @@
SDL_FillRect(cell_surface, &dst_rect, bgcolor_mapped);
// render glyph, blit it onto cell surface
- SDL_Surface *glyph_surface = TTF_RenderGlyph_Shaded(font, ch, color, bgcolor);
- int minx, maxy;
- TTF_GlyphMetrics(font, ch, &minx, NULL, NULL, &maxy, NULL);
- dst_rect.x = minx;
- dst_rect.y = TTF_FontAscent(font) - maxy;
- SDL_BlitSurface(glyph_surface, NULL, cell_surface, &dst_rect);
- SDL_FreeSurface(glyph_surface);
+ if (ch)
+ {
+ SDL_Surface *glyph_surface = TTF_RenderGlyph_Shaded(font, ch, color, bgcolor);
+ int minx, maxy;
+ TTF_GlyphMetrics(font, ch, &minx, NULL, NULL, &maxy, NULL);
+ dst_rect.x = minx;
+ dst_rect.y = TTF_FontAscent(font) - maxy;
+ SDL_BlitSurface(glyph_surface, NULL, cell_surface, &dst_rect);
+ SDL_FreeSurface(glyph_surface);
+ }
+ // convert to display format
+ SDL_Surface *tmp_surface = cell_surface;
+ cell_surface = SDL_DisplayFormat(tmp_surface);
+ SDL_FreeSurface(tmp_surface);
+
+ // put to cache
_cache.put_glyph(ch, cell_surface);
+
return cell_surface;
}
-TerminalScreen::~TerminalScreen()
-{
- if (_cells)
- {
- delete[] _cells;
- }
-}
-
-
void TerminalScreen::select_font(const char *fname_regular, const char *fname_bold, int ptsize)
{
_render.open_font(fname_regular, fname_bold, ptsize);
@@ -171,7 +168,7 @@
void TerminalScreen::resize(int pxwidth, int pxheight)
{
- _screen_surface = SDL_SetVideoMode(pxwidth, pxheight, 32, SDL_HWSURFACE|SDL_RESIZABLE);
+ _screen_surface = SDL_SetVideoMode(pxwidth, pxheight, 0, SDL_SWSURFACE|SDL_ANYFORMAT|SDL_RESIZABLE);
if (_screen_surface == NULL)
{
@@ -190,19 +187,13 @@
void TerminalScreen::erase()
{
- TerminalCell * cell = _cells;
- for (int i = 0; i < _width * _height; i++)
- {
- cell->ch = ' ';
- cell->attr = 0;
- cell++;
- }
+ std::fill(_cells_front.begin(), _cells_front.end(), TerminalCell());
}
void TerminalScreen::putch(int x, int y, Uint16 ch, Uint16 attr)
{
- TerminalCell &cell = _cells[y * _width + x];
+ TerminalCell &cell = _cells_front[y * _width + x];
cell.ch = ch;
cell.attr = attr;
}
@@ -210,18 +201,24 @@
void TerminalScreen::commit()
{
- TerminalCell * cell = _cells;
+ auto front_iter = _cells_front.begin();
+ auto back_iter = _cells_back.begin();
SDL_Surface *glyph_surface;
SDL_Rect dst_rect;
for (int y = 0; y < _height; y++)
{
for (int x = 0; x < _width; x++)
{
- dst_rect.x = x * _cell_width;
- dst_rect.y = y * _cell_height;
- glyph_surface = _render.render_glyph(cell->ch);
- SDL_BlitSurface(glyph_surface, NULL, _screen_surface, &dst_rect);
- cell++;
+ if (*front_iter != *back_iter)
+ {
+ dst_rect.x = x * _cell_width;
+ dst_rect.y = y * _cell_height;
+ glyph_surface = _render.render_glyph(front_iter->ch);
+ SDL_BlitSurface(glyph_surface, NULL, _screen_surface, &dst_rect);
+ *back_iter = *front_iter;
+ }
+ front_iter++;
+ back_iter++;
}
}
@@ -231,24 +228,19 @@
void TerminalScreen::_reset_cells()
{
- if (_cells)
- {
- delete[] _cells;
- _cells = NULL;
- }
-
_cell_width = _render.get_cell_width();
_cell_height = _render.get_cell_height();
_width = _pixel_width / _cell_width;
_height = _pixel_height / _cell_height;
int num_cells = _width * _height;
- _cells = new TerminalCell[num_cells];
+ _cells_front.resize(num_cells);
+ _cells_back.resize(num_cells);
}
Terminal::Terminal()
- : _screen()
+ : _screen(), _mousemove_last_x(-1)
{
if (SDL_Init(SDL_INIT_VIDEO) == -1)
{
@@ -267,7 +259,7 @@
void Terminal::get_next_event(Event &event)
{
- SDL_Event sdl_event;
+ static SDL_Event sdl_event;
while (SDL_WaitEvent(&sdl_event))
{
@@ -278,11 +270,25 @@
return;
case SDL_KEYDOWN:
+ {
//switch(event.key.keysym.sym)
event.type = Event::KEYPRESS;
- event.key.unicode = sdl_event.key.keysym.unicode;
- strncpy(event.key.keyname, _translate_keyname(sdl_event.key.keysym.sym), 10);
+ const char *keyname = _translate_keyname(sdl_event.key.keysym.sym);
+ // return only keyname or unicode, never both
+ if (keyname)
+ {
+ strncpy(event.key.keyname, keyname, 10);
+ event.key.unicode = 0;
+ }
+ else
+ {
+ event.key.keyname[0] = 0;
+ event.key.unicode = sdl_event.key.keysym.unicode;
+ if (!event.key.unicode)
+ break; // continue loop (unknown key)
+ }
return;
+ }
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
@@ -290,13 +296,21 @@
event.mouse.x = sdl_event.button.x / _screen.get_cell_width();
event.mouse.y = sdl_event.button.y / _screen.get_cell_height();
event.mouse.button = sdl_event.button.button;
+ _mousemove_last_x = -1;
return;
case SDL_MOUSEMOTION:
event.type = Event::MOUSEMOVE;
event.mouse.x = sdl_event.motion.x / _screen.get_cell_width();
event.mouse.y = sdl_event.motion.y / _screen.get_cell_height();
- return;
+ if (_mousemove_last_x != event.mouse.x ||
+ _mousemove_last_y != event.mouse.y)
+ {
+ _mousemove_last_x = event.mouse.x;
+ _mousemove_last_y = event.mouse.y;
+ return;
+ }
+ break; // continue loop when mouse position did not change
default:
break; // continue loop
@@ -337,7 +351,7 @@
case SDLK_F10: return "f10";
case SDLK_F11: return "f11";
case SDLK_F12: return "f12";
- default: return "";
+ default: return NULL;
}
}
--- a/sdlterm/src/sdlterm.h Sat Jan 05 12:40:32 2013 +0100
+++ b/sdlterm/src/sdlterm.h Sat Jan 05 16:47:30 2013 +0100
@@ -45,14 +45,15 @@
{
Uint16 ch;
Uint16 attr;
+ bool operator !=(const TerminalCell &rhs) const { return ch != rhs.ch || attr != rhs.attr; };
};
class TerminalScreen
{
public:
- TerminalScreen(): _screen_surface(NULL), _cells(NULL), _render() {};
- ~TerminalScreen();
+ TerminalScreen(): _screen_surface(NULL), _render() {};
+ ~TerminalScreen() {};
void select_font(const char *fname_regular, const char *fname_bold, int ptsize);
void resize(int pxwidth, int pxheight);
@@ -68,7 +69,8 @@
private:
SDL_Surface *_screen_surface;
- TerminalCell *_cells;
+ std::vector<TerminalCell> _cells_front;
+ std::vector<TerminalCell> _cells_back;
GlyphRenderer _render;
int _pixel_width; // terminal window width in pixels
@@ -135,6 +137,9 @@
int _cursor_y;
bool _cursor_visible;
+ int _mousemove_last_x;
+ int _mousemove_last_y;
+
const char *_translate_keyname(SDLKey sym);
};
--- a/tuikit/application.py Sat Jan 05 12:40:32 2013 +0100
+++ b/tuikit/application.py Sat Jan 05 16:47:30 2013 +0100
@@ -67,7 +67,7 @@
'''Application class. Defines main loop.'''
- def __init__(self, driver = 'curses'):
+ def __init__(self, driver = 'sdl'):
'''Create application.'''
self.top = TopWindow()