diff --git a/repos/gems/src/server/terminal/main.cc b/repos/gems/src/server/terminal/main.cc index 84147764ec..cfe3206207 100644 --- a/repos/gems/src/server/terminal/main.cc +++ b/repos/gems/src/server/terminal/main.cc @@ -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::Snapshot Snapshot; + Constructible 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 { diff --git a/repos/gems/src/server/terminal/text_screen_surface.h b/repos/gems/src/server/terminal/text_screen_surface.h index 56ae95ab95..950f087b55 100644 --- a/repos/gems/src/server/terminal/text_screen_surface.h +++ b/repos/gems/src/server/terminal/text_screen_surface.h @@ -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 _cell_array; + + public: + + static size_t bytes_needed(Text_screen_surface const &surface) + { + return Cell_array::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(); @@ -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 */ diff --git a/repos/os/include/terminal/cell_array.h b/repos/os/include/terminal/cell_array.h index 3f7e212d21..e2ae60b908 100644 --- a/repos/os/include/terminal/cell_array.h +++ b/repos/os/include/terminal/cell_array.h @@ -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_ */ diff --git a/repos/os/include/terminal/char_cell_array_character_screen.h b/repos/os/include/terminal/char_cell_array_character_screen.h index 1fc06bc162..fc616c5b5b 100644 --- a/repos/os/include/terminal/char_cell_array_character_screen.h +++ b/repos/os/include/terminal/char_cell_array_character_screen.h @@ -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) {