/* * \brief Array of character cells * \author Norman Feske * \date 2011-06-06 */ /* * Copyright (C) 2011-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ #ifndef _TERMINAL__CELL_ARRAY_H_ #define _TERMINAL__CELL_ARRAY_H_ /* Genode includes */ #include /** * \param CELL type of a single character cell that contains the information * about the glyph and its attributes * * The 'CELL' type must have a default constructor and has to provide the * methods 'set_cursor()' and 'clear_cursor'. */ template class Cell_array { private: /* * Noncopyable */ Cell_array(Cell_array const &); Cell_array &operator = (Cell_array const &); unsigned _num_cols; unsigned _num_lines; Genode::Allocator &_alloc; CELL **_array = nullptr; bool *_line_dirty = nullptr; typedef CELL *Char_cell_line; void _clear_line(Char_cell_line line) { for (unsigned col = 0; col < _num_cols; col++) *line++ = CELL(); } void _mark_lines_as_dirty(int start, int end) { for (int line = start; line <= end; line++) _line_dirty[line] = true; } void _scroll_vertically(int start, int end, bool up) { /* rotate lines of the scroll region */ Char_cell_line yanked_line = _array[up ? start : end]; if (up) { for (int line = start; line <= end - 1; line++) _array[line] = _array[line + 1]; } else { for (int line = end; line >= start + 1; line--) _array[line] = _array[line - 1]; } _clear_line(yanked_line); _array[up ? end: start] = yanked_line; _mark_lines_as_dirty(start, end); } public: Cell_array(unsigned num_cols, unsigned num_lines, Genode::Allocator &alloc) : _num_cols(num_cols), _num_lines(num_lines), _alloc(alloc) { _array = new (alloc) Char_cell_line[num_lines]; _line_dirty = new (alloc) bool[num_lines]; mark_all_lines_as_dirty(); for (unsigned i = 0; i < num_lines; i++) _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++) Genode::destroy(_alloc, _array[i]); Genode::destroy(_alloc, _line_dirty); Genode::destroy(_alloc, _array); } void mark_all_lines_as_dirty() { for (unsigned i = 0; i < _num_lines; i++) _line_dirty[i] = true; } void set_cell(int column, int line, CELL cell) { _array[line][column] = cell; _line_dirty[line] = true; } 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) { _line_dirty[line] = false; } void mark_line_as_dirty(int line) { _line_dirty[line] = true; } void scroll_up(int region_start, int region_end) { _scroll_vertically(region_start, region_end, true); } void scroll_down(int region_start, int region_end) { _scroll_vertically(region_start, region_end, false); } void clear(int region_start, int region_end) { for (int line = region_start; line <= region_end; line++) _clear_line(_array[line]); _mark_lines_as_dirty(region_start, region_end); } void cursor(Terminal::Position pos, bool enable, bool mark_dirty = false) { if (((unsigned)pos.x >= _num_cols) || ((unsigned)pos.y >= _num_lines)) return; CELL &cell = _array[pos.y][pos.x]; if (enable) cell.set_cursor(); else cell.clear_cursor(); if (mark_dirty) _line_dirty[pos.y] = true; } unsigned num_cols() const { return _num_cols; } unsigned num_lines() const { return _num_lines; } }; #endif /* _TERMINAL__CELL_ARRAY_H_ */