terminal: preserve content during resize

This patch eliminates the flickering of the terminal during resize.
This commit is contained in:
Norman Feske 2018-04-22 19:06:37 +02:00 committed by Christian Helmuth
parent 674b0ba947
commit 8e0cc44e24
4 changed files with 96 additions and 3 deletions

View File

@ -190,8 +190,39 @@ void Terminal::Main::_handle_config()
bool const reconstruct = !_text_screen_surface.constructed() ||
_text_screen_surface->size() != new_geometry.size();
if (reconstruct) {
typedef Text_screen_surface<PT>::Snapshot Snapshot;
Constructible<Snapshot> snapshot { };
size_t const snapshot_bytes = _text_screen_surface.constructed()
? Snapshot::bytes_needed(*_text_screen_surface)
: 0,
preserved_bytes = 32*1024,
needed_bytes = snapshot_bytes + preserved_bytes,
avail_bytes = _env.pd().avail_ram().value;
bool const preserve_content = (needed_bytes < avail_bytes);
if (!preserve_content)
warning("not enough spare RAM to preserve content (",
"need ", Genode::Number_of_bytes(needed_bytes), ", "
"have ", Genode::Number_of_bytes(avail_bytes), ")");
if (preserve_content && _text_screen_surface.constructed())
snapshot.construct(_heap, *_text_screen_surface);
Position const orig_cursor_pos = _text_screen_surface.constructed()
? _text_screen_surface->cursor_pos()
: Position();
_text_screen_surface.construct(_heap, _font->font(),
_color_palette, _framebuffer);
if (snapshot.constructed())
_text_screen_surface->import(*snapshot);
_text_screen_surface->cursor_pos(orig_cursor_pos);
_terminal_size = _text_screen_surface->size();
} else {

View File

@ -92,6 +92,34 @@ class Terminal::Text_screen_surface
bool valid() const { return columns*lines > 0; }
};
/**
* Snapshot of text-screen content
*/
class Snapshot
{
private:
friend class Text_screen_surface;
Cell_array<Char_cell> _cell_array;
public:
static size_t bytes_needed(Text_screen_surface const &surface)
{
return Cell_array<Char_cell>::bytes_needed(surface.size().w(),
surface.size().h());
}
Snapshot(Allocator &alloc, Text_screen_surface const &from)
:
_cell_array(from._cell_array.num_cols(),
from._cell_array.num_lines(), alloc)
{
_cell_array.import_from(from._cell_array);
}
};
private:
Font const &_font;
@ -133,6 +161,10 @@ class Terminal::Text_screen_surface
_cell_array.mark_all_lines_as_dirty(); /* trigger refresh */
}
Position cursor_pos() const { return _character_screen.cursor_pos(); }
void cursor_pos(Position pos) { _character_screen.cursor_pos(pos); }
void redraw()
{
PT *fb_base = _framebuffer.pixel<PT>();
@ -238,6 +270,11 @@ class Terminal::Text_screen_surface
_decoder.insert(c.c);
}
void import(Snapshot const &snapshot)
{
_cell_array.import_from(snapshot._cell_array);
}
/**
* Return size in colums/rows
*/

View File

@ -94,6 +94,13 @@ class Cell_array
_array[i] = new (alloc) CELL[num_cols];
}
static Genode::size_t bytes_needed(unsigned num_cols, unsigned num_lines)
{
return sizeof(Char_cell_line[num_lines])
+ sizeof(bool[num_lines])
+ sizeof(CELL[num_cols])*num_lines;
}
~Cell_array()
{
for (unsigned i = 0; i < _num_lines; i++)
@ -115,11 +122,23 @@ class Cell_array
_line_dirty[line] = true;
}
CELL get_cell(int column, int line)
CELL get_cell(int column, int line) const
{
return _array[line][column];
}
void import_from(Cell_array const &other)
{
unsigned const num_cols = Genode::min(_num_cols, other._num_cols),
num_lines = Genode::min(_num_lines, other._num_lines);
for (unsigned line = 0; line < num_lines; line++)
for (unsigned column = 0; column < num_cols; column++)
_array[line][column] = other.get_cell(column, line);
mark_all_lines_as_dirty();
}
bool line_dirty(int line) { return _line_dirty[line]; }
void mark_line_as_clean(int line)
@ -167,8 +186,8 @@ class Cell_array
_line_dirty[pos.y] = true;
}
unsigned num_cols() { return _num_cols; }
unsigned num_lines() { return _num_lines; }
unsigned num_cols() const { return _num_cols; }
unsigned num_lines() const { return _num_lines; }
};
#endif /* _TERMINAL__CELL_ARRAY_H_ */

View File

@ -160,6 +160,12 @@ class Char_cell_array_character_screen : public Terminal::Character_screen
Terminal::Position cursor_pos() const { return _cursor_pos; }
void cursor_pos(Terminal::Position pos)
{
_cursor_pos.x = Genode::min(_boundary.width - 1, pos.x);
_cursor_pos.y = Genode::min(_boundary.height - 1, pos.y);
}
void output(Terminal::Character c)
{
if (c.ascii() > 0x10) {