mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-23 23:42:32 +00:00
terminal: improve internal structure
This patch reorganizes the terminal's source code to become easier to extend. It also enables the strict warning level.
This commit is contained in:
parent
12c8e51071
commit
96a068f90a
87
repos/gems/src/server/terminal/color_palette.h
Normal file
87
repos/gems/src/server/terminal/color_palette.h
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* \brief Terminal color palette
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2018-02-06
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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 _COLOR_PALETTE_H_
|
||||||
|
#define _COLOR_PALETTE_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <util/color.h>
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
namespace Terminal {
|
||||||
|
class Color_palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Terminal::Color_palette
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
struct Index { unsigned value; };
|
||||||
|
|
||||||
|
struct Highlighted { bool value; };
|
||||||
|
|
||||||
|
struct Inverse { bool value; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum { NUM_COLORS = 16U };
|
||||||
|
|
||||||
|
Color _colors[NUM_COLORS];
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Color_palette()
|
||||||
|
{
|
||||||
|
_colors[0] = Color( 0, 0, 0); /* black */
|
||||||
|
_colors[1] = Color(255, 128, 128); /* red */
|
||||||
|
_colors[2] = Color(128, 255, 128); /* green */
|
||||||
|
_colors[3] = Color(255, 255, 0); /* yellow */
|
||||||
|
_colors[4] = Color(128, 128, 255); /* blue */
|
||||||
|
_colors[5] = Color(255, 0, 255); /* magenta */
|
||||||
|
_colors[6] = Color( 0, 255, 255); /* cyan */
|
||||||
|
_colors[7] = Color(255, 255, 255); /* white */
|
||||||
|
|
||||||
|
/* the upper portion of the palette contains highlight colors */
|
||||||
|
for (unsigned i = 0; i < NUM_COLORS/2; i++) {
|
||||||
|
Color const col = _colors[i];
|
||||||
|
_colors[i + NUM_COLORS/2] = Color((col.r*2)/3, (col.g*2)/3, (col.b*2)/3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Color foreground(Index index, Highlighted highlighted, Inverse inverse) const
|
||||||
|
{
|
||||||
|
if (index.value >= NUM_COLORS/2)
|
||||||
|
return Color(0, 0, 0);
|
||||||
|
|
||||||
|
Color const col =
|
||||||
|
_colors[index.value + (highlighted.value ? NUM_COLORS/2 : 0)];
|
||||||
|
|
||||||
|
return (inverse.value) ? Color(col.r/2, col.g/2, col.b/2) : col;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color background(Index index, Highlighted highlighted, Inverse inverse) const
|
||||||
|
{
|
||||||
|
Color const color =
|
||||||
|
_colors[index.value + (highlighted.value ? NUM_COLORS/2 : 0)];
|
||||||
|
|
||||||
|
return (inverse.value) ? Color((color.r + 255)/2,
|
||||||
|
(color.g + 255)/2,
|
||||||
|
(color.b + 255)/2)
|
||||||
|
: color;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _COLOR_PALETTE_H_ */
|
69
repos/gems/src/server/terminal/draw_glyph.h
Normal file
69
repos/gems/src/server/terminal/draw_glyph.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* \brief Function for drawing the glyphs of terminal characters
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2018-02-06
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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 _DRAW_GLYPH_H_
|
||||||
|
#define _DRAW_GLYPH_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <os/pixel_rgb565.h>
|
||||||
|
|
||||||
|
template <typename PT>
|
||||||
|
inline void draw_glyph(Genode::Color fg_color,
|
||||||
|
Genode::Color bg_color,
|
||||||
|
const unsigned char *glyph_base,
|
||||||
|
unsigned glyph_width,
|
||||||
|
unsigned glyph_img_width,
|
||||||
|
unsigned glyph_img_height,
|
||||||
|
unsigned cell_width,
|
||||||
|
PT *fb_base,
|
||||||
|
unsigned fb_width)
|
||||||
|
{
|
||||||
|
PT fg_pixel(fg_color.r, fg_color.g, fg_color.b);
|
||||||
|
PT bg_pixel(bg_color.r, bg_color.g, bg_color.b);
|
||||||
|
|
||||||
|
unsigned const horizontal_gap = cell_width
|
||||||
|
- Genode::min(glyph_width, cell_width);
|
||||||
|
|
||||||
|
unsigned const left_gap = horizontal_gap / 2;
|
||||||
|
unsigned const right_gap = horizontal_gap - left_gap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear gaps to the left and right of the character if the character's
|
||||||
|
* with is smaller than the cell width.
|
||||||
|
*/
|
||||||
|
if (horizontal_gap) {
|
||||||
|
|
||||||
|
PT *line = fb_base;
|
||||||
|
for (unsigned y = 0 ; y < glyph_img_height; y++, line += fb_width) {
|
||||||
|
|
||||||
|
for (unsigned x = 0; x < left_gap; x++)
|
||||||
|
line[x] = bg_pixel;
|
||||||
|
|
||||||
|
for (unsigned x = cell_width - right_gap; x < cell_width; x++)
|
||||||
|
line[x] = bg_pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* center glyph horizontally within its cell */
|
||||||
|
fb_base += left_gap;
|
||||||
|
|
||||||
|
for (unsigned y = 0 ; y < glyph_img_height; y++) {
|
||||||
|
for (unsigned x = 0; x < glyph_width; x++)
|
||||||
|
fb_base[x] = PT::mix(bg_pixel, fg_pixel, glyph_base[x]);
|
||||||
|
|
||||||
|
fb_base += fb_width;
|
||||||
|
glyph_base += glyph_img_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _DRAW_GLYPH_H_ */
|
47
repos/gems/src/server/terminal/font_family.h
Normal file
47
repos/gems/src/server/terminal/font_family.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* \brief Terminal font handling
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2018-02-06
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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 _FONT_FAMILY_H_
|
||||||
|
#define _FONT_FAMILY_H_
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
namespace Terminal {
|
||||||
|
typedef Text_painter::Font Font;
|
||||||
|
class Font_family;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Terminal::Font_family
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Font const &_regular;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Font_family(Font const ®ular) : _regular(regular) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return font for specified face
|
||||||
|
*
|
||||||
|
* For now, we do not support font faces other than regular.
|
||||||
|
*/
|
||||||
|
Font const &font(Font_face) const { return _regular; }
|
||||||
|
|
||||||
|
unsigned cell_width() const { return _regular.str_w("m"); }
|
||||||
|
unsigned cell_height() const { return _regular.str_h("m"); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _FONT_FAMILY_H_ */
|
80
repos/gems/src/server/terminal/framebuffer.h
Normal file
80
repos/gems/src/server/terminal/framebuffer.h
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* \brief Terminal framebuffer output backend
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2018-02-06
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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 _FRAMEBUFFER_H_
|
||||||
|
#define _FRAMEBUFFER_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <framebuffer_session/connection.h>
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
namespace Terminal { class Framebuffer; }
|
||||||
|
|
||||||
|
class Terminal::Framebuffer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Env &_env;
|
||||||
|
|
||||||
|
::Framebuffer::Connection _fb { _env, ::Framebuffer::Mode() };
|
||||||
|
|
||||||
|
Constructible<Attached_dataspace> _ds { };
|
||||||
|
|
||||||
|
::Framebuffer::Mode _mode { };
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* \param mode_sigh signal handler to be triggered on mode changes
|
||||||
|
*/
|
||||||
|
Framebuffer(Env &env, Signal_context_capability mode_sigh) : _env(env)
|
||||||
|
{
|
||||||
|
switch_to_new_mode();
|
||||||
|
_fb.mode_sigh(mode_sigh);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned w() const { return _mode.width(); }
|
||||||
|
unsigned h() const { return _mode.height(); }
|
||||||
|
|
||||||
|
template <typename PT>
|
||||||
|
PT *pixel() { return _ds->local_addr<PT>(); }
|
||||||
|
|
||||||
|
void refresh(Rect rect)
|
||||||
|
{
|
||||||
|
_fb.refresh(rect.x1(), rect.y1(), rect.w(), rect.h());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the framebuffer mode differs from the current
|
||||||
|
* terminal size.
|
||||||
|
*/
|
||||||
|
bool mode_changed() const
|
||||||
|
{
|
||||||
|
::Framebuffer::Mode _new_mode = _fb.mode();
|
||||||
|
|
||||||
|
return _new_mode.width() != _mode.width()
|
||||||
|
|| _new_mode.height() != _mode.height();
|
||||||
|
}
|
||||||
|
|
||||||
|
void switch_to_new_mode()
|
||||||
|
{
|
||||||
|
_ds.construct(_env.rm(), _fb.dataspace());
|
||||||
|
_mode = _fb.mode();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _FRAMEBUFFER_H_ */
|
@ -18,528 +18,121 @@
|
|||||||
#include <framebuffer_session/connection.h>
|
#include <framebuffer_session/connection.h>
|
||||||
#include <input_session/connection.h>
|
#include <input_session/connection.h>
|
||||||
#include <timer_session/connection.h>
|
#include <timer_session/connection.h>
|
||||||
#include <root/component.h>
|
|
||||||
#include <base/attached_rom_dataspace.h>
|
#include <base/attached_rom_dataspace.h>
|
||||||
#include <base/attached_ram_dataspace.h>
|
#include <base/attached_ram_dataspace.h>
|
||||||
#include <input/event.h>
|
#include <input/event.h>
|
||||||
#include <util/color.h>
|
|
||||||
#include <os/pixel_rgb565.h>
|
|
||||||
|
|
||||||
/* terminal includes */
|
/* terminal includes */
|
||||||
#include <terminal/decoder.h>
|
#include <terminal/decoder.h>
|
||||||
#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/char_cell_array_character_screen.h>
|
|
||||||
#include <terminal_session/terminal_session.h>
|
|
||||||
|
|
||||||
/* nitpicker graphic back end */
|
/* local includes */
|
||||||
#include <nitpicker_gfx/text_painter.h>
|
#include "text_screen_surface.h"
|
||||||
|
#include "session.h"
|
||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal { struct Main; }
|
||||||
using namespace Genode;
|
|
||||||
struct Main;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
using Genode::Pixel_rgb565;
|
struct Terminal::Main : Character_consumer
|
||||||
typedef Text_painter::Font Font;
|
|
||||||
|
|
||||||
|
|
||||||
static bool const verbose = false;
|
|
||||||
|
|
||||||
|
|
||||||
inline Pixel_rgb565 blend(Pixel_rgb565 src, int alpha)
|
|
||||||
{
|
{
|
||||||
Pixel_rgb565 res;
|
|
||||||
res.pixel = ((((alpha >> 3) * (src.pixel & 0xf81f)) >> 5) & 0xf81f)
|
|
||||||
| ((( alpha * (src.pixel & 0x07c0)) >> 8) & 0x07c0);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Pixel_rgb565 mix(Pixel_rgb565 p1, Pixel_rgb565 p2, int alpha)
|
|
||||||
{
|
|
||||||
Pixel_rgb565 res;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We substract the alpha from 264 instead of 255 to
|
* Noncopyable
|
||||||
* compensate the brightness loss caused by the rounding
|
|
||||||
* error of the blend function when having only 5 bits
|
|
||||||
* per channel.
|
|
||||||
*/
|
*/
|
||||||
res.pixel = blend(p1, 264 - alpha).pixel + blend(p2, alpha).pixel;
|
Main(Main const &);
|
||||||
return res;
|
Main &operator = (Main const &);
|
||||||
}
|
|
||||||
|
|
||||||
|
Env &_env;
|
||||||
|
|
||||||
using Genode::Color;
|
Attached_rom_dataspace _config { _env, "config" };
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Font const &_regular;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Font_family(Font const ®ular /* ...to be extended */ )
|
|
||||||
: _regular(regular) { }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return font for specified face
|
* Return font data according to config
|
||||||
*
|
|
||||||
* For now, we do not support font faces other than regular.
|
|
||||||
*/
|
*/
|
||||||
Font const *font(Font_face) const { return &_regular; }
|
static char const *_font_data(Xml_node config);
|
||||||
|
|
||||||
unsigned cell_width() const { return _regular.str_w("m"); }
|
Reconstructible<Font> _font { _font_data(_config.xml()) };
|
||||||
unsigned cell_height() const { return _regular.str_h("m"); }
|
Reconstructible<Font_family> _font_family { *_font };
|
||||||
};
|
|
||||||
|
|
||||||
|
unsigned char *_keymap = Terminal::usenglish_keymap;
|
||||||
|
unsigned char *_shift = Terminal::usenglish_shift;
|
||||||
|
unsigned char *_altgr = nullptr;
|
||||||
|
|
||||||
template <typename PT>
|
Color_palette _color_palette { };
|
||||||
inline void draw_glyph(Color fg_color,
|
|
||||||
Color bg_color,
|
|
||||||
const unsigned char *glyph_base,
|
|
||||||
unsigned glyph_width,
|
|
||||||
unsigned glyph_img_width,
|
|
||||||
unsigned glyph_img_height,
|
|
||||||
unsigned cell_width,
|
|
||||||
PT *fb_base,
|
|
||||||
unsigned fb_width)
|
|
||||||
{
|
|
||||||
PT fg_pixel(fg_color.r, fg_color.g, fg_color.b);
|
|
||||||
PT bg_pixel(bg_color.r, bg_color.g, bg_color.b);
|
|
||||||
|
|
||||||
unsigned const horizontal_gap = cell_width
|
void _handle_config();
|
||||||
- Genode::min(glyph_width, cell_width);
|
|
||||||
|
|
||||||
unsigned const left_gap = horizontal_gap / 2;
|
Signal_handler<Main> _config_handler {
|
||||||
unsigned const right_gap = horizontal_gap - left_gap;
|
_env.ep(), *this, &Main::_handle_config };
|
||||||
|
|
||||||
/*
|
|
||||||
* Clear gaps to the left and right of the character if the character's
|
|
||||||
* with is smaller than the cell width.
|
|
||||||
*/
|
|
||||||
if (horizontal_gap) {
|
|
||||||
|
|
||||||
PT *line = fb_base;
|
|
||||||
for (unsigned y = 0 ; y < glyph_img_height; y++, line += fb_width) {
|
|
||||||
|
|
||||||
for (unsigned x = 0; x < left_gap; x++)
|
|
||||||
line[x] = bg_pixel;
|
|
||||||
|
|
||||||
for (unsigned x = cell_width - right_gap; x < cell_width; x++)
|
|
||||||
line[x] = bg_pixel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* center glyph horizontally within its cell */
|
|
||||||
fb_base += left_gap;
|
|
||||||
|
|
||||||
for (unsigned y = 0 ; y < glyph_img_height; y++) {
|
|
||||||
for (unsigned x = 0; x < glyph_width; x++)
|
|
||||||
fb_base[x] = mix(bg_pixel, fg_pixel, glyph_base[x]);
|
|
||||||
|
|
||||||
fb_base += fb_width;
|
|
||||||
glyph_base += glyph_img_width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <typename PT>
|
|
||||||
static void convert_char_array_to_pixels(Cell_array<Char_cell> *cell_array,
|
|
||||||
PT *fb_base,
|
|
||||||
unsigned fb_width,
|
|
||||||
unsigned fb_height,
|
|
||||||
Font_family const &font_family)
|
|
||||||
{
|
|
||||||
Font const ®ular_font = *font_family.font(Font_face::REGULAR);
|
|
||||||
unsigned glyph_height = regular_font.img_h,
|
|
||||||
glyph_step_x = regular_font.wtab['m'];
|
|
||||||
|
|
||||||
unsigned y = 0;
|
|
||||||
for (unsigned line = 0; line < cell_array->num_lines(); line++) {
|
|
||||||
|
|
||||||
if (cell_array->line_dirty(line)) {
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
Genode::log("convert line ", line);
|
|
||||||
|
|
||||||
unsigned x = 0;
|
|
||||||
for (unsigned column = 0; column < cell_array->num_cols(); column++) {
|
|
||||||
|
|
||||||
Char_cell cell = cell_array->get_cell(column, line);
|
|
||||||
Font const *font = font_family.font(cell.font_face());
|
|
||||||
unsigned char ascii = cell.ascii;
|
|
||||||
|
|
||||||
if (ascii == 0)
|
|
||||||
ascii = ' ';
|
|
||||||
|
|
||||||
unsigned char const *glyph_base = font->img + font->otab[ascii];
|
|
||||||
|
|
||||||
unsigned glyph_width = regular_font.wtab[ascii];
|
|
||||||
|
|
||||||
if (x + glyph_width > fb_width) break;
|
|
||||||
|
|
||||||
Color fg_color = foreground_color(cell);
|
|
||||||
Color bg_color = background_color(cell);
|
|
||||||
|
|
||||||
if (cell.has_cursor()) {
|
|
||||||
fg_color = Color( 63, 63, 63);
|
|
||||||
bg_color = Color(255, 255, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
draw_glyph<PT>(fg_color, bg_color,
|
|
||||||
glyph_base, glyph_width,
|
|
||||||
(unsigned)font->img_w, (unsigned)font->img_h,
|
|
||||||
glyph_step_x, fb_base + x, fb_width);
|
|
||||||
|
|
||||||
x += glyph_step_x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
y += glyph_height;
|
|
||||||
fb_base += fb_width*glyph_height;
|
|
||||||
|
|
||||||
if (y + glyph_height > fb_height) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace Terminal {
|
|
||||||
|
|
||||||
struct Flush_callback : Genode::List<Flush_callback>::Element
|
|
||||||
{
|
|
||||||
virtual void flush() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct Flush_callback_registry
|
|
||||||
{
|
|
||||||
Genode::List<Flush_callback> _list;
|
|
||||||
Genode::Lock _lock;
|
|
||||||
|
|
||||||
void add(Flush_callback *flush_callback)
|
|
||||||
{
|
|
||||||
Genode::Lock::Guard guard(_lock);
|
|
||||||
_list.insert(flush_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove(Flush_callback *flush_callback)
|
|
||||||
{
|
|
||||||
Genode::Lock::Guard guard(_lock);
|
|
||||||
_list.remove(flush_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void flush()
|
|
||||||
{
|
|
||||||
Genode::Lock::Guard guard(_lock);
|
|
||||||
Flush_callback *curr = _list.first();
|
|
||||||
for (; curr; curr = curr->next())
|
|
||||||
curr->flush();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct Trigger_flush_callback
|
|
||||||
{
|
|
||||||
virtual void trigger_flush() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Session_component : public Genode::Rpc_object<Session, Session_component>,
|
|
||||||
public Flush_callback
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Read_buffer &_read_buffer;
|
|
||||||
Framebuffer::Session &_framebuffer;
|
|
||||||
|
|
||||||
Flush_callback_registry &_flush_callback_registry;
|
|
||||||
Trigger_flush_callback &_trigger_flush_callback;
|
|
||||||
Genode::Attached_ram_dataspace _io_buffer;
|
|
||||||
Framebuffer::Mode _fb_mode;
|
|
||||||
Genode::Dataspace_capability _fb_ds_cap;
|
|
||||||
unsigned _char_width;
|
|
||||||
unsigned _char_height;
|
|
||||||
unsigned _columns;
|
|
||||||
unsigned _lines;
|
|
||||||
void *_fb_addr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Protect '_char_cell_array'
|
|
||||||
*/
|
|
||||||
Genode::Lock _lock;
|
|
||||||
|
|
||||||
Cell_array<Char_cell> _char_cell_array;
|
|
||||||
Char_cell_array_character_screen _char_cell_array_character_screen;
|
|
||||||
Terminal::Decoder _decoder;
|
|
||||||
|
|
||||||
Terminal::Position _last_cursor_pos;
|
|
||||||
|
|
||||||
Font_family const &_font_family;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize framebuffer-related attributes
|
|
||||||
*/
|
|
||||||
Genode::Dataspace_capability _init_fb()
|
|
||||||
{
|
|
||||||
if (_fb_mode.format() != Framebuffer::Mode::RGB565) {
|
|
||||||
Genode::error("color mode ", _fb_mode, " not supported");
|
|
||||||
return Genode::Dataspace_capability();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _framebuffer.dataspace();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Session_component(Genode::Env &env,
|
|
||||||
Genode::Allocator &alloc,
|
|
||||||
Read_buffer &read_buffer,
|
|
||||||
Framebuffer::Session &framebuffer,
|
|
||||||
Genode::size_t io_buffer_size,
|
|
||||||
Flush_callback_registry &flush_callback_registry,
|
|
||||||
Trigger_flush_callback &trigger_flush_callback,
|
|
||||||
Font_family const &font_family)
|
|
||||||
:
|
|
||||||
_read_buffer(read_buffer), _framebuffer(framebuffer),
|
|
||||||
_flush_callback_registry(flush_callback_registry),
|
|
||||||
_trigger_flush_callback(trigger_flush_callback),
|
|
||||||
_io_buffer(env.ram(), env.rm(), io_buffer_size),
|
|
||||||
_fb_mode(_framebuffer.mode()),
|
|
||||||
_fb_ds_cap(_init_fb()),
|
|
||||||
|
|
||||||
/* take size of space character as character cell size */
|
|
||||||
_char_width(font_family.cell_width()),
|
|
||||||
_char_height(font_family.cell_height()),
|
|
||||||
|
|
||||||
/* compute number of characters fitting on the framebuffer */
|
|
||||||
_columns(_fb_mode.width()/_char_width),
|
|
||||||
_lines(_fb_mode.height()/_char_height),
|
|
||||||
|
|
||||||
_fb_addr(env.rm().attach(_fb_ds_cap)),
|
|
||||||
_char_cell_array(_columns, _lines, &alloc),
|
|
||||||
_char_cell_array_character_screen(_char_cell_array),
|
|
||||||
_decoder(_char_cell_array_character_screen),
|
|
||||||
|
|
||||||
_font_family(font_family)
|
|
||||||
{
|
|
||||||
using namespace Genode;
|
|
||||||
|
|
||||||
log("new terminal session:");
|
|
||||||
log(" framebuffer has mode ", _fb_mode);
|
|
||||||
log(" character size is ", _char_width, "x", _char_height, " pixels");
|
|
||||||
log(" terminal size is ", _columns, "x", _lines, " characters");
|
|
||||||
|
|
||||||
framebuffer.refresh(0, 0, _fb_mode.width(), _fb_mode.height());
|
|
||||||
|
|
||||||
_flush_callback_registry.add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
~Session_component()
|
|
||||||
{
|
|
||||||
_flush_callback_registry.remove(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void flush()
|
|
||||||
{
|
|
||||||
Genode::Lock::Guard guard(_lock);
|
|
||||||
|
|
||||||
convert_char_array_to_pixels<Pixel_rgb565>(&_char_cell_array,
|
|
||||||
(Pixel_rgb565 *)_fb_addr,
|
|
||||||
_fb_mode.width(),
|
|
||||||
_fb_mode.height(),
|
|
||||||
_font_family);
|
|
||||||
|
|
||||||
|
|
||||||
int first_dirty_line = 10000,
|
|
||||||
last_dirty_line = -10000;
|
|
||||||
|
|
||||||
for (int line = 0; line < (int)_char_cell_array.num_lines(); line++) {
|
|
||||||
if (!_char_cell_array.line_dirty(line)) continue;
|
|
||||||
|
|
||||||
first_dirty_line = Genode::min(line, first_dirty_line);
|
|
||||||
last_dirty_line = Genode::max(line, last_dirty_line);
|
|
||||||
|
|
||||||
_char_cell_array.mark_line_as_clean(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
int num_dirty_lines = last_dirty_line - first_dirty_line + 1;
|
|
||||||
if (num_dirty_lines > 0)
|
|
||||||
_framebuffer.refresh(0, first_dirty_line*_char_height,
|
|
||||||
_fb_mode.width(),
|
|
||||||
num_dirty_lines*_char_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/********************************
|
|
||||||
** Terminal session interface **
|
|
||||||
********************************/
|
|
||||||
|
|
||||||
Size size() { return Size(_columns, _lines); }
|
|
||||||
|
|
||||||
bool avail() { return !_read_buffer.empty(); }
|
|
||||||
|
|
||||||
Genode::size_t _read(Genode::size_t dst_len)
|
|
||||||
{
|
|
||||||
/* read data, block on first byte if needed */
|
|
||||||
unsigned num_bytes = 0;
|
|
||||||
unsigned char *dst = _io_buffer.local_addr<unsigned char>();
|
|
||||||
Genode::size_t dst_size = Genode::min(_io_buffer.size(), dst_len);
|
|
||||||
|
|
||||||
while (!_read_buffer.empty() && num_bytes < dst_size)
|
|
||||||
dst[num_bytes++] = _read_buffer.get();
|
|
||||||
|
|
||||||
return num_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
Genode::size_t _write(Genode::size_t num_bytes)
|
|
||||||
{
|
|
||||||
Genode::Lock::Guard guard(_lock);
|
|
||||||
|
|
||||||
unsigned char *src = _io_buffer.local_addr<unsigned char>();
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < num_bytes; i++) {
|
|
||||||
|
|
||||||
/* submit character to sequence decoder */
|
|
||||||
_decoder.insert(src[i]);
|
|
||||||
}
|
|
||||||
_trigger_flush_callback.trigger_flush();
|
|
||||||
|
|
||||||
return num_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
Genode::Dataspace_capability _dataspace()
|
|
||||||
{
|
|
||||||
return _io_buffer.cap();
|
|
||||||
}
|
|
||||||
|
|
||||||
void connected_sigh(Genode::Signal_context_capability sigh)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Immediately reflect connection-established signal to the
|
|
||||||
* client because the session is ready to use immediately after
|
|
||||||
* creation.
|
|
||||||
*/
|
|
||||||
Genode::Signal_transmitter(sigh).submit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void read_avail_sigh(Genode::Signal_context_capability cap)
|
|
||||||
{
|
|
||||||
_read_buffer.sigh(cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
Genode::size_t read(void *buf, Genode::size_t) { return 0; }
|
|
||||||
Genode::size_t write(void const *buf, Genode::size_t) { return 0; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Root_component : public Genode::Root_component<Session_component>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Genode::Env &_env;
|
|
||||||
Read_buffer &_read_buffer;
|
|
||||||
Framebuffer::Session &_framebuffer;
|
|
||||||
Flush_callback_registry &_flush_callback_registry;
|
|
||||||
Trigger_flush_callback &_trigger_flush_callback;
|
|
||||||
Font_family const &_font_family;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
Session_component *_create_session(const char *args)
|
|
||||||
{
|
|
||||||
Genode::log("create terminal session");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX read I/O buffer size from args
|
|
||||||
*/
|
|
||||||
Genode::size_t io_buffer_size = 4096;
|
|
||||||
|
|
||||||
return new (md_alloc())
|
|
||||||
Session_component(_env, *md_alloc(),
|
|
||||||
_read_buffer,
|
|
||||||
_framebuffer,
|
|
||||||
io_buffer_size,
|
|
||||||
_flush_callback_registry,
|
|
||||||
_trigger_flush_callback,
|
|
||||||
_font_family);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Root_component(Genode::Env &env,
|
|
||||||
Genode::Allocator &md_alloc,
|
|
||||||
Read_buffer &read_buffer,
|
|
||||||
Framebuffer::Session &framebuffer,
|
|
||||||
Flush_callback_registry &flush_callback_registry,
|
|
||||||
Trigger_flush_callback &trigger_flush_callback,
|
|
||||||
Font_family const &font_family)
|
|
||||||
:
|
|
||||||
Genode::Root_component<Session_component>(env.ep(), md_alloc),
|
|
||||||
_env(env),
|
|
||||||
_read_buffer(read_buffer), _framebuffer(framebuffer),
|
|
||||||
_flush_callback_registry(flush_callback_registry),
|
|
||||||
_trigger_flush_callback(trigger_flush_callback),
|
|
||||||
_font_family(font_family)
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct Terminal::Main
|
|
||||||
{
|
|
||||||
Genode::Env &_env;
|
|
||||||
|
|
||||||
Framebuffer::Connection _framebuffer { _env, Framebuffer::Mode() };
|
|
||||||
Input::Connection _input { _env };
|
Input::Connection _input { _env };
|
||||||
Timer::Connection _timer { _env };
|
Timer::Connection _timer { _env };
|
||||||
|
|
||||||
Heap _heap { _env.ram(), _env.rm() };
|
Heap _heap { _env.ram(), _env.rm() };
|
||||||
|
|
||||||
/* input read buffer */
|
Framebuffer _framebuffer { _env, _config_handler };
|
||||||
Read_buffer _read_buffer;
|
|
||||||
|
|
||||||
Terminal::Flush_callback_registry _flush_callback_registry;
|
typedef Pixel_rgb565 PT;
|
||||||
|
|
||||||
|
Constructible<Text_screen_surface<PT>> _text_screen_surface { };
|
||||||
|
|
||||||
|
Session::Size _terminal_size { };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time in milliseconds between a change of the terminal content and the
|
||||||
|
* update of the pixels. By delaying the update, multiple intermediate
|
||||||
|
* changes result in only one rendering step.
|
||||||
|
*/
|
||||||
|
unsigned const _flush_delay = 5;
|
||||||
|
|
||||||
|
bool _flush_scheduled = false;
|
||||||
|
|
||||||
|
void _handle_flush(Duration)
|
||||||
|
{
|
||||||
|
_flush_scheduled = false;
|
||||||
|
|
||||||
|
// XXX distinguish between normal and alternate display
|
||||||
|
if (_text_screen_surface.constructed())
|
||||||
|
_text_screen_surface->redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer::One_shot_timeout<Main> _flush_timeout {
|
||||||
|
_timer, *this, &Main::_handle_flush };
|
||||||
|
|
||||||
|
void _schedule_flush()
|
||||||
|
{
|
||||||
|
if (!_flush_scheduled) {
|
||||||
|
_flush_timeout.schedule(Microseconds{1000*_flush_delay});
|
||||||
|
_flush_scheduled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Character_consumer interface, called from 'Terminal::Session_component'
|
||||||
|
*/
|
||||||
|
void consume_character(Character c) override
|
||||||
|
{
|
||||||
|
// XXX distinguish between normal and alternative display mode (smcup)
|
||||||
|
if (_text_screen_surface.constructed())
|
||||||
|
_text_screen_surface->apply_character(c);
|
||||||
|
|
||||||
|
_schedule_flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* input read buffer */
|
||||||
|
Read_buffer _read_buffer { };
|
||||||
|
|
||||||
/* create root interface for service */
|
/* create root interface for service */
|
||||||
Terminal::Root_component _root;
|
Root_component _root { _env, _heap, _read_buffer, *this, _terminal_size };
|
||||||
|
|
||||||
Terminal::Scancode_tracker _scancode_tracker;
|
/*
|
||||||
|
* builtin keyboard-layout handling
|
||||||
|
*
|
||||||
|
* \deprecated The keyboard layout should be handled by the input-filter
|
||||||
|
* component.
|
||||||
|
*/
|
||||||
|
Constructible<Scancode_tracker> _scancode_tracker { };
|
||||||
|
|
||||||
/* state needed for key-repeat handling */
|
/* state needed for key-repeat handling */
|
||||||
unsigned const _repeat_delay = 250;
|
unsigned const _repeat_delay = 250;
|
||||||
@ -556,53 +149,10 @@ struct Terminal::Main
|
|||||||
Timer::One_shot_timeout<Main> _key_repeat_timeout {
|
Timer::One_shot_timeout<Main> _key_repeat_timeout {
|
||||||
_timer, *this, &Main::_handle_key_repeat };
|
_timer, *this, &Main::_handle_key_repeat };
|
||||||
|
|
||||||
void _handle_flush(Duration);
|
Main(Env &env) : _env(env)
|
||||||
|
|
||||||
/*
|
|
||||||
* Time in milliseconds between a change of the terminal content and the
|
|
||||||
* update of the pixels. By delaying the update, multiple intermediate
|
|
||||||
* changes result in only one rendering step.
|
|
||||||
*/
|
|
||||||
unsigned const _flush_delay = 5;
|
|
||||||
|
|
||||||
bool _flush_scheduled = false;
|
|
||||||
|
|
||||||
void _trigger_flush()
|
|
||||||
{
|
{
|
||||||
if (!_flush_scheduled) {
|
_handle_config();
|
||||||
_flush_timeout.schedule(Microseconds{1000*_flush_delay});
|
|
||||||
_flush_scheduled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Callback invoked if new terminal content appears
|
|
||||||
*/
|
|
||||||
struct Trigger_flush : Trigger_flush_callback
|
|
||||||
{
|
|
||||||
Main &_main;
|
|
||||||
void trigger_flush() override { _main._trigger_flush(); }
|
|
||||||
Trigger_flush(Main &main) : _main(main) { }
|
|
||||||
} _trigger_flush_callback { *this };
|
|
||||||
|
|
||||||
Timer::One_shot_timeout<Main> _flush_timeout {
|
|
||||||
_timer, *this, &Main::_handle_flush };
|
|
||||||
|
|
||||||
Main(Genode::Env &env,
|
|
||||||
Font_family &font_family,
|
|
||||||
unsigned char const *keymap,
|
|
||||||
unsigned char const *shift,
|
|
||||||
unsigned char const *altgr,
|
|
||||||
unsigned char const *control)
|
|
||||||
:
|
|
||||||
_env(env),
|
|
||||||
_root(_env, _heap,
|
|
||||||
_read_buffer, _framebuffer,
|
|
||||||
_flush_callback_registry,
|
|
||||||
_trigger_flush_callback,
|
|
||||||
font_family),
|
|
||||||
_scancode_tracker(keymap, shift, altgr, Terminal::control)
|
|
||||||
{
|
|
||||||
_input.sigh(_input_handler);
|
_input.sigh(_input_handler);
|
||||||
|
|
||||||
/* announce service at our parent */
|
/* announce service at our parent */
|
||||||
@ -611,6 +161,79 @@ struct Terminal::Main
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* built-in fonts */
|
||||||
|
extern char const _binary_notix_8_tff_start;
|
||||||
|
extern char const _binary_terminus_12_tff_start;
|
||||||
|
extern char const _binary_terminus_16_tff_start;
|
||||||
|
|
||||||
|
|
||||||
|
char const *Terminal::Main::_font_data(Xml_node config)
|
||||||
|
{
|
||||||
|
if (config.has_sub_node("font")) {
|
||||||
|
size_t const size = config.sub_node("font").attribute_value("size", 16U);
|
||||||
|
|
||||||
|
switch (size) {
|
||||||
|
case 8: return &_binary_notix_8_tff_start; break;
|
||||||
|
case 12: return &_binary_terminus_12_tff_start; break;
|
||||||
|
case 16: return &_binary_terminus_16_tff_start; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &_binary_terminus_16_tff_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Terminal::Main::_handle_config()
|
||||||
|
{
|
||||||
|
_config.update();
|
||||||
|
|
||||||
|
_font_family.destruct();
|
||||||
|
_font.destruct();
|
||||||
|
|
||||||
|
Xml_node const config = _config.xml();
|
||||||
|
|
||||||
|
_font.construct(_font_data(config));
|
||||||
|
_font_family.construct(*_font);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adapt terminal to framebuffer mode changes
|
||||||
|
*/
|
||||||
|
if (_framebuffer.mode_changed() || !_text_screen_surface.constructed()) {
|
||||||
|
_framebuffer.switch_to_new_mode();
|
||||||
|
_text_screen_surface.construct(_heap, *_font_family,
|
||||||
|
_color_palette, _framebuffer);
|
||||||
|
_terminal_size = _text_screen_surface->size();
|
||||||
|
_schedule_flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read keyboard layout from config file
|
||||||
|
*/
|
||||||
|
|
||||||
|
_keymap = Terminal::usenglish_keymap;
|
||||||
|
_shift = Terminal::usenglish_shift;
|
||||||
|
_altgr = nullptr;
|
||||||
|
|
||||||
|
if (config.has_sub_node("keyboard")) {
|
||||||
|
|
||||||
|
if (config.sub_node("keyboard").attribute("layout").has_value("de")) {
|
||||||
|
_keymap = Terminal::german_keymap;
|
||||||
|
_shift = Terminal::german_shift;
|
||||||
|
_altgr = Terminal::german_altgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.sub_node("keyboard").attribute("layout").has_value("none")) {
|
||||||
|
_keymap = nullptr;
|
||||||
|
_shift = nullptr;
|
||||||
|
_altgr = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_scancode_tracker.constructed())
|
||||||
|
_scancode_tracker.construct(_keymap, _shift, _altgr, Terminal::control);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Terminal::Main::_handle_input()
|
void Terminal::Main::_handle_input()
|
||||||
{
|
{
|
||||||
_input.for_each_event([&] (Input::Event const &event) {
|
_input.for_each_event([&] (Input::Event const &event) {
|
||||||
@ -623,15 +246,19 @@ void Terminal::Main::_handle_input()
|
|||||||
if (utf8.b3) _read_buffer.add(utf8.b3);
|
if (utf8.b3) _read_buffer.add(utf8.b3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* apply the terminal's built-in character map if configured */
|
||||||
|
if (!_scancode_tracker.constructed())
|
||||||
|
return;
|
||||||
|
|
||||||
bool press = (event.type() == Input::Event::PRESS ? true : false);
|
bool press = (event.type() == Input::Event::PRESS ? true : false);
|
||||||
bool release = (event.type() == Input::Event::RELEASE ? true : false);
|
bool release = (event.type() == Input::Event::RELEASE ? true : false);
|
||||||
int keycode = event.code();
|
int keycode = event.code();
|
||||||
|
|
||||||
if (press || release)
|
if (press || release)
|
||||||
_scancode_tracker.submit(keycode, press);
|
_scancode_tracker->submit(keycode, press);
|
||||||
|
|
||||||
if (press) {
|
if (press) {
|
||||||
_scancode_tracker.emit_current_character(_read_buffer);
|
_scancode_tracker->emit_current_character(_read_buffer);
|
||||||
|
|
||||||
/* setup first key repeat */
|
/* setup first key repeat */
|
||||||
_repeat_next = _repeat_delay;
|
_repeat_next = _repeat_delay;
|
||||||
@ -651,7 +278,8 @@ void Terminal::Main::_handle_key_repeat(Duration)
|
|||||||
if (_repeat_next) {
|
if (_repeat_next) {
|
||||||
|
|
||||||
/* repeat current character or sequence */
|
/* repeat current character or sequence */
|
||||||
_scancode_tracker.emit_current_character(_read_buffer);
|
if (_scancode_tracker.constructed())
|
||||||
|
_scancode_tracker->emit_current_character(_read_buffer);
|
||||||
|
|
||||||
_repeat_next = _repeat_rate;
|
_repeat_next = _repeat_rate;
|
||||||
}
|
}
|
||||||
@ -660,89 +288,4 @@ void Terminal::Main::_handle_key_repeat(Duration)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Terminal::Main::_handle_flush(Duration)
|
void Component::construct(Genode::Env &env) { static Terminal::Main main(env); }
|
||||||
{
|
|
||||||
_flush_scheduled = false;
|
|
||||||
_flush_callback_registry.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* built-in fonts */
|
|
||||||
extern char _binary_notix_8_tff_start;
|
|
||||||
extern char _binary_terminus_12_tff_start;
|
|
||||||
extern char _binary_terminus_16_tff_start;
|
|
||||||
|
|
||||||
|
|
||||||
void Component::construct(Genode::Env &env)
|
|
||||||
{
|
|
||||||
/* XXX execute constructors of global statics */
|
|
||||||
env.exec_static_constructors();
|
|
||||||
|
|
||||||
using namespace Genode;
|
|
||||||
|
|
||||||
Attached_rom_dataspace config(env, "config");
|
|
||||||
|
|
||||||
/* initialize color palette */
|
|
||||||
color_palette[0] = Color( 0, 0, 0); /* black */
|
|
||||||
color_palette[1] = Color(255, 128, 128); /* red */
|
|
||||||
color_palette[2] = Color(128, 255, 128); /* green */
|
|
||||||
color_palette[3] = Color(255, 255, 0); /* yellow */
|
|
||||||
color_palette[4] = Color(128, 128, 255); /* blue */
|
|
||||||
color_palette[5] = Color(255, 0, 255); /* magenta */
|
|
||||||
color_palette[6] = Color( 0, 255, 255); /* cyan */
|
|
||||||
color_palette[7] = Color(255, 255, 255); /* white */
|
|
||||||
|
|
||||||
/* the upper portion of the palette contains highlight colors */
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
Color col = color_palette[i];
|
|
||||||
col = Color((col.r*2)/3, (col.g*2)/3, (col.b*2)/3);
|
|
||||||
color_palette[i + 8] = col;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pick font according to config file */
|
|
||||||
char const *font_data = &_binary_terminus_16_tff_start;
|
|
||||||
try {
|
|
||||||
size_t font_size = 16;
|
|
||||||
config.xml().sub_node("font").attribute("size").value(&font_size);
|
|
||||||
|
|
||||||
switch (font_size) {
|
|
||||||
case 8: font_data = &_binary_notix_8_tff_start; break;
|
|
||||||
case 12: font_data = &_binary_terminus_12_tff_start; break;
|
|
||||||
case 16: font_data = &_binary_terminus_16_tff_start; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
} catch (...) { }
|
|
||||||
|
|
||||||
static Font font(font_data);
|
|
||||||
static Font_family font_family(font);
|
|
||||||
|
|
||||||
log("cell size is ", (int)font_family.cell_width(),
|
|
||||||
"x", (int)font_family.cell_height());
|
|
||||||
|
|
||||||
unsigned char *keymap = Terminal::usenglish_keymap;
|
|
||||||
unsigned char *shift = Terminal::usenglish_shift;
|
|
||||||
unsigned char *altgr = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read keyboard layout from config file
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
if (config.xml().sub_node("keyboard")
|
|
||||||
.attribute("layout").has_value("de")) {
|
|
||||||
keymap = Terminal::german_keymap;
|
|
||||||
shift = Terminal::german_shift;
|
|
||||||
altgr = Terminal::german_altgr;
|
|
||||||
}
|
|
||||||
} catch (...) { }
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (config.xml().sub_node("keyboard")
|
|
||||||
.attribute("layout").has_value("none")) {
|
|
||||||
keymap = nullptr;
|
|
||||||
shift = nullptr;
|
|
||||||
altgr = nullptr;
|
|
||||||
}
|
|
||||||
} catch (...) { }
|
|
||||||
|
|
||||||
static Terminal::Main main(env, font_family, keymap, shift, altgr, Terminal::control);
|
|
||||||
}
|
|
||||||
|
157
repos/gems/src/server/terminal/session.h
Normal file
157
repos/gems/src/server/terminal/session.h
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* \brief Terminal session interface
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2018-02-06
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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 _SESSION_H_
|
||||||
|
#define _SESSION_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <root/component.h>
|
||||||
|
#include <terminal_session/terminal_session.h>
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
namespace Terminal {
|
||||||
|
class Session_component;
|
||||||
|
class Root_component;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Terminal::Session_component : public Rpc_object<Session, Session_component>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Read_buffer &_read_buffer;
|
||||||
|
Character_consumer &_character_consumer;
|
||||||
|
Size const &_terminal_size;
|
||||||
|
Attached_ram_dataspace _io_buffer;
|
||||||
|
|
||||||
|
Terminal::Position _last_cursor_pos { };
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
Session_component(Env &env,
|
||||||
|
Read_buffer &read_buffer,
|
||||||
|
Character_consumer &character_consumer,
|
||||||
|
Size const &terminal_size,
|
||||||
|
size_t io_buffer_size)
|
||||||
|
:
|
||||||
|
_read_buffer(read_buffer),
|
||||||
|
_character_consumer(character_consumer),
|
||||||
|
_terminal_size(terminal_size),
|
||||||
|
_io_buffer(env.ram(), env.rm(), io_buffer_size)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
/********************************
|
||||||
|
** Terminal session interface **
|
||||||
|
********************************/
|
||||||
|
|
||||||
|
Size size() override { return _terminal_size; }
|
||||||
|
|
||||||
|
bool avail() override { return !_read_buffer.empty(); }
|
||||||
|
|
||||||
|
size_t _read(size_t dst_len)
|
||||||
|
{
|
||||||
|
/* read data, block on first byte if needed */
|
||||||
|
unsigned num_bytes = 0;
|
||||||
|
unsigned char *dst = _io_buffer.local_addr<unsigned char>();
|
||||||
|
size_t dst_size = min(_io_buffer.size(), dst_len);
|
||||||
|
|
||||||
|
while (!_read_buffer.empty() && num_bytes < dst_size)
|
||||||
|
dst[num_bytes++] = _read_buffer.get();
|
||||||
|
|
||||||
|
return num_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t _write(size_t num_bytes)
|
||||||
|
{
|
||||||
|
unsigned char *src = _io_buffer.local_addr<unsigned char>();
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < num_bytes; i++)
|
||||||
|
_character_consumer.consume_character(src[i]);
|
||||||
|
|
||||||
|
return num_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dataspace_capability _dataspace() { return _io_buffer.cap(); }
|
||||||
|
|
||||||
|
void connected_sigh(Signal_context_capability sigh) override
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Immediately reflect connection-established signal to the
|
||||||
|
* client because the session is ready to use immediately after
|
||||||
|
* creation.
|
||||||
|
*/
|
||||||
|
Signal_transmitter(sigh).submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_avail_sigh(Signal_context_capability cap) override
|
||||||
|
{
|
||||||
|
_read_buffer.sigh(cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t read(void *, size_t) override { return 0; }
|
||||||
|
size_t write(void const *, size_t) override { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Terminal::Root_component : public Genode::Root_component<Session_component>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Env &_env;
|
||||||
|
Read_buffer &_read_buffer;
|
||||||
|
Character_consumer &_character_consumer;
|
||||||
|
Session::Size &_terminal_size;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Session_component *_create_session(const char *)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* XXX read I/O buffer size from args
|
||||||
|
*/
|
||||||
|
size_t io_buffer_size = 4096;
|
||||||
|
|
||||||
|
return new (md_alloc())
|
||||||
|
Session_component(_env,
|
||||||
|
_read_buffer,
|
||||||
|
_character_consumer,
|
||||||
|
_terminal_size,
|
||||||
|
io_buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
Root_component(Env &env,
|
||||||
|
Allocator &md_alloc,
|
||||||
|
Read_buffer &read_buffer,
|
||||||
|
Character_consumer &character_consumer,
|
||||||
|
Session::Size &terminal_size)
|
||||||
|
:
|
||||||
|
Genode::Root_component<Session_component>(env.ep(), md_alloc),
|
||||||
|
_env(env),
|
||||||
|
_read_buffer(read_buffer),
|
||||||
|
_character_consumer(character_consumer),
|
||||||
|
_terminal_size(terminal_size)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _SESSION_H_ */
|
@ -2,5 +2,3 @@ TARGET = terminal
|
|||||||
SRC_CC = main.cc
|
SRC_CC = main.cc
|
||||||
LIBS = base
|
LIBS = base
|
||||||
SRC_BIN = $(notdir $(wildcard $(PRG_DIR)/*.tff))
|
SRC_BIN = $(notdir $(wildcard $(PRG_DIR)/*.tff))
|
||||||
|
|
||||||
CC_CXX_WARN_STRICT =
|
|
||||||
|
160
repos/gems/src/server/terminal/text_screen_surface.h
Normal file
160
repos/gems/src/server/terminal/text_screen_surface.h
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* \brief Terminal graphics backend for textual screen
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2018-02-06
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2018 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 _TEXT_SCREEN_SURFACE_H_
|
||||||
|
#define _TEXT_SCREEN_SURFACE_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <os/pixel_rgb565.h>
|
||||||
|
|
||||||
|
/* terminal includes */
|
||||||
|
#include <terminal/char_cell_array_character_screen.h>
|
||||||
|
|
||||||
|
/* nitpicker graphic back end */
|
||||||
|
#include <nitpicker_gfx/text_painter.h>
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include "font_family.h"
|
||||||
|
#include "draw_glyph.h"
|
||||||
|
#include "color_palette.h"
|
||||||
|
#include "framebuffer.h"
|
||||||
|
|
||||||
|
namespace Terminal { template <typename> class Text_screen_surface; }
|
||||||
|
|
||||||
|
|
||||||
|
template <typename PT>
|
||||||
|
class Terminal::Text_screen_surface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Font_family const &_font_family;
|
||||||
|
Color_palette const &_palette;
|
||||||
|
Framebuffer &_framebuffer;
|
||||||
|
|
||||||
|
/* take size of space character as character cell size */
|
||||||
|
unsigned const _char_width { _font_family.cell_width() };
|
||||||
|
unsigned const _char_height { _font_family.cell_height() };
|
||||||
|
|
||||||
|
/* number of characters fitting on the framebuffer */
|
||||||
|
unsigned const _columns { _framebuffer.w()/_char_width };
|
||||||
|
unsigned const _lines { _framebuffer.h()/_char_height };
|
||||||
|
|
||||||
|
Cell_array<Char_cell> _cell_array;
|
||||||
|
Char_cell_array_character_screen _character_screen { _cell_array };
|
||||||
|
|
||||||
|
Decoder _decoder { _character_screen };
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Text_screen_surface(Allocator &alloc, Font_family const &font_family,
|
||||||
|
Color_palette &palette, Framebuffer &framebuffer)
|
||||||
|
:
|
||||||
|
_font_family(font_family),
|
||||||
|
_palette(palette),
|
||||||
|
_framebuffer(framebuffer),
|
||||||
|
_cell_array(_columns, _lines, alloc)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void redraw()
|
||||||
|
{
|
||||||
|
Font const ®ular_font = _font_family.font(Font_face::REGULAR);
|
||||||
|
|
||||||
|
unsigned const glyph_height = regular_font.img_h,
|
||||||
|
glyph_step_x = regular_font.wtab['m'];
|
||||||
|
|
||||||
|
unsigned const fb_width = _framebuffer.w(),
|
||||||
|
fb_height = _framebuffer.h();
|
||||||
|
|
||||||
|
PT *fb_base = _framebuffer.pixel<PT>();
|
||||||
|
|
||||||
|
unsigned y = 0;
|
||||||
|
for (unsigned line = 0; line < _cell_array.num_lines(); line++) {
|
||||||
|
|
||||||
|
if (_cell_array.line_dirty(line)) {
|
||||||
|
|
||||||
|
unsigned x = 0;
|
||||||
|
for (unsigned column = 0; column < _cell_array.num_cols(); column++) {
|
||||||
|
|
||||||
|
Char_cell cell = _cell_array.get_cell(column, line);
|
||||||
|
Font const &font = _font_family.font(cell.font_face());
|
||||||
|
unsigned char ascii = cell.ascii;
|
||||||
|
|
||||||
|
if (ascii == 0)
|
||||||
|
ascii = ' ';
|
||||||
|
|
||||||
|
unsigned char const *glyph_base = font.img + font.otab[ascii];
|
||||||
|
|
||||||
|
unsigned glyph_width = regular_font.wtab[ascii];
|
||||||
|
|
||||||
|
if (x + glyph_width > fb_width)
|
||||||
|
break;
|
||||||
|
|
||||||
|
Color_palette::Highlighted const highlighted { cell.highlight() };
|
||||||
|
Color_palette::Inverse const inverse { cell.inverse() };
|
||||||
|
|
||||||
|
Color fg_color =
|
||||||
|
_palette.foreground(Color_palette::Index{cell.colidx_fg()},
|
||||||
|
highlighted, inverse);
|
||||||
|
|
||||||
|
Color bg_color =
|
||||||
|
_palette.background(Color_palette::Index{cell.colidx_bg()},
|
||||||
|
highlighted, inverse);
|
||||||
|
|
||||||
|
if (cell.has_cursor()) {
|
||||||
|
fg_color = Color( 63, 63, 63);
|
||||||
|
bg_color = Color(255, 255, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_glyph<PT>(fg_color, bg_color,
|
||||||
|
glyph_base, glyph_width,
|
||||||
|
(unsigned)font.img_w, (unsigned)font.img_h,
|
||||||
|
glyph_step_x, fb_base + x, fb_width);
|
||||||
|
|
||||||
|
x += glyph_step_x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
y += glyph_height;
|
||||||
|
fb_base += fb_width*glyph_height;
|
||||||
|
|
||||||
|
if (y + glyph_height > fb_height) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int first_dirty_line = 10000,
|
||||||
|
last_dirty_line = -10000;
|
||||||
|
|
||||||
|
for (int line = 0; line < (int)_cell_array.num_lines(); line++) {
|
||||||
|
if (!_cell_array.line_dirty(line)) continue;
|
||||||
|
|
||||||
|
first_dirty_line = min(line, first_dirty_line);
|
||||||
|
last_dirty_line = max(line, last_dirty_line);
|
||||||
|
|
||||||
|
_cell_array.mark_line_as_clean(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
int const num_dirty_lines = last_dirty_line - first_dirty_line + 1;
|
||||||
|
if (num_dirty_lines > 0)
|
||||||
|
_framebuffer.refresh(Rect(Point(0, first_dirty_line*_char_height),
|
||||||
|
Area(fb_width,
|
||||||
|
num_dirty_lines*_char_height)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_character(Character c)
|
||||||
|
{
|
||||||
|
/* submit character to sequence decoder */
|
||||||
|
_decoder.insert(c.c);
|
||||||
|
}
|
||||||
|
|
||||||
|
Session::Size size() const { return Session::Size(_columns, _lines); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _TEXT_SCREEN_SURFACE_H_ */
|
41
repos/gems/src/server/terminal/types.h
Normal file
41
repos/gems/src/server/terminal/types.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* \brief Common types used by the terminal
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2018-02-06
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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 _TYPES_H_
|
||||||
|
#define _TYPES_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <util/interface.h>
|
||||||
|
#include <util/list.h>
|
||||||
|
#include <base/registry.h>
|
||||||
|
#include <os/surface.h>
|
||||||
|
#include <terminal_session/terminal_session.h>
|
||||||
|
|
||||||
|
/* terminal includes */
|
||||||
|
#include <terminal/types.h>
|
||||||
|
|
||||||
|
namespace Terminal {
|
||||||
|
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
typedef Surface_base::Rect Rect;
|
||||||
|
typedef Surface_base::Area Area;
|
||||||
|
typedef Surface_base::Point Point;
|
||||||
|
|
||||||
|
struct Character_consumer : Interface
|
||||||
|
{
|
||||||
|
virtual void consume_character(Character c) = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _TYPES_H_ */
|
@ -220,7 +220,7 @@ class Terminal::Session_component : public Genode::Rpc_object<Session, Session_c
|
|||||||
_label(label),
|
_label(label),
|
||||||
_session_manager(session_manager),
|
_session_manager(session_manager),
|
||||||
_io_buffer(_env.ram(), _env.rm(), io_buffer_size),
|
_io_buffer(_env.ram(), _env.rm(), io_buffer_size),
|
||||||
_char_cell_array(ncurses.columns(), ncurses.lines() - 1, &heap),
|
_char_cell_array(ncurses.columns(), ncurses.lines() - 1, heap),
|
||||||
_char_cell_array_character_screen(_char_cell_array),
|
_char_cell_array_character_screen(_char_cell_array),
|
||||||
_decoder(_char_cell_array_character_screen)
|
_decoder(_char_cell_array_character_screen)
|
||||||
{
|
{
|
||||||
|
@ -30,11 +30,17 @@ class Cell_array
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Noncopyable
|
||||||
|
*/
|
||||||
|
Cell_array(Cell_array const &);
|
||||||
|
Cell_array &operator = (Cell_array const &);
|
||||||
|
|
||||||
unsigned _num_cols;
|
unsigned _num_cols;
|
||||||
unsigned _num_lines;
|
unsigned _num_lines;
|
||||||
Genode::Allocator *_alloc;
|
Genode::Allocator &_alloc;
|
||||||
CELL **_array;
|
CELL **_array = nullptr;
|
||||||
bool *_line_dirty;
|
bool *_line_dirty = nullptr;
|
||||||
|
|
||||||
typedef CELL *Char_cell_line;
|
typedef CELL *Char_cell_line;
|
||||||
|
|
||||||
@ -73,7 +79,7 @@ class Cell_array
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
Cell_array(unsigned num_cols, unsigned num_lines,
|
Cell_array(unsigned num_cols, unsigned num_lines,
|
||||||
Genode::Allocator *alloc)
|
Genode::Allocator &alloc)
|
||||||
:
|
:
|
||||||
_num_cols(num_cols),
|
_num_cols(num_cols),
|
||||||
_num_lines(num_lines),
|
_num_lines(num_lines),
|
||||||
|
@ -24,10 +24,10 @@ struct Char_cell
|
|||||||
unsigned char ascii;
|
unsigned char ascii;
|
||||||
unsigned char color;
|
unsigned char color;
|
||||||
|
|
||||||
enum { ATTR_COLIDX_MASK = 0x07,
|
enum { ATTR_COLIDX_MASK = 0x07U,
|
||||||
ATTR_CURSOR = 0x10,
|
ATTR_CURSOR = 0x10U,
|
||||||
ATTR_INVERSE = 0x20,
|
ATTR_INVERSE = 0x20U,
|
||||||
ATTR_HIGHLIGHT = 0x40 };
|
ATTR_HIGHLIGHT = 0x40U };
|
||||||
|
|
||||||
enum { COLOR_MASK = 0x3f }; /* 111111 */
|
enum { COLOR_MASK = 0x3f }; /* 111111 */
|
||||||
|
|
||||||
@ -47,8 +47,8 @@ struct Char_cell
|
|||||||
return Font_face((Font_face::Type)(attr & Font_face::attr_mask()));
|
return Font_face((Font_face::Type)(attr & Font_face::attr_mask()));
|
||||||
}
|
}
|
||||||
|
|
||||||
int colidx_fg() const { return color & ATTR_COLIDX_MASK; }
|
unsigned colidx_fg() const { return color & ATTR_COLIDX_MASK; }
|
||||||
int colidx_bg() const { return (color >> 3) & ATTR_COLIDX_MASK; }
|
unsigned colidx_bg() const { return (color >> 3) & ATTR_COLIDX_MASK; }
|
||||||
bool inverse() const { return attr & ATTR_INVERSE; }
|
bool inverse() const { return attr & ATTR_INVERSE; }
|
||||||
bool highlight() const { return attr & ATTR_HIGHLIGHT; }
|
bool highlight() const { return attr & ATTR_HIGHLIGHT; }
|
||||||
|
|
||||||
@ -69,7 +69,8 @@ class Char_cell_array_character_screen : public Terminal::Character_screen
|
|||||||
|
|
||||||
Cell_array<Char_cell> &_char_cell_array;
|
Cell_array<Char_cell> &_char_cell_array;
|
||||||
Terminal::Boundary _boundary;
|
Terminal::Boundary _boundary;
|
||||||
Terminal::Position _cursor_pos;
|
Terminal::Position _cursor_pos { };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Color index contains the fg color in the first 3 bits
|
* Color index contains the fg color in the first 3 bits
|
||||||
* and the bg color in the second 3 bits (0bbbbfff).
|
* and the bg color in the second 3 bits (0bbbbfff).
|
||||||
|
@ -22,7 +22,7 @@ namespace Terminal { struct Character_screen; }
|
|||||||
/**
|
/**
|
||||||
* Character-screen interface called by input-stream decoder
|
* Character-screen interface called by input-stream decoder
|
||||||
*/
|
*/
|
||||||
struct Terminal::Character_screen
|
struct Terminal::Character_screen : Genode::Interface
|
||||||
{
|
{
|
||||||
virtual void output(Character c) = 0;
|
virtual void output(Character c) = 0;
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ class Terminal::Decoder
|
|||||||
return (index <= _index) ? _entries[index] : Invalid_entry();
|
return (index <= _index) ? _entries[index] : Invalid_entry();
|
||||||
}
|
}
|
||||||
|
|
||||||
} _escape_stack;
|
} _escape_stack { };
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
STATE_IDLE,
|
STATE_IDLE,
|
||||||
|
@ -30,54 +30,14 @@ class Terminal::Read_buffer : public Genode::Ring_buffer<unsigned char, READ_BUF
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Genode::Signal_context_capability _sigh_cap;
|
Genode::Signal_context_capability _sigh_cap { };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register signal handler for read-avail signals
|
* Register signal handler for read-avail signals
|
||||||
*/
|
*/
|
||||||
void sigh(Genode::Signal_context_capability cap)
|
void sigh(Genode::Signal_context_capability cap) { _sigh_cap = cap; }
|
||||||
{
|
|
||||||
_sigh_cap = cap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add element into read buffer and emit signal
|
|
||||||
*/
|
|
||||||
void add(unsigned char c)
|
|
||||||
{
|
|
||||||
Genode::Ring_buffer<unsigned char, READ_BUFFER_SIZE>::add(c);
|
|
||||||
|
|
||||||
if (_sigh_cap.valid())
|
|
||||||
Genode::Signal_transmitter(_sigh_cap).submit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void add(char const *str)
|
|
||||||
{
|
|
||||||
while (*str)
|
|
||||||
add(*str++);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
enum { READ_BUFFER_SIZE = 4096 };
|
|
||||||
|
|
||||||
class Read_buffer : public Genode::Ring_buffer<unsigned char, READ_BUFFER_SIZE>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Genode::Signal_context_capability _sigh_cap;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register signal handler for read-avail signals
|
|
||||||
*/
|
|
||||||
void sigh(Genode::Signal_context_capability cap)
|
|
||||||
{
|
|
||||||
_sigh_cap = cap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add element into read buffer and emit signal
|
* Add element into read buffer and emit signal
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
#ifndef _TERMINAL__TYPES_H_
|
#ifndef _TERMINAL__TYPES_H_
|
||||||
#define _TERMINAL__TYPES_H_
|
#define _TERMINAL__TYPES_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <util/interface.h>
|
||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal {
|
||||||
|
|
||||||
struct Character;
|
struct Character;
|
||||||
@ -84,7 +87,7 @@ struct Terminal::Position
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Terminal::Character_array
|
struct Terminal::Character_array : Genode::Interface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Assign character to specified position
|
* Assign character to specified position
|
||||||
|
Loading…
Reference in New Issue
Block a user