terminal_mux: adapt to component API

This commit is contained in:
Christian Helmuth 2016-11-17 16:53:32 +01:00
parent 383a3c6f54
commit 79dd99e521

View File

@ -13,11 +13,10 @@
/* Genode includes */ /* Genode includes */
#include <base/env.h> #include <base/env.h>
#include <base/printf.h> #include <base/component.h>
#include <base/heap.h> #include <base/heap.h>
#include <base/sleep.h> #include <base/session_label.h>
#include <util/arg_string.h> #include <util/arg_string.h>
#include <cap_session/connection.h>
#include <root/component.h> #include <root/component.h>
#include <os/attached_ram_dataspace.h> #include <os/attached_ram_dataspace.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
@ -82,7 +81,7 @@ struct Registry
/** /**
* Return session label * Return session label
*/ */
virtual char const *label() const = 0; virtual Genode::Session_label const & label() const = 0;
/** /**
* Submit character into entry * Submit character into entry
@ -178,30 +177,23 @@ class Session_manager
namespace Terminal { namespace Terminal {
class Session_component;
class Root_component;
}
class Session_component : public Genode::Rpc_object<Session, Session_component>, class Terminal::Session_component : public Genode::Rpc_object<Session, Session_component>,
public Registry::Entry public Registry::Entry
{ {
public:
enum { LABEL_MAX_LEN = 128 };
private: private:
Genode::Env &_env;
Read_buffer _read_buffer; Read_buffer _read_buffer;
Ncurses &_ncurses; Ncurses &_ncurses;
Ncurses::Window &_window; Ncurses::Window &_window;
struct Label Genode::Session_label const _label;
{
char buf[LABEL_MAX_LEN];
Label(char const *label)
{
Genode::strncpy(buf, label, sizeof(buf));
}
} _label;
Session_manager &_session_manager; Session_manager &_session_manager;
@ -213,24 +205,22 @@ namespace Terminal {
Terminal::Position _last_cursor_pos; Terminal::Position _last_cursor_pos;
public: public:
/**
* Constructor
*/
Session_component(Genode::size_t io_buffer_size, Session_component(Genode::size_t io_buffer_size,
Ncurses &ncurses, Ncurses &ncurses,
Session_manager &session_manager, Session_manager &session_manager,
char const *label) Genode::Session_label const &label,
Genode::Env &env,
Genode::Allocator &heap)
: :
_env(env),
_ncurses(ncurses), _ncurses(ncurses),
_window(*ncurses.create_window(0, 1, ncurses.columns(), ncurses.lines() - 1)), _window(*ncurses.create_window(0, 1, ncurses.columns(), ncurses.lines() - 1)),
_label(label), _label(label),
_session_manager(session_manager), _session_manager(session_manager),
_io_buffer(Genode::env()->ram_session(), io_buffer_size), _io_buffer(_env.ram(), _env.rm(), io_buffer_size),
_char_cell_array(ncurses.columns(), ncurses.lines() - 1, _char_cell_array(ncurses.columns(), ncurses.lines() - 1, &heap),
Genode::env()->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)
{ {
@ -248,7 +238,7 @@ namespace Terminal {
** Registry::Entry interface ** ** Registry::Entry interface **
*******************************/ *******************************/
void flush() void flush() override
{ {
convert_char_array_to_window(&_char_cell_array, _window); convert_char_array_to_window(&_char_cell_array, _window);
@ -271,7 +261,7 @@ namespace Terminal {
_window.refresh(); _window.refresh();
} }
void flush_all() void flush_all() override
{ {
for (unsigned line = 0; line < _char_cell_array.num_lines(); line++) for (unsigned line = 0; line < _char_cell_array.num_lines(); line++)
_char_cell_array.mark_line_as_dirty(line); _char_cell_array.mark_line_as_dirty(line);
@ -280,25 +270,19 @@ namespace Terminal {
flush(); flush();
} }
char const *label() const Genode::Session_label const & label() const override { return _label; }
{
return _label.buf;
}
void submit_input(char c) void submit_input(char c) override { _read_buffer.add(c); }
{
_read_buffer.add(c);
}
/******************************** /********************************
** Terminal session interface ** ** Terminal session interface **
********************************/ ********************************/
Size size() { return Size(_char_cell_array.num_cols(), Size size() override { return Size(_char_cell_array.num_cols(),
_char_cell_array.num_lines()); } _char_cell_array.num_lines()); }
bool avail() { return !_read_buffer.empty(); } bool avail() override { return !_read_buffer.empty(); }
Genode::size_t _read(Genode::size_t dst_len) Genode::size_t _read(Genode::size_t dst_len)
{ {
@ -329,7 +313,7 @@ namespace Terminal {
return _io_buffer.cap(); return _io_buffer.cap();
} }
void connected_sigh(Genode::Signal_context_capability sigh) void connected_sigh(Genode::Signal_context_capability sigh) override
{ {
/* /*
* Immediately reflect connection-established signal to the * Immediately reflect connection-established signal to the
@ -339,23 +323,32 @@ namespace Terminal {
Genode::Signal_transmitter(sigh).submit(); Genode::Signal_transmitter(sigh).submit();
} }
void read_avail_sigh(Genode::Signal_context_capability cap) void read_avail_sigh(Genode::Signal_context_capability cap) override
{ {
_read_buffer.sigh(cap); _read_buffer.sigh(cap);
} }
Genode::size_t read(void *buf, Genode::size_t) { return 0; } Genode::size_t read(void *buf, Genode::size_t) override { return 0; }
Genode::size_t write(void const *buf, Genode::size_t) { return 0; } Genode::size_t write(void const *buf, Genode::size_t) override { return 0; }
}; };
class Root_component : public Genode::Root_component<Session_component> class Terminal::Root_component : public Genode::Root_component<Session_component>
{ {
private: private:
Genode::Env &_env;
Ncurses &_ncurses; Ncurses &_ncurses;
Session_manager &_session_manager; Session_manager &_session_manager;
/*
* FIXME The heap is shared between all clients. The allocator should
* be moved into the session component but this increases per-session
* RAM costs significantly, which would break all connections to this
* server.
*/
Genode::Heap _heap { _env.ram(), _env.rm() };
protected: protected:
Session_component *_create_session(const char *args) Session_component *_create_session(const char *args)
@ -365,11 +358,9 @@ namespace Terminal {
*/ */
Genode::size_t io_buffer_size = 4096; Genode::size_t io_buffer_size = 4096;
char label[Session_component::LABEL_MAX_LEN];
Genode::Arg_string::find_arg(args, "label").string(label, sizeof(label), "<unlabeled>");
return new (md_alloc()) return new (md_alloc())
Session_component(io_buffer_size, _ncurses, _session_manager, label); Session_component(io_buffer_size, _ncurses, _session_manager,
Genode::label_from_args(args), _env, _heap);
} }
public: public:
@ -377,17 +368,17 @@ namespace Terminal {
/** /**
* Constructor * Constructor
*/ */
Root_component(Genode::Rpc_entrypoint &ep, Root_component(Genode::Env &env,
Genode::Allocator &md_alloc, Genode::Allocator &md_alloc,
Ncurses &ncurses, Ncurses &ncurses,
Session_manager &session_manager) Session_manager &session_manager)
: :
Genode::Root_component<Session_component>(&ep, &md_alloc), Genode::Root_component<Session_component>(env.ep(), md_alloc),
_env(env),
_ncurses(ncurses), _ncurses(ncurses),
_session_manager(session_manager) _session_manager(session_manager)
{ } { }
}; };
}
class Status_window class Status_window
@ -397,32 +388,27 @@ class Status_window
Ncurses &_ncurses; Ncurses &_ncurses;
Ncurses::Window &_window; Ncurses::Window &_window;
char _label[Terminal::Session_component::LABEL_MAX_LEN];
public: public:
Status_window(Ncurses &ncurses) Status_window(Ncurses &ncurses)
: :
_ncurses(ncurses), _ncurses(ncurses),
_window(*_ncurses.create_window(0, 0, ncurses.columns(), 1)) _window(*_ncurses.create_window(0, 0, ncurses.columns(), 1))
{ { }
_label[0] = 0;
}
~Status_window() ~Status_window()
{ {
_ncurses.destroy_window(&_window); _ncurses.destroy_window(&_window);
} }
void label(char const *label) void label(Genode::Session_label const &label)
{ {
Genode::strncpy(_label, label, sizeof(_label));
_window.erase(); _window.erase();
_window.move_cursor(0, 0); _window.move_cursor(0, 0);
_window.print_char('[', false, false); _window.print_char('[', false, false);
unsigned const max_columns = _ncurses.columns() - 2; unsigned const max_columns = _ncurses.columns() - 2;
char const *_label = label.string();
for (unsigned i = 0; i < max_columns && _label[i]; i++) for (unsigned i = 0; i < max_columns && _label[i]; i++)
_window.print_char(_label[i], false, false); _window.print_char(_label[i], false, false);
@ -443,6 +429,8 @@ class Menu : public Registry::Entry
unsigned _selected_idx; unsigned _selected_idx;
unsigned _max_idx; unsigned _max_idx;
Genode::Session_label const _label { "-" };
/** /**
* State tracker for escape sequences within user input * State tracker for escape sequences within user input
* *
@ -523,9 +511,9 @@ class Menu : public Registry::Entry
void reset_selection() { _selected_idx = 0; } void reset_selection() { _selected_idx = 0; }
void flush() { } void flush() override { }
void flush_all() void flush_all() override
{ {
_window.erase(); _window.erase();
@ -546,7 +534,7 @@ class Menu : public Registry::Entry
unsigned const padding = 2; unsigned const padding = 2;
_window.move_cursor(padding, 1 + i); _window.move_cursor(padding, 1 + i);
char const *label = entry->label(); char const *label = entry->label().string();
for (unsigned j = 0; j < (max_columns - padding) && label[j]; j++) for (unsigned j = 0; j < (max_columns - padding) && label[j]; j++)
_window.print_char(label[j], highlight, highlight); _window.print_char(label[j], highlight, highlight);
} }
@ -555,7 +543,7 @@ class Menu : public Registry::Entry
_window.refresh(); _window.refresh();
} }
char const *label() const { return "-"; } Genode::Session_label const & label() const { return _label; }
void submit_input(char c) void submit_input(char c)
{ {
@ -666,37 +654,47 @@ void Session_manager::remove(Registry::Entry *entry)
} }
/******************* /***************
** Input handler ** ** Component **
*******************/ ***************/
struct Input_handler struct Main
{ {
GENODE_RPC(Rpc_handle_input, void, handle); Genode::Env &env;
GENODE_RPC_INTERFACE(Rpc_handle_input);
};
Genode::Sliced_heap sliced_heap { env.ram(), env.rm() };
struct Input_handler_component : Genode::Rpc_object<Input_handler, Registry registry;
Input_handler_component> Ncurses ncurses;
Status_window status_window { ncurses };
Menu menu { ncurses, registry, status_window };
User_input user_input { ncurses };
Session_manager session_manager { ncurses, registry, status_window, menu };
Terminal::Root_component root { env, sliced_heap, ncurses, session_manager };
Timer::Connection timer { env };
Genode::Signal_handler<Main> timer_handler { env.ep(), *this, &Main::handle_timer };
Main(Genode::Env &env) : env(env)
{ {
User_input &_user_input; Genode::log("--- terminal_mux service started ---");
Session_manager &_session_manager;
registry.add(&menu);
session_manager.activate_menu();
Input_handler_component(User_input &user_input, env.parent().announce(env.ep().manage(root));
Session_manager &session_manager)
: timer.sigh(timer_handler);
_user_input(user_input), timer.trigger_periodic(10*1000);
_session_manager(session_manager)
{
_session_manager.activate_menu();
} }
void handle() void handle_timer()
{ {
for (;;) { for (;;) {
int c = _user_input.read_character(); int c = user_input.read_character();
if (c == -1) if (c == -1)
break; break;
@ -712,55 +710,16 @@ struct Input_handler_component : Genode::Rpc_object<Input_handler,
*/ */
enum { KEYCODE_C_X = 24 }; enum { KEYCODE_C_X = 24 };
if (c == KEYCODE_C_X) { if (c == KEYCODE_C_X) {
_session_manager.activate_menu(); session_manager.activate_menu();
} else { } else {
_session_manager.submit_input(c); session_manager.submit_input(c);
} }
} }
_session_manager.update_ncurses_screen(); session_manager.update_ncurses_screen();
} }
}; };
int main(int, char **) Genode::size_t Component::stack_size() { return 4096*sizeof(long); }
{ void Component::construct(Genode::Env &env) { static Main inst(env); }
using namespace Genode;
printf("--- terminal_mux service started ---\n");
static Cap_connection cap;
/* initialize entry point that serves the root interface */
enum { STACK_SIZE = sizeof(addr_t)*4096 };
static Rpc_entrypoint ep(&cap, STACK_SIZE, "terminal_mux_ep");
static Sliced_heap sliced_heap(env()->ram_session(), env()->rm_session());
static ::Registry registry;
static Ncurses ncurses;
static Status_window status_window(ncurses);
static Menu menu(ncurses, registry, status_window);
registry.add(&menu);
static User_input user_input(ncurses);
static Session_manager session_manager(ncurses, registry, status_window, menu);
/* create root interface for service */
static Terminal::Root_component root(ep, sliced_heap, ncurses, session_manager);
static Input_handler_component input_handler(user_input, session_manager);
Capability<Input_handler> input_handler_cap = ep.manage(&input_handler);
/* announce service at our parent */
env()->parent()->announce(ep.manage(&root));
while (1) {
static Timer::Connection timer;
timer.msleep(10);
input_handler_cap.call<Input_handler::Rpc_handle_input>();
}
return 0;
}