mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 16:35:28 +00:00
terminal: Generalize character-screen code
This patch moves the further reusable parts of the terminal into public header files. It also slightly tweaks the color table to give all colors a similar brightness level.
This commit is contained in:
parent
438b8be2fa
commit
d1c2a7126a
389
gems/include/terminal/char_cell_array_character_screen.h
Normal file
389
gems/include/terminal/char_cell_array_character_screen.h
Normal file
@ -0,0 +1,389 @@
|
|||||||
|
/*
|
||||||
|
* \brief Char-cell-array-based implementation of a character screen
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2013-01-20
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TERMINAL__CHAR_CELL_ARRAY_CHARACTER_SCREEN_H_
|
||||||
|
#define _TERMINAL__CHAR_CELL_ARRAY_CHARACTER_SCREEN_H_
|
||||||
|
|
||||||
|
/* terminal includes */
|
||||||
|
#include <terminal/cell_array.h>
|
||||||
|
#include <terminal/font_face.h>
|
||||||
|
|
||||||
|
struct Char_cell
|
||||||
|
{
|
||||||
|
unsigned char attr;
|
||||||
|
unsigned char ascii;
|
||||||
|
unsigned char color;
|
||||||
|
|
||||||
|
enum { ATTR_COLIDX_MASK = 0x07,
|
||||||
|
ATTR_CURSOR = 0x10,
|
||||||
|
ATTR_INVERSE = 0x20,
|
||||||
|
ATTR_HIGHLIGHT = 0x40 };
|
||||||
|
|
||||||
|
enum { COLOR_MASK = 0x3f }; /* 111111 */
|
||||||
|
|
||||||
|
Char_cell() : attr(0), ascii(0), color(0) { }
|
||||||
|
|
||||||
|
Char_cell(unsigned char c, Font_face f,
|
||||||
|
int colidx, bool inv, bool highlight)
|
||||||
|
:
|
||||||
|
attr(f.attr_bits() | (inv ? ATTR_INVERSE : 0)
|
||||||
|
| (highlight ? ATTR_HIGHLIGHT : 0)),
|
||||||
|
ascii(c),
|
||||||
|
color(colidx & COLOR_MASK)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Font_face font_face() const
|
||||||
|
{
|
||||||
|
return Font_face((Font_face::Type)(attr & Font_face::attr_mask()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int colidx_fg() const { return color & ATTR_COLIDX_MASK; }
|
||||||
|
int colidx_bg() const { return (color >> 3) & ATTR_COLIDX_MASK; }
|
||||||
|
bool inverse() const { return attr & ATTR_INVERSE; }
|
||||||
|
bool highlight() const { return attr & ATTR_HIGHLIGHT; }
|
||||||
|
|
||||||
|
void set_cursor() { attr |= ATTR_CURSOR; }
|
||||||
|
void clear_cursor() { attr &= ~ATTR_CURSOR; }
|
||||||
|
|
||||||
|
bool has_cursor() const { return attr & ATTR_CURSOR; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Char_cell_array_character_screen : public Terminal::Character_screen
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum Cursor_visibility { CURSOR_INVISIBLE,
|
||||||
|
CURSOR_VISIBLE,
|
||||||
|
CURSOR_VERY_VISIBLE };
|
||||||
|
|
||||||
|
Cell_array<Char_cell> &_char_cell_array;
|
||||||
|
Terminal::Boundary _boundary;
|
||||||
|
Terminal::Position _cursor_pos;
|
||||||
|
/**
|
||||||
|
* Color index contains the fg color in the first 3 bits
|
||||||
|
* and the bg color in the second 3 bits (0bbbbfff).
|
||||||
|
*/
|
||||||
|
int _color_index;
|
||||||
|
bool _inverse;
|
||||||
|
bool _highlight;
|
||||||
|
Cursor_visibility _cursor_visibility;
|
||||||
|
int _region_start;
|
||||||
|
int _region_end;
|
||||||
|
int _tab_size;
|
||||||
|
|
||||||
|
enum { DEFAULT_COLOR_INDEX_BG = 0, DEFAULT_COLOR_INDEX = 7, DEFAULT_TAB_SIZE = 8 };
|
||||||
|
|
||||||
|
struct Cursor_guard
|
||||||
|
{
|
||||||
|
Char_cell_array_character_screen &cs;
|
||||||
|
|
||||||
|
Terminal::Position old_cursor_pos;
|
||||||
|
|
||||||
|
Cursor_guard(Char_cell_array_character_screen &cs)
|
||||||
|
:
|
||||||
|
cs(cs), old_cursor_pos(cs._cursor_pos)
|
||||||
|
{
|
||||||
|
/* temporarily remove cursor */
|
||||||
|
cs._char_cell_array.cursor(old_cursor_pos, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Cursor_guard()
|
||||||
|
{
|
||||||
|
/* restore original cursor */
|
||||||
|
cs._char_cell_array.cursor(old_cursor_pos, true);
|
||||||
|
|
||||||
|
/* if cursor position changed, move cursor */
|
||||||
|
Terminal::Position &new_cursor_pos = cs._cursor_pos;
|
||||||
|
if (old_cursor_pos != new_cursor_pos) {
|
||||||
|
|
||||||
|
cs._char_cell_array.cursor(old_cursor_pos, false, true);
|
||||||
|
cs._char_cell_array.cursor(new_cursor_pos, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Char_cell_array_character_screen(Cell_array<Char_cell> &char_cell_array)
|
||||||
|
:
|
||||||
|
_char_cell_array(char_cell_array),
|
||||||
|
_boundary(_char_cell_array.num_cols(), _char_cell_array.num_lines()),
|
||||||
|
_color_index(DEFAULT_COLOR_INDEX),
|
||||||
|
_inverse(false),
|
||||||
|
_highlight(false),
|
||||||
|
_cursor_visibility(CURSOR_VISIBLE),
|
||||||
|
_region_start(0),
|
||||||
|
_region_end(_boundary.height - 1),
|
||||||
|
_tab_size(DEFAULT_TAB_SIZE)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
void _line_feed()
|
||||||
|
{
|
||||||
|
Cursor_guard guard(*this);
|
||||||
|
|
||||||
|
_cursor_pos.y++;
|
||||||
|
|
||||||
|
if (_cursor_pos.y > _region_end) {
|
||||||
|
_char_cell_array.scroll_up(_region_start, _region_end);
|
||||||
|
_cursor_pos.y = _region_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _carriage_return()
|
||||||
|
{
|
||||||
|
Cursor_guard guard(*this);
|
||||||
|
|
||||||
|
_cursor_pos.x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************
|
||||||
|
** Character_screen interface **
|
||||||
|
********************************/
|
||||||
|
|
||||||
|
Terminal::Position cursor_pos() const { return _cursor_pos; }
|
||||||
|
|
||||||
|
void output(Terminal::Character c)
|
||||||
|
{
|
||||||
|
if (c.ascii() > 0x10) {
|
||||||
|
Cursor_guard guard(*this);
|
||||||
|
_char_cell_array.set_cell(_cursor_pos.x, _cursor_pos.y,
|
||||||
|
Char_cell(c.ascii(), Font_face::REGULAR,
|
||||||
|
_color_index, _inverse, _highlight));
|
||||||
|
_cursor_pos.x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (c.ascii()) {
|
||||||
|
|
||||||
|
case '\r': /* 13 */
|
||||||
|
_carriage_return();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\n': /* 10 */
|
||||||
|
_line_feed();
|
||||||
|
_carriage_return();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8: /* backspace */
|
||||||
|
{
|
||||||
|
Cursor_guard guard(*this);
|
||||||
|
|
||||||
|
if (_cursor_pos.x > 0)
|
||||||
|
_cursor_pos.x--;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 9: /* tab */
|
||||||
|
{
|
||||||
|
Cursor_guard guard(*this);
|
||||||
|
_cursor_pos.x += _tab_size - (_cursor_pos.x % _tab_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cursor_pos.x >= _boundary.width) {
|
||||||
|
_carriage_return();
|
||||||
|
_line_feed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void civis()
|
||||||
|
{
|
||||||
|
_cursor_visibility = CURSOR_INVISIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cnorm()
|
||||||
|
{
|
||||||
|
_cursor_visibility = CURSOR_VISIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cvvis()
|
||||||
|
{
|
||||||
|
_cursor_visibility = CURSOR_VERY_VISIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpr()
|
||||||
|
{
|
||||||
|
PDBG("not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
void csr(int start, int end)
|
||||||
|
{
|
||||||
|
/* the arguments are specified use coordinate origin (1, 1) */
|
||||||
|
start--;
|
||||||
|
end--;
|
||||||
|
|
||||||
|
_region_start = Genode::max(start, 0);
|
||||||
|
_region_end = Genode::min(end, _boundary.height - 1);
|
||||||
|
|
||||||
|
/* preserve invariant of region size >= 0 */
|
||||||
|
_region_end = Genode::max(_region_end, _region_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cuf(int dx)
|
||||||
|
{
|
||||||
|
Cursor_guard guard(*this);
|
||||||
|
|
||||||
|
_cursor_pos.x += dx;
|
||||||
|
_cursor_pos.x = Genode::min(_boundary.width - 1, _cursor_pos.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cup(int y, int x)
|
||||||
|
{
|
||||||
|
Cursor_guard guard(*this);
|
||||||
|
|
||||||
|
/* top-left cursor position is reported as (1, 1) */
|
||||||
|
x--;
|
||||||
|
y--;
|
||||||
|
|
||||||
|
using namespace Genode;
|
||||||
|
x = max(0, min(x, _boundary.width - 1));
|
||||||
|
y = max(0, min(y, _boundary.height - 1));
|
||||||
|
|
||||||
|
_cursor_pos = Terminal::Position(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cuu1() { PWRN("not implemented"); }
|
||||||
|
void dch(int) { PDBG("not implemented"); }
|
||||||
|
|
||||||
|
void dl(int num_lines)
|
||||||
|
{
|
||||||
|
/* delete number of lines */
|
||||||
|
for (int i = 0; i < num_lines; i++)
|
||||||
|
_char_cell_array.scroll_up(_cursor_pos.y, _region_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ech(int v)
|
||||||
|
{
|
||||||
|
Cursor_guard guard(*this);
|
||||||
|
|
||||||
|
for (int i = 0; i < v; i++, _cursor_pos.x++)
|
||||||
|
_char_cell_array.set_cell(_cursor_pos.x, _cursor_pos.y,
|
||||||
|
Char_cell(' ', Font_face::REGULAR,
|
||||||
|
_color_index, _inverse, _highlight));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ed()
|
||||||
|
{
|
||||||
|
/* clear to end of screen */
|
||||||
|
_char_cell_array.clear(_cursor_pos.y, _boundary.height - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void el()
|
||||||
|
{
|
||||||
|
/* clear to end of line */
|
||||||
|
for (int x = _cursor_pos.x; x < _boundary.width; x++)
|
||||||
|
_char_cell_array.set_cell(x, _cursor_pos.y, Char_cell());
|
||||||
|
}
|
||||||
|
|
||||||
|
void el1() { PDBG("not implemented"); }
|
||||||
|
|
||||||
|
void home()
|
||||||
|
{
|
||||||
|
Cursor_guard guard(*this);
|
||||||
|
|
||||||
|
_cursor_pos = Terminal::Position(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hpa(int x)
|
||||||
|
{
|
||||||
|
Cursor_guard guard(*this);
|
||||||
|
|
||||||
|
_cursor_pos.x = x;
|
||||||
|
_cursor_pos.x = Genode::min(_boundary.width - 1, _cursor_pos.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hts() { PDBG("not implemented"); }
|
||||||
|
void ich(int) { PDBG("not implemented"); }
|
||||||
|
|
||||||
|
void il(int value)
|
||||||
|
{
|
||||||
|
Cursor_guard guard(*this);
|
||||||
|
|
||||||
|
if (_cursor_pos.y > _region_end)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_char_cell_array.cursor(_cursor_pos, false);
|
||||||
|
|
||||||
|
for (int i = 0; i < value; i++)
|
||||||
|
_char_cell_array.scroll_down(_cursor_pos.y, _region_end);
|
||||||
|
|
||||||
|
_char_cell_array.cursor(_cursor_pos, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc() { PDBG("not implemented"); }
|
||||||
|
|
||||||
|
void op()
|
||||||
|
{
|
||||||
|
_color_index = DEFAULT_COLOR_INDEX | (DEFAULT_COLOR_INDEX_BG << 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rc() { PDBG("not implemented"); }
|
||||||
|
void ri() { PDBG("not implemented"); }
|
||||||
|
void ris() { PDBG("not implemented"); }
|
||||||
|
void rmam() { PDBG("not implemented"); }
|
||||||
|
void rmir() { PDBG("not implemented"); }
|
||||||
|
|
||||||
|
void setab(int value)
|
||||||
|
{
|
||||||
|
//_inverse = (value != 0);
|
||||||
|
_color_index &= ~0x38; /* clear 111000 */
|
||||||
|
_color_index |= (((value == 9) ? DEFAULT_COLOR_INDEX_BG : value) << 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setaf(int value)
|
||||||
|
{
|
||||||
|
_color_index &= ~0x7; /* clear 000111 */
|
||||||
|
_color_index |= (value == 9) ? DEFAULT_COLOR_INDEX : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sgr(int value)
|
||||||
|
{
|
||||||
|
_highlight = (value & 0x1) != 0;
|
||||||
|
_inverse = (value & 0x2) != 0;
|
||||||
|
|
||||||
|
/* sgr 0 is the command to reset all attributes, including color */
|
||||||
|
if (value == 0)
|
||||||
|
_color_index = DEFAULT_COLOR_INDEX | (DEFAULT_COLOR_INDEX_BG << 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sgr0()
|
||||||
|
{
|
||||||
|
sgr(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sc() { PDBG("not implemented"); }
|
||||||
|
void smam() { PDBG("not implemented"); }
|
||||||
|
void smir() { PDBG("not implemented"); }
|
||||||
|
void tbc() { PDBG("not implemented"); }
|
||||||
|
void u6(int, int) { PDBG("not implemented"); }
|
||||||
|
void u7() { PDBG("not implemented"); }
|
||||||
|
void u8() { PDBG("not implemented"); }
|
||||||
|
void u9() { PDBG("not implemented"); }
|
||||||
|
|
||||||
|
void vpa(int y)
|
||||||
|
{
|
||||||
|
Cursor_guard guard(*this);
|
||||||
|
|
||||||
|
_cursor_pos.y = y;
|
||||||
|
_cursor_pos.y = Genode::min(_boundary.height - 1, _cursor_pos.y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _TERMINAL__CHAR_CELL_ARRAY_CHARACTER_SCREEN_H_ */
|
36
gems/include/terminal/font_face.h
Normal file
36
gems/include/terminal/font_face.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* \brief Interface for font styles
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2013-01-20
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TERMINAL__FONT_FACE_H_
|
||||||
|
#define _TERMINAL__FONT_FACE_H_
|
||||||
|
|
||||||
|
class Font_face
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Type { REGULAR, ITALIC, BOLD, BOLD_ITALIC };
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Type _type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Font_face(Type type) : _type(type) { }
|
||||||
|
|
||||||
|
static unsigned char attr_mask() { return 3; }
|
||||||
|
|
||||||
|
unsigned char attr_bits() const { return _type & attr_mask(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _TERMINAL__FONT_FACE_H_ */
|
@ -29,7 +29,7 @@
|
|||||||
#include <terminal/types.h>
|
#include <terminal/types.h>
|
||||||
#include <terminal/scancode_tracker.h>
|
#include <terminal/scancode_tracker.h>
|
||||||
#include <terminal/keymaps.h>
|
#include <terminal/keymaps.h>
|
||||||
#include <terminal/cell_array.h>
|
#include <terminal/char_cell_array_character_screen.h>
|
||||||
#include <terminal_session/terminal_session.h>
|
#include <terminal_session/terminal_session.h>
|
||||||
|
|
||||||
/* nitpicker graphic back end */
|
/* nitpicker graphic back end */
|
||||||
@ -68,6 +68,28 @@ inline Pixel_rgb565 mix(Pixel_rgb565 p1, Pixel_rgb565 p2, int alpha)
|
|||||||
static Color color_palette[2*8];
|
static Color color_palette[2*8];
|
||||||
|
|
||||||
|
|
||||||
|
static Color foreground_color(Char_cell const &cell)
|
||||||
|
{
|
||||||
|
Color col = color_palette[cell.colidx_fg() + (cell.highlight() ? 8 : 0)];
|
||||||
|
|
||||||
|
if (cell.inverse())
|
||||||
|
col = Color(col.r/2, col.g/2, col.b/2);
|
||||||
|
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Color background_color(Char_cell const &cell)
|
||||||
|
{
|
||||||
|
Color col = color_palette[cell.colidx_bg() + (cell.highlight() ? 8 : 0)];
|
||||||
|
|
||||||
|
if (cell.inverse())
|
||||||
|
return Color((col.r + 255)/2, (col.g + 255)/2, (col.b + 255)/2);
|
||||||
|
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Font_family
|
class Font_family
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@ -76,8 +98,6 @@ class Font_family
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum Face { REGULAR, ITALIC, BOLD, BOLD_ITALIC };
|
|
||||||
|
|
||||||
Font_family(Font const ®ular /* ...to be extended */ )
|
Font_family(Font const ®ular /* ...to be extended */ )
|
||||||
: _regular(regular) { }
|
: _regular(regular) { }
|
||||||
|
|
||||||
@ -86,399 +106,13 @@ class Font_family
|
|||||||
*
|
*
|
||||||
* For now, we do not support font faces other than regular.
|
* For now, we do not support font faces other than regular.
|
||||||
*/
|
*/
|
||||||
Font const *font(Face) const { return &_regular; }
|
Font const *font(Font_face) const { return &_regular; }
|
||||||
|
|
||||||
unsigned cell_width() const { return _regular.str_w("m"); }
|
unsigned cell_width() const { return _regular.str_w("m"); }
|
||||||
unsigned cell_height() const { return _regular.str_h("m"); }
|
unsigned cell_height() const { return _regular.str_h("m"); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Char_cell
|
|
||||||
{
|
|
||||||
unsigned char attr;
|
|
||||||
unsigned char ascii;
|
|
||||||
unsigned char color;
|
|
||||||
|
|
||||||
enum { ATTR_COLIDX_MASK = 0x07,
|
|
||||||
ATTR_CURSOR = 0x10,
|
|
||||||
ATTR_INVERSE = 0x20,
|
|
||||||
ATTR_HIGHLIGHT = 0x40 };
|
|
||||||
|
|
||||||
enum { COLOR_MASK = 0x3f }; /* 111111 */
|
|
||||||
|
|
||||||
Char_cell() : attr(0), ascii(0), color(0) { }
|
|
||||||
|
|
||||||
Char_cell(unsigned char c, Font_family::Face f,
|
|
||||||
int colidx, bool inv, bool highlight)
|
|
||||||
:
|
|
||||||
attr(f | (inv ? ATTR_INVERSE : 0)
|
|
||||||
| (highlight ? ATTR_HIGHLIGHT : 0)),
|
|
||||||
ascii(c),
|
|
||||||
color(colidx & COLOR_MASK)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
Font_family::Face font_face() const { return (Font_family::Face)(attr & 0x3); }
|
|
||||||
|
|
||||||
int colidx_fg() const { return color & ATTR_COLIDX_MASK; }
|
|
||||||
int colidx_bg() const { return (color >> 3) & ATTR_COLIDX_MASK; }
|
|
||||||
bool inverse() const { return attr & ATTR_INVERSE; }
|
|
||||||
bool highlight() const { return attr & ATTR_HIGHLIGHT; }
|
|
||||||
|
|
||||||
Color fg_color() const
|
|
||||||
{
|
|
||||||
Color col = color_palette[colidx_fg() + (highlight() ? 8 : 0)];
|
|
||||||
|
|
||||||
if (inverse())
|
|
||||||
col = Color(col.r/2, col.g/2, col.b/2);
|
|
||||||
|
|
||||||
return col;
|
|
||||||
}
|
|
||||||
|
|
||||||
Color bg_color() const
|
|
||||||
{
|
|
||||||
Color col = color_palette[colidx_bg() + (highlight() ? 8 : 0)];
|
|
||||||
|
|
||||||
if (inverse())
|
|
||||||
return Color((col.r + 255)/2, (col.g + 255)/2, (col.b + 255)/2);
|
|
||||||
|
|
||||||
return col;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_cursor() { attr |= ATTR_CURSOR; }
|
|
||||||
void clear_cursor() { attr &= ~ATTR_CURSOR; }
|
|
||||||
|
|
||||||
bool has_cursor() const { return attr & ATTR_CURSOR; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Char_cell_array_character_screen : public Terminal::Character_screen
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
enum Cursor_visibility { CURSOR_INVISIBLE,
|
|
||||||
CURSOR_VISIBLE,
|
|
||||||
CURSOR_VERY_VISIBLE };
|
|
||||||
|
|
||||||
Cell_array<Char_cell> &_char_cell_array;
|
|
||||||
Terminal::Boundary _boundary;
|
|
||||||
Terminal::Position _cursor_pos;
|
|
||||||
/**
|
|
||||||
* Color index contains the fg color in the first 3 bits
|
|
||||||
* and the bg color in the second 3 bits (0bbbbfff).
|
|
||||||
*/
|
|
||||||
int _color_index;
|
|
||||||
bool _inverse;
|
|
||||||
bool _highlight;
|
|
||||||
Cursor_visibility _cursor_visibility;
|
|
||||||
int _region_start;
|
|
||||||
int _region_end;
|
|
||||||
int _tab_size;
|
|
||||||
|
|
||||||
enum { DEFAULT_COLOR_INDEX_BG = 0, DEFAULT_COLOR_INDEX = 7, DEFAULT_TAB_SIZE = 8 };
|
|
||||||
|
|
||||||
struct Cursor_guard
|
|
||||||
{
|
|
||||||
Char_cell_array_character_screen &cs;
|
|
||||||
|
|
||||||
Terminal::Position old_cursor_pos;
|
|
||||||
|
|
||||||
Cursor_guard(Char_cell_array_character_screen &cs)
|
|
||||||
:
|
|
||||||
cs(cs), old_cursor_pos(cs._cursor_pos)
|
|
||||||
{
|
|
||||||
/* temporarily remove cursor */
|
|
||||||
cs._char_cell_array.cursor(old_cursor_pos, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
~Cursor_guard()
|
|
||||||
{
|
|
||||||
/* restore original cursor */
|
|
||||||
cs._char_cell_array.cursor(old_cursor_pos, true);
|
|
||||||
|
|
||||||
/* if cursor position changed, move cursor */
|
|
||||||
Terminal::Position &new_cursor_pos = cs._cursor_pos;
|
|
||||||
if (old_cursor_pos != new_cursor_pos) {
|
|
||||||
|
|
||||||
cs._char_cell_array.cursor(old_cursor_pos, false, true);
|
|
||||||
cs._char_cell_array.cursor(new_cursor_pos, true, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Char_cell_array_character_screen(Cell_array<Char_cell> &char_cell_array)
|
|
||||||
:
|
|
||||||
_char_cell_array(char_cell_array),
|
|
||||||
_boundary(_char_cell_array.num_cols(), _char_cell_array.num_lines()),
|
|
||||||
_color_index(DEFAULT_COLOR_INDEX),
|
|
||||||
_inverse(false),
|
|
||||||
_highlight(false),
|
|
||||||
_cursor_visibility(CURSOR_VISIBLE),
|
|
||||||
_region_start(0),
|
|
||||||
_region_end(_boundary.height - 1),
|
|
||||||
_tab_size(DEFAULT_TAB_SIZE)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
|
|
||||||
void _line_feed()
|
|
||||||
{
|
|
||||||
Cursor_guard guard(*this);
|
|
||||||
|
|
||||||
_cursor_pos.y++;
|
|
||||||
|
|
||||||
if (_cursor_pos.y > _region_end) {
|
|
||||||
_char_cell_array.scroll_up(_region_start, _region_end);
|
|
||||||
_cursor_pos.y = _region_end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _carriage_return()
|
|
||||||
{
|
|
||||||
Cursor_guard guard(*this);
|
|
||||||
|
|
||||||
_cursor_pos.x = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/********************************
|
|
||||||
** Character_screen interface **
|
|
||||||
********************************/
|
|
||||||
|
|
||||||
Terminal::Position cursor_pos() const { return _cursor_pos; }
|
|
||||||
|
|
||||||
void output(Terminal::Character c)
|
|
||||||
{
|
|
||||||
if (c.ascii() > 0x10) {
|
|
||||||
Cursor_guard guard(*this);
|
|
||||||
_char_cell_array.set_cell(_cursor_pos.x, _cursor_pos.y,
|
|
||||||
Char_cell(c.ascii(), Font_family::REGULAR,
|
|
||||||
_color_index, _inverse, _highlight));
|
|
||||||
_cursor_pos.x++;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (c.ascii()) {
|
|
||||||
|
|
||||||
case '\r': /* 13 */
|
|
||||||
_carriage_return();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\n': /* 10 */
|
|
||||||
_line_feed();
|
|
||||||
_carriage_return();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 8: /* backspace */
|
|
||||||
{
|
|
||||||
Cursor_guard guard(*this);
|
|
||||||
|
|
||||||
if (_cursor_pos.x > 0)
|
|
||||||
_cursor_pos.x--;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 9: /* tab */
|
|
||||||
{
|
|
||||||
Cursor_guard guard(*this);
|
|
||||||
_cursor_pos.x += _tab_size - (_cursor_pos.x % _tab_size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_cursor_pos.x >= _boundary.width) {
|
|
||||||
_carriage_return();
|
|
||||||
_line_feed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void civis()
|
|
||||||
{
|
|
||||||
_cursor_visibility = CURSOR_INVISIBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cnorm()
|
|
||||||
{
|
|
||||||
_cursor_visibility = CURSOR_VISIBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cvvis()
|
|
||||||
{
|
|
||||||
_cursor_visibility = CURSOR_VERY_VISIBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpr()
|
|
||||||
{
|
|
||||||
PDBG("not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
void csr(int start, int end)
|
|
||||||
{
|
|
||||||
/* the arguments are specified use coordinate origin (1, 1) */
|
|
||||||
start--;
|
|
||||||
end--;
|
|
||||||
|
|
||||||
_region_start = Genode::max(start, 0);
|
|
||||||
_region_end = Genode::min(end, _boundary.height - 1);
|
|
||||||
|
|
||||||
/* preserve invariant of region size >= 0 */
|
|
||||||
_region_end = Genode::max(_region_end, _region_start);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cuf(int dx)
|
|
||||||
{
|
|
||||||
Cursor_guard guard(*this);
|
|
||||||
|
|
||||||
_cursor_pos.x += dx;
|
|
||||||
_cursor_pos.x = Genode::min(_boundary.width - 1, _cursor_pos.x);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cup(int y, int x)
|
|
||||||
{
|
|
||||||
Cursor_guard guard(*this);
|
|
||||||
|
|
||||||
/* top-left cursor position is reported as (1, 1) */
|
|
||||||
x--;
|
|
||||||
y--;
|
|
||||||
|
|
||||||
using namespace Genode;
|
|
||||||
x = max(0, min(x, _boundary.width - 1));
|
|
||||||
y = max(0, min(y, _boundary.height - 1));
|
|
||||||
|
|
||||||
_cursor_pos = Terminal::Position(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cuu1() { PWRN("not implemented"); }
|
|
||||||
void dch(int) { PDBG("not implemented"); }
|
|
||||||
|
|
||||||
void dl(int num_lines)
|
|
||||||
{
|
|
||||||
/* delete number of lines */
|
|
||||||
for (int i = 0; i < num_lines; i++)
|
|
||||||
_char_cell_array.scroll_up(_cursor_pos.y, _region_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ech(int v)
|
|
||||||
{
|
|
||||||
Cursor_guard guard(*this);
|
|
||||||
|
|
||||||
for (int i = 0; i < v; i++, _cursor_pos.x++)
|
|
||||||
_char_cell_array.set_cell(_cursor_pos.x, _cursor_pos.y,
|
|
||||||
Char_cell(' ', Font_family::REGULAR,
|
|
||||||
_color_index, _inverse, _highlight));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ed()
|
|
||||||
{
|
|
||||||
/* clear to end of screen */
|
|
||||||
_char_cell_array.clear(_cursor_pos.y, _boundary.height - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void el()
|
|
||||||
{
|
|
||||||
/* clear to end of line */
|
|
||||||
for (int x = _cursor_pos.x; x < _boundary.width; x++)
|
|
||||||
_char_cell_array.set_cell(x, _cursor_pos.y, Char_cell());
|
|
||||||
}
|
|
||||||
|
|
||||||
void el1() { PDBG("not implemented"); }
|
|
||||||
|
|
||||||
void home()
|
|
||||||
{
|
|
||||||
Cursor_guard guard(*this);
|
|
||||||
|
|
||||||
_cursor_pos = Terminal::Position(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hpa(int x)
|
|
||||||
{
|
|
||||||
Cursor_guard guard(*this);
|
|
||||||
|
|
||||||
_cursor_pos.x = x;
|
|
||||||
_cursor_pos.x = Genode::min(_boundary.width - 1, _cursor_pos.x);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hts() { PDBG("not implemented"); }
|
|
||||||
void ich(int) { PDBG("not implemented"); }
|
|
||||||
|
|
||||||
void il(int value)
|
|
||||||
{
|
|
||||||
Cursor_guard guard(*this);
|
|
||||||
|
|
||||||
if (_cursor_pos.y > _region_end)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_char_cell_array.cursor(_cursor_pos, false);
|
|
||||||
|
|
||||||
for (int i = 0; i < value; i++)
|
|
||||||
_char_cell_array.scroll_down(_cursor_pos.y, _region_end);
|
|
||||||
|
|
||||||
_char_cell_array.cursor(_cursor_pos, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void oc() { PDBG("not implemented"); }
|
|
||||||
|
|
||||||
void op()
|
|
||||||
{
|
|
||||||
_color_index = DEFAULT_COLOR_INDEX | (DEFAULT_COLOR_INDEX_BG << 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rc() { PDBG("not implemented"); }
|
|
||||||
void ri() { PDBG("not implemented"); }
|
|
||||||
void ris() { PDBG("not implemented"); }
|
|
||||||
void rmam() { PDBG("not implemented"); }
|
|
||||||
void rmir() { PDBG("not implemented"); }
|
|
||||||
|
|
||||||
void setab(int value)
|
|
||||||
{
|
|
||||||
//_inverse = (value != 0);
|
|
||||||
_color_index &= ~0x38; /* clear 111000 */
|
|
||||||
_color_index |= (((value == 9) ? DEFAULT_COLOR_INDEX_BG : value) << 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setaf(int value)
|
|
||||||
{
|
|
||||||
_color_index &= ~0x7; /* clear 000111 */
|
|
||||||
_color_index |= (value == 9) ? DEFAULT_COLOR_INDEX : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sgr(int value)
|
|
||||||
{
|
|
||||||
_highlight = (value & 0x1) != 0;
|
|
||||||
_inverse = (value & 0x2) != 0;
|
|
||||||
|
|
||||||
/* sgr 0 is the command to reset all attributes, including color */
|
|
||||||
if (value == 0)
|
|
||||||
_color_index = DEFAULT_COLOR_INDEX | (DEFAULT_COLOR_INDEX_BG << 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sgr0()
|
|
||||||
{
|
|
||||||
sgr(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sc() { PDBG("not implemented"); }
|
|
||||||
void smam() { PDBG("not implemented"); }
|
|
||||||
void smir() { PDBG("not implemented"); }
|
|
||||||
void tbc() { PDBG("not implemented"); }
|
|
||||||
void u6(int, int) { PDBG("not implemented"); }
|
|
||||||
void u7() { PDBG("not implemented"); }
|
|
||||||
void u8() { PDBG("not implemented"); }
|
|
||||||
void u9() { PDBG("not implemented"); }
|
|
||||||
|
|
||||||
void vpa(int y)
|
|
||||||
{
|
|
||||||
Cursor_guard guard(*this);
|
|
||||||
|
|
||||||
_cursor_pos.y = y;
|
|
||||||
_cursor_pos.y = Genode::min(_boundary.height - 1, _cursor_pos.y);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template <typename PT>
|
template <typename PT>
|
||||||
inline void draw_glyph(Color fg_color,
|
inline void draw_glyph(Color fg_color,
|
||||||
Color bg_color,
|
Color bg_color,
|
||||||
@ -536,7 +170,7 @@ static void convert_char_array_to_pixels(Cell_array<Char_cell> *cell_array,
|
|||||||
unsigned fb_height,
|
unsigned fb_height,
|
||||||
Font_family const &font_family)
|
Font_family const &font_family)
|
||||||
{
|
{
|
||||||
Font const ®ular_font = *font_family.font(Font_family::REGULAR);
|
Font const ®ular_font = *font_family.font(Font_face::REGULAR);
|
||||||
unsigned glyph_height = regular_font.img_h,
|
unsigned glyph_height = regular_font.img_h,
|
||||||
glyph_step_x = regular_font.wtab['m'];
|
glyph_step_x = regular_font.wtab['m'];
|
||||||
|
|
||||||
@ -564,8 +198,8 @@ static void convert_char_array_to_pixels(Cell_array<Char_cell> *cell_array,
|
|||||||
|
|
||||||
if (x + glyph_width >= fb_width) break;
|
if (x + glyph_width >= fb_width) break;
|
||||||
|
|
||||||
Color fg_color = cell.fg_color();
|
Color fg_color = foreground_color(cell);
|
||||||
Color bg_color = cell.bg_color();
|
Color bg_color = background_color(cell);
|
||||||
|
|
||||||
if (cell.has_cursor()) {
|
if (cell.has_cursor()) {
|
||||||
fg_color = Color( 63, 63, 63);
|
fg_color = Color( 63, 63, 63);
|
||||||
@ -887,10 +521,10 @@ int main(int, char **)
|
|||||||
|
|
||||||
/* initialize color palette */
|
/* initialize color palette */
|
||||||
color_palette[0] = Color( 0, 0, 0); /* black */
|
color_palette[0] = Color( 0, 0, 0); /* black */
|
||||||
color_palette[1] = Color(255, 0, 0); /* red */
|
color_palette[1] = Color(255, 128, 128); /* red */
|
||||||
color_palette[2] = Color( 0, 255, 0); /* green */
|
color_palette[2] = Color(128, 255, 128); /* green */
|
||||||
color_palette[3] = Color(255, 255, 0); /* yellow */
|
color_palette[3] = Color(255, 255, 0); /* yellow */
|
||||||
color_palette[4] = Color( 0, 0, 255); /* blue */
|
color_palette[4] = Color(128, 128, 255); /* blue */
|
||||||
color_palette[5] = Color(255, 0, 255); /* magenta */
|
color_palette[5] = Color(255, 0, 255); /* magenta */
|
||||||
color_palette[6] = Color( 0, 255, 255); /* cyan */
|
color_palette[6] = Color( 0, 255, 255); /* cyan */
|
||||||
color_palette[7] = Color(255, 255, 255); /* white */
|
color_palette[7] = Color(255, 255, 255); /* white */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user