2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* \brief Terminal service
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2011-08-11
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2011-2013 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <base/env.h>
|
|
|
|
#include <base/printf.h>
|
|
|
|
#include <base/heap.h>
|
|
|
|
#include <framebuffer_session/connection.h>
|
|
|
|
#include <input_session/connection.h>
|
|
|
|
#include <timer_session/connection.h>
|
|
|
|
#include <cap_session/connection.h>
|
|
|
|
#include <root/component.h>
|
|
|
|
#include <os/attached_ram_dataspace.h>
|
|
|
|
#include <input/event.h>
|
|
|
|
#include <os/config.h>
|
2013-12-28 20:35:56 +01:00
|
|
|
#include <util/color.h>
|
2013-12-28 22:29:30 +01:00
|
|
|
#include <os/pixel_rgb565.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2012-10-09 17:28:44 +02:00
|
|
|
/* terminal includes */
|
2011-12-22 16:19:25 +01:00
|
|
|
#include <terminal/decoder.h>
|
|
|
|
#include <terminal/types.h>
|
2012-10-09 17:28:44 +02:00
|
|
|
#include <terminal/scancode_tracker.h>
|
|
|
|
#include <terminal/keymaps.h>
|
2013-02-20 22:51:34 +01:00
|
|
|
#include <terminal/char_cell_array_character_screen.h>
|
2012-10-09 17:28:44 +02:00
|
|
|
#include <terminal_session/terminal_session.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2012-10-09 17:28:44 +02:00
|
|
|
/* nitpicker graphic back end */
|
2013-12-28 22:29:30 +01:00
|
|
|
#include <nitpicker_gfx/text_painter.h>
|
|
|
|
|
|
|
|
|
|
|
|
using Genode::Pixel_rgb565;
|
|
|
|
typedef Text_painter::Font Font;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
* 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;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2012-10-09 17:28:44 +02:00
|
|
|
|
2013-12-28 20:35:56 +01:00
|
|
|
using Genode::Color;
|
|
|
|
|
|
|
|
|
2012-10-09 15:02:20 +02:00
|
|
|
static Color color_palette[2*8];
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
2013-02-20 22:51:34 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-09 15:02:20 +02:00
|
|
|
class Font_family
|
|
|
|
{
|
|
|
|
private:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2012-10-09 15:02:20 +02:00
|
|
|
Font const &_regular;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2012-10-09 15:02:20 +02:00
|
|
|
public:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2012-10-09 15:02:20 +02:00
|
|
|
Font_family(Font const ®ular /* ...to be extended */ )
|
|
|
|
: _regular(regular) { }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return font for specified face
|
|
|
|
*
|
|
|
|
* For now, we do not support font faces other than regular.
|
|
|
|
*/
|
2013-02-20 22:51:34 +01:00
|
|
|
Font const *font(Font_face) const { return &_regular; }
|
2012-10-09 15:02:20 +02:00
|
|
|
|
|
|
|
unsigned cell_width() const { return _regular.str_w("m"); }
|
|
|
|
unsigned cell_height() const { return _regular.str_h("m"); }
|
|
|
|
};
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
template <typename PT>
|
|
|
|
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
|
|
|
|
- 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] = mix(bg_pixel, fg_pixel, glyph_base[x]);
|
|
|
|
|
|
|
|
fb_base += fb_width;
|
|
|
|
glyph_base += glyph_img_width;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename PT>
|
2012-10-09 17:28:44 +02:00
|
|
|
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)
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2013-02-20 22:51:34 +01:00
|
|
|
Font const ®ular_font = *font_family.font(Font_face::REGULAR);
|
2012-10-09 15:02:20 +02:00
|
|
|
unsigned glyph_height = regular_font.img_h,
|
|
|
|
glyph_step_x = regular_font.wtab['m'];
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
unsigned y = 0;
|
|
|
|
for (unsigned line = 0; line < cell_array->num_lines(); line++) {
|
|
|
|
|
|
|
|
if (cell_array->line_dirty(line)) {
|
|
|
|
|
|
|
|
if (verbose)
|
|
|
|
Genode::printf("convert line %d\n", line);
|
|
|
|
|
|
|
|
unsigned x = 0;
|
|
|
|
for (unsigned column = 0; column < cell_array->num_cols(); column++) {
|
|
|
|
|
|
|
|
Char_cell cell = cell_array->get_cell(column, line);
|
2012-10-09 15:02:20 +02:00
|
|
|
Font const *font = font_family.font(cell.font_face());
|
2011-12-22 16:19:25 +01:00
|
|
|
unsigned char ascii = cell.ascii;
|
|
|
|
|
|
|
|
if (ascii == 0)
|
|
|
|
ascii = ' ';
|
|
|
|
|
2012-10-09 15:02:20 +02:00
|
|
|
unsigned char const *glyph_base = font->img + font->otab[ascii];
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2012-10-09 15:02:20 +02:00
|
|
|
unsigned glyph_width = regular_font.wtab[ascii];
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-07-22 16:09:24 +02:00
|
|
|
if (x + glyph_width > fb_width) break;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-02-20 22:51:34 +01:00
|
|
|
Color fg_color = foreground_color(cell);
|
|
|
|
Color bg_color = background_color(cell);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
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 {
|
|
|
|
|
2011-12-23 19:50:28 +01:00
|
|
|
struct Flush_callback : Genode::List<Flush_callback>::Element
|
|
|
|
{
|
|
|
|
virtual void flush() = 0;
|
|
|
|
};
|
|
|
|
|
2012-01-28 00:02:01 +01:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-12-23 19:50:28 +01:00
|
|
|
class Session_component : public Genode::Rpc_object<Session, Session_component>,
|
|
|
|
public Flush_callback
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2012-01-28 00:02:01 +01:00
|
|
|
Read_buffer *_read_buffer;
|
|
|
|
Framebuffer::Session *_framebuffer;
|
|
|
|
|
|
|
|
Flush_callback_registry &_flush_callback_registry;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
Genode::Attached_ram_dataspace _io_buffer;
|
|
|
|
|
2012-01-28 00:02:01 +01:00
|
|
|
Framebuffer::Mode _fb_mode;
|
|
|
|
Genode::Dataspace_capability _fb_ds_cap;
|
|
|
|
unsigned _char_width;
|
|
|
|
unsigned _char_height;
|
|
|
|
unsigned _columns;
|
|
|
|
unsigned _lines;
|
|
|
|
void *_fb_addr;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2011-12-23 19:50:28 +01:00
|
|
|
/**
|
|
|
|
* Protect '_char_cell_array'
|
|
|
|
*/
|
|
|
|
Genode::Lock _lock;
|
|
|
|
|
2012-10-09 17:28:44 +02:00
|
|
|
Cell_array<Char_cell> _char_cell_array;
|
2011-12-22 16:19:25 +01:00
|
|
|
Char_cell_array_character_screen _char_cell_array_character_screen;
|
|
|
|
Terminal::Decoder _decoder;
|
|
|
|
|
2012-10-09 15:02:20 +02:00
|
|
|
Terminal::Position _last_cursor_pos;
|
|
|
|
|
|
|
|
Font_family const *_font_family;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize framebuffer-related attributes
|
|
|
|
*/
|
|
|
|
Genode::Dataspace_capability _init_fb()
|
|
|
|
{
|
2012-01-18 14:57:08 +01:00
|
|
|
if (_fb_mode.format() != Framebuffer::Mode::RGB565) {
|
|
|
|
PERR("Color mode %d not supported", _fb_mode.format());
|
2011-12-22 16:19:25 +01:00
|
|
|
return Genode::Dataspace_capability();
|
|
|
|
}
|
|
|
|
|
|
|
|
return _framebuffer->dataspace();
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
2012-01-28 00:02:01 +01:00
|
|
|
Session_component(Read_buffer *read_buffer,
|
|
|
|
Framebuffer::Session *framebuffer,
|
|
|
|
Genode::size_t io_buffer_size,
|
2012-10-09 15:02:20 +02:00
|
|
|
Flush_callback_registry &flush_callback_registry,
|
|
|
|
Font_family const &font_family)
|
2012-01-28 00:02:01 +01:00
|
|
|
:
|
|
|
|
_read_buffer(read_buffer), _framebuffer(framebuffer),
|
|
|
|
_flush_callback_registry(flush_callback_registry),
|
|
|
|
_io_buffer(Genode::env()->ram_session(), io_buffer_size),
|
|
|
|
_fb_mode(_framebuffer->mode()),
|
|
|
|
_fb_ds_cap(_init_fb()),
|
|
|
|
|
|
|
|
/* take size of space character as character cell size */
|
2012-10-09 15:02:20 +02:00
|
|
|
_char_width(font_family.cell_width()),
|
|
|
|
_char_height(font_family.cell_height()),
|
2012-01-28 00:02:01 +01:00
|
|
|
|
|
|
|
/* compute number of characters fitting on the framebuffer */
|
|
|
|
_columns(_fb_mode.width()/_char_width),
|
|
|
|
_lines(_fb_mode.height()/_char_height),
|
|
|
|
|
|
|
|
_fb_addr(Genode::env()->rm_session()->attach(_fb_ds_cap)),
|
|
|
|
_char_cell_array(_columns, _lines, Genode::env()->heap()),
|
|
|
|
_char_cell_array_character_screen(_char_cell_array),
|
2012-10-09 15:02:20 +02:00
|
|
|
_decoder(_char_cell_array_character_screen),
|
|
|
|
|
|
|
|
_font_family(&font_family)
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
printf("new terminal session:\n");
|
2012-01-18 14:57:08 +01:00
|
|
|
printf(" framebuffer has %dx%d pixels\n", _fb_mode.width(), _fb_mode.height());
|
2011-12-22 16:19:25 +01:00
|
|
|
printf(" character size is %dx%d pixels\n", _char_width, _char_height);
|
|
|
|
printf(" terminal size is %dx%d characters\n", _columns, _lines);
|
|
|
|
|
2012-01-18 14:57:08 +01:00
|
|
|
framebuffer->refresh(0, 0, _fb_mode.width(), _fb_mode.height());
|
2012-01-28 00:02:01 +01:00
|
|
|
|
|
|
|
_flush_callback_registry.add(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
~Session_component()
|
|
|
|
{
|
|
|
|
_flush_callback_registry.remove(this);
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void flush()
|
|
|
|
{
|
2011-12-23 19:50:28 +01:00
|
|
|
Genode::Lock::Guard guard(_lock);
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
convert_char_array_to_pixels<Pixel_rgb565>(&_char_cell_array,
|
2011-12-23 19:50:28 +01:00
|
|
|
(Pixel_rgb565 *)_fb_addr,
|
2012-01-18 14:57:08 +01:00
|
|
|
_fb_mode.width(),
|
2012-10-09 15:02:20 +02:00
|
|
|
_fb_mode.height(),
|
|
|
|
*_font_family);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
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;
|
2013-08-22 09:49:58 +02:00
|
|
|
if (num_dirty_lines > 0)
|
|
|
|
_framebuffer->refresh(0, first_dirty_line*_char_height,
|
|
|
|
_fb_mode.width(),
|
|
|
|
num_dirty_lines*_char_height);
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/********************************
|
|
|
|
** 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);
|
|
|
|
do {
|
2015-02-12 11:26:18 +01:00
|
|
|
dst[num_bytes++] = _read_buffer->get();
|
2011-12-22 16:19:25 +01:00
|
|
|
} while (!_read_buffer->empty() && num_bytes < dst_size);
|
|
|
|
|
|
|
|
return num_bytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _write(Genode::size_t num_bytes)
|
|
|
|
{
|
2011-12-23 19:50:28 +01:00
|
|
|
Genode::Lock::Guard guard(_lock);
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
unsigned char *src = _io_buffer.local_addr<unsigned char>();
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < num_bytes; i++) {
|
|
|
|
if (verbose)
|
|
|
|
Genode::printf("%c (%d)\n", src[i], (int)src[i]);
|
|
|
|
|
|
|
|
/* submit character to sequence decoder */
|
|
|
|
_decoder.insert(src[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
2011-12-23 19:50:28 +01:00
|
|
|
Read_buffer *_read_buffer;
|
|
|
|
Framebuffer::Session *_framebuffer;
|
|
|
|
Flush_callback_registry &_flush_callback_registry;
|
2012-10-09 15:02:20 +02:00
|
|
|
Font_family const &_font_family;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
Session_component *_create_session(const char *args)
|
|
|
|
{
|
|
|
|
Genode::printf("create terminal session\n");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX read I/O buffer size from args
|
|
|
|
*/
|
|
|
|
Genode::size_t io_buffer_size = 4096;
|
|
|
|
|
2011-12-23 19:50:28 +01:00
|
|
|
Session_component *session =
|
|
|
|
new (md_alloc()) Session_component(_read_buffer,
|
|
|
|
_framebuffer,
|
2012-01-28 00:02:01 +01:00
|
|
|
io_buffer_size,
|
2012-10-09 15:02:20 +02:00
|
|
|
_flush_callback_registry,
|
|
|
|
_font_family);
|
2011-12-23 19:50:28 +01:00
|
|
|
return session;
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
2011-12-23 19:50:28 +01:00
|
|
|
Root_component(Genode::Rpc_entrypoint *ep,
|
|
|
|
Genode::Allocator *md_alloc,
|
|
|
|
Read_buffer *read_buffer,
|
|
|
|
Framebuffer::Session *framebuffer,
|
2012-10-09 15:02:20 +02:00
|
|
|
Flush_callback_registry &flush_callback_registry,
|
|
|
|
Font_family const &font_family)
|
2011-12-22 16:19:25 +01:00
|
|
|
:
|
|
|
|
Genode::Root_component<Session_component>(ep, md_alloc),
|
2011-12-23 19:50:28 +01:00
|
|
|
_read_buffer(read_buffer), _framebuffer(framebuffer),
|
2012-10-09 15:02:20 +02:00
|
|
|
_flush_callback_registry(flush_callback_registry),
|
|
|
|
_font_family(font_family)
|
2011-12-22 16:19:25 +01:00
|
|
|
{ }
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main(int, char **)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
PDBG("--- terminal service started ---");
|
|
|
|
|
|
|
|
static Framebuffer::Connection framebuffer;
|
|
|
|
static Input::Connection input;
|
|
|
|
static Timer::Connection timer;
|
|
|
|
static Cap_connection cap;
|
|
|
|
|
|
|
|
Dataspace_capability ev_ds_cap = input.dataspace();
|
|
|
|
|
|
|
|
Input::Event *ev_buf = static_cast<Input::Event *>
|
|
|
|
(env()->rm_session()->attach(ev_ds_cap));
|
|
|
|
|
|
|
|
/* initialize entry point that serves the root interface */
|
2012-05-08 18:59:52 +02:00
|
|
|
enum { STACK_SIZE = sizeof(addr_t)*1024 };
|
2011-12-22 16:19:25 +01:00
|
|
|
static Rpc_entrypoint ep(&cap, STACK_SIZE, "terminal_ep");
|
|
|
|
|
|
|
|
static Sliced_heap sliced_heap(env()->ram_session(), env()->rm_session());
|
|
|
|
|
|
|
|
/* input read buffer */
|
2012-10-09 17:28:44 +02:00
|
|
|
static Terminal::Read_buffer read_buffer;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/* initialize color palette */
|
2012-10-09 15:02:20 +02:00
|
|
|
color_palette[0] = Color( 0, 0, 0); /* black */
|
2013-02-20 22:51:34 +01:00
|
|
|
color_palette[1] = Color(255, 128, 128); /* red */
|
|
|
|
color_palette[2] = Color(128, 255, 128); /* green */
|
2012-10-09 15:02:20 +02:00
|
|
|
color_palette[3] = Color(255, 255, 0); /* yellow */
|
2013-02-20 22:51:34 +01:00
|
|
|
color_palette[4] = Color(128, 128, 255); /* blue */
|
2012-10-09 15:02:20 +02:00
|
|
|
color_palette[5] = Color(255, 0, 255); /* magenta */
|
|
|
|
color_palette[6] = Color( 0, 255, 255); /* cyan */
|
|
|
|
color_palette[7] = Color(255, 255, 255); /* white */
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2012-10-09 15:02:20 +02:00
|
|
|
/* built-in fonts */
|
|
|
|
extern char _binary_notix_8_tff_start;
|
|
|
|
extern char _binary_terminus_12_tff_start;
|
|
|
|
extern char _binary_terminus_16_tff_start;
|
|
|
|
|
|
|
|
/* pick font according to config file */
|
|
|
|
char const *font_data = &_binary_terminus_16_tff_start;
|
|
|
|
try {
|
|
|
|
size_t font_size = 16;
|
|
|
|
config()->xml_node().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);
|
|
|
|
|
|
|
|
printf("cell size is %dx%d\n", (int)font_family.cell_width(),
|
|
|
|
(int)font_family.cell_height());
|
|
|
|
|
2011-12-23 19:50:28 +01:00
|
|
|
static Terminal::Flush_callback_registry flush_callback_registry;
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
/* create root interface for service */
|
|
|
|
static Terminal::Root_component root(&ep, &sliced_heap,
|
2011-12-23 19:50:28 +01:00
|
|
|
&read_buffer, &framebuffer,
|
2012-10-09 15:02:20 +02:00
|
|
|
flush_callback_registry,
|
|
|
|
font_family);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/* announce service at our parent */
|
|
|
|
env()->parent()->announce(ep.manage(&root));
|
|
|
|
|
|
|
|
/* state needed for key-repeat handling */
|
|
|
|
static int const repeat_delay = 170;
|
|
|
|
static int const repeat_rate = 25;
|
|
|
|
static int repeat_cnt = 0;
|
|
|
|
|
2012-10-09 17:28:44 +02:00
|
|
|
unsigned char *keymap = Terminal::usenglish_keymap;
|
|
|
|
unsigned char *shift = Terminal::usenglish_shift;
|
2011-12-22 16:19:25 +01:00
|
|
|
unsigned char *altgr = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read keyboard layout from config file
|
|
|
|
*/
|
|
|
|
try {
|
|
|
|
if (config()->xml_node().sub_node("keyboard")
|
|
|
|
.attribute("layout").has_value("de")) {
|
|
|
|
|
2012-10-09 17:28:44 +02:00
|
|
|
keymap = Terminal::german_keymap;
|
|
|
|
shift = Terminal::german_shift;
|
|
|
|
altgr = Terminal::german_altgr;
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
} catch (...) { }
|
|
|
|
|
2012-10-09 17:28:44 +02:00
|
|
|
static Terminal::Scancode_tracker
|
|
|
|
scancode_tracker(keymap, shift, altgr, Terminal::control);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
2011-12-23 19:50:28 +01:00
|
|
|
flush_callback_registry.flush();
|
|
|
|
|
2016-05-11 18:21:47 +02:00
|
|
|
while (!input.pending()) {
|
2011-12-22 16:19:25 +01:00
|
|
|
enum { PASSED_MSECS = 10 };
|
|
|
|
timer.msleep(PASSED_MSECS);
|
2011-12-23 19:50:28 +01:00
|
|
|
|
|
|
|
flush_callback_registry.flush();
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
if (scancode_tracker.valid()) {
|
|
|
|
repeat_cnt -= PASSED_MSECS;
|
|
|
|
|
|
|
|
if (repeat_cnt < 0) {
|
|
|
|
|
|
|
|
/* repeat current character or sequence */
|
|
|
|
scancode_tracker.emit_current_character(read_buffer);
|
|
|
|
|
|
|
|
/* reset repeat counter according to repeat rate */
|
|
|
|
repeat_cnt = repeat_rate;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned num_events = input.flush();
|
|
|
|
|
|
|
|
for (Input::Event *event = ev_buf; num_events--; event++) {
|
|
|
|
|
|
|
|
bool press = (event->type() == Input::Event::PRESS ? true : false);
|
|
|
|
bool release = (event->type() == Input::Event::RELEASE ? true : false);
|
2013-01-12 23:34:49 +01:00
|
|
|
int keycode = event->code();
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
if (press || release)
|
|
|
|
scancode_tracker.submit(keycode, press);
|
|
|
|
|
|
|
|
if (press)
|
|
|
|
scancode_tracker.emit_current_character(read_buffer);
|
|
|
|
|
|
|
|
/* setup first key repeat */
|
|
|
|
repeat_cnt = repeat_delay;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|