diff --git a/repos/gems/src/server/terminal/main.cc b/repos/gems/src/server/terminal/main.cc
index a43761c531..d7ba71be22 100644
--- a/repos/gems/src/server/terminal/main.cc
+++ b/repos/gems/src/server/terminal/main.cc
@@ -12,19 +12,19 @@
*/
/* Genode includes */
-#include
+#include
#include
#include
#include
#include
#include
-#include
#include
-#include
+#include
+#include
#include
-#include
#include
#include
+#include
/* terminal includes */
#include
@@ -37,6 +37,11 @@
/* nitpicker graphic back end */
#include
+namespace Terminal {
+ using namespace Genode;
+ struct Main;
+}
+
using Genode::Pixel_rgb565;
typedef Text_painter::Font Font;
@@ -264,15 +269,22 @@ namespace Terminal {
};
+ struct Trigger_flush_callback
+ {
+ virtual void trigger_flush() = 0;
+ };
+
+
class Session_component : public Genode::Rpc_object,
public Flush_callback
{
private:
- Read_buffer *_read_buffer;
- Framebuffer::Session *_framebuffer;
+ 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;
@@ -295,7 +307,7 @@ namespace Terminal {
Terminal::Position _last_cursor_pos;
- Font_family const *_font_family;
+ Font_family const &_font_family;
/**
* Initialize framebuffer-related attributes
@@ -307,7 +319,7 @@ namespace Terminal {
return Genode::Dataspace_capability();
}
- return _framebuffer->dataspace();
+ return _framebuffer.dataspace();
}
public:
@@ -315,16 +327,20 @@ namespace Terminal {
/**
* Constructor
*/
- Session_component(Read_buffer *read_buffer,
- Framebuffer::Session *framebuffer,
+ 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),
- _io_buffer(Genode::env()->ram_session(), io_buffer_size),
- _fb_mode(_framebuffer->mode()),
+ _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 */
@@ -335,12 +351,12 @@ namespace Terminal {
_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()),
+ _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)
+ _font_family(font_family)
{
using namespace Genode;
@@ -349,7 +365,7 @@ namespace Terminal {
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());
+ framebuffer.refresh(0, 0, _fb_mode.width(), _fb_mode.height());
_flush_callback_registry.add(this);
}
@@ -367,7 +383,7 @@ namespace Terminal {
(Pixel_rgb565 *)_fb_addr,
_fb_mode.width(),
_fb_mode.height(),
- *_font_family);
+ _font_family);
int first_dirty_line = 10000,
@@ -384,9 +400,9 @@ namespace Terminal {
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);
+ _framebuffer.refresh(0, first_dirty_line*_char_height,
+ _fb_mode.width(),
+ num_dirty_lines*_char_height);
}
@@ -396,7 +412,7 @@ namespace Terminal {
Size size() { return Size(_columns, _lines); }
- bool avail() { return !_read_buffer->empty(); }
+ bool avail() { return !_read_buffer.empty(); }
Genode::size_t _read(Genode::size_t dst_len)
{
@@ -404,9 +420,9 @@ namespace Terminal {
unsigned num_bytes = 0;
unsigned char *dst = _io_buffer.local_addr();
Genode::size_t dst_size = Genode::min(_io_buffer.size(), dst_len);
- do {
- dst[num_bytes++] = _read_buffer->get();
- } while (!_read_buffer->empty() && num_bytes < dst_size);
+
+ while (!_read_buffer.empty() && num_bytes < dst_size)
+ dst[num_bytes++] = _read_buffer.get();
return num_bytes;
}
@@ -422,6 +438,7 @@ namespace Terminal {
/* submit character to sequence decoder */
_decoder.insert(src[i]);
}
+ _trigger_flush_callback.trigger_flush();
}
Genode::Dataspace_capability _dataspace()
@@ -441,7 +458,7 @@ namespace Terminal {
void read_avail_sigh(Genode::Signal_context_capability cap)
{
- _read_buffer->sigh(cap);
+ _read_buffer.sigh(cap);
}
Genode::size_t read(void *buf, Genode::size_t) { return 0; }
@@ -453,9 +470,11 @@ namespace Terminal {
{
private:
- Read_buffer *_read_buffer;
- Framebuffer::Session *_framebuffer;
+ 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:
@@ -470,10 +489,12 @@ namespace Terminal {
Genode::size_t io_buffer_size = 4096;
Session_component *session =
- new (md_alloc()) Session_component(_read_buffer,
+ new (md_alloc()) Session_component(_env, *md_alloc(),
+ _read_buffer,
_framebuffer,
io_buffer_size,
_flush_callback_registry,
+ _trigger_flush_callback,
_font_family);
return session;
}
@@ -483,41 +504,175 @@ namespace Terminal {
/**
* Constructor
*/
- Root_component(Genode::Rpc_entrypoint *ep,
- Genode::Allocator *md_alloc,
- Read_buffer *read_buffer,
- Framebuffer::Session *framebuffer,
+ 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(ep, md_alloc),
+ Genode::Root_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)
{ }
};
}
-int main(int, char **)
+struct Terminal::Main
+{
+ Genode::Env &_env;
+
+ Framebuffer::Connection _framebuffer { _env, Framebuffer::Mode() };
+ Input::Connection _input { _env };
+ Timer::Connection _timer_conection { _env };
+ Genode::Timer _timer { _timer_conection, _env.ep() };
+
+ Sliced_heap _sliced_heap { _env.ram(), _env.rm() };
+
+ /* input read buffer */
+ Read_buffer _read_buffer;
+
+ Terminal::Flush_callback_registry _flush_callback_registry;
+
+ /* create root interface for service */
+ Terminal::Root_component _root;
+
+ Terminal::Scancode_tracker _scancode_tracker;
+
+ /* state needed for key-repeat handling */
+ unsigned const _repeat_delay = 250;
+ unsigned const _repeat_rate = 25;
+ unsigned _repeat_next = 0;
+
+ void _handle_input();
+
+ Signal_handler _input_handler {
+ _env.ep(), *this, &Main::_handle_input };
+
+ void _handle_key_repeat(Time_source::Microseconds);
+
+ One_shot_timeout _key_repeat_timeout {
+ _timer, *this, &Main::_handle_key_repeat };
+
+ void _handle_flush(Time_source::Microseconds);
+
+ /*
+ * 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) {
+ _flush_timeout.start(Time_source::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 };
+
+ One_shot_timeout _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, _sliced_heap,
+ _read_buffer, _framebuffer,
+ _flush_callback_registry,
+ _trigger_flush_callback,
+ font_family),
+ _scancode_tracker(keymap, shift, altgr, Terminal::control)
+ {
+ _input.sigh(_input_handler);
+
+ /* announce service at our parent */
+ _env.parent().announce(_env.ep().manage(_root));
+ }
+
+};
+
+
+void Terminal::Main::_handle_input()
+{
+ _input.for_each_event([&] (Input::Event const &event) {
+ bool press = (event.type() == Input::Event::PRESS ? true : false);
+ bool release = (event.type() == Input::Event::RELEASE ? true : false);
+ int keycode = event.code();
+
+ if (press || release)
+ _scancode_tracker.submit(keycode, press);
+
+ if (press) {
+ _scancode_tracker.emit_current_character(_read_buffer);
+
+ /* setup first key repeat */
+ _repeat_next = _repeat_delay;
+ }
+
+ if (release)
+ _repeat_next = 0;
+ });
+
+ if (_repeat_next)
+ _key_repeat_timeout.start(Time_source::Microseconds{1000*_repeat_next});
+}
+
+
+void Terminal::Main::_handle_key_repeat(Time_source::Microseconds)
+{
+ if (_repeat_next) {
+
+ /* repeat current character or sequence */
+ _scancode_tracker.emit_current_character(_read_buffer);
+
+ _repeat_next = _repeat_rate;
+ }
+
+ _handle_input();
+}
+
+
+void Terminal::Main::_handle_flush(Time_source::Microseconds)
+{
+ _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)
{
using namespace Genode;
- log("--- terminal service started ---");
-
- static Framebuffer::Connection framebuffer;
- static Input::Connection input;
- static Timer::Connection timer;
- static Cap_connection cap;
-
- /* initialize entry point that serves the root interface */
- enum { STACK_SIZE = 2*sizeof(addr_t)*1024 };
- static Rpc_entrypoint ep(&cap, STACK_SIZE, "terminal_ep");
-
- static Sliced_heap sliced_heap(env()->ram_session(), env()->rm_session());
-
- /* input read buffer */
- static Terminal::Read_buffer read_buffer;
+ Attached_rom_dataspace config(env, "config");
/* initialize color palette */
color_palette[0] = Color( 0, 0, 0); /* black */
@@ -536,17 +691,11 @@ int main(int, char **)
color_palette[i + 8] = col;
}
- /* 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);
+ config.xml().sub_node("font").attribute("size").value(&font_size);
switch (font_size) {
case 8: font_data = &_binary_notix_8_tff_start; break;
@@ -562,22 +711,6 @@ int main(int, char **)
log("cell size is ", (int)font_family.cell_width(),
"x", (int)font_family.cell_height());
- static Terminal::Flush_callback_registry flush_callback_registry;
-
- /* create root interface for service */
- static Terminal::Root_component root(&ep, &sliced_heap,
- &read_buffer, &framebuffer,
- flush_callback_registry,
- font_family);
-
- /* 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;
-
unsigned char *keymap = Terminal::usenglish_keymap;
unsigned char *shift = Terminal::usenglish_shift;
unsigned char *altgr = 0;
@@ -586,7 +719,7 @@ int main(int, char **)
* Read keyboard layout from config file
*/
try {
- if (config()->xml_node().sub_node("keyboard")
+ if (config.xml().sub_node("keyboard")
.attribute("layout").has_value("de")) {
keymap = Terminal::german_keymap;
@@ -595,47 +728,5 @@ int main(int, char **)
}
} catch (...) { }
- static Terminal::Scancode_tracker
- scancode_tracker(keymap, shift, altgr, Terminal::control);
-
- while (1) {
-
- flush_callback_registry.flush();
-
- while (!input.pending()) {
- enum { PASSED_MSECS = 10 };
- timer.msleep(PASSED_MSECS);
-
- flush_callback_registry.flush();
-
- 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;
- }
- }
- }
-
- input.for_each_event([&] (Input::Event const &event) {
- bool press = (event.type() == Input::Event::PRESS ? true : false);
- bool release = (event.type() == Input::Event::RELEASE ? true : false);
- int keycode = event.code();
-
- 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;
+ static Terminal::Main main(env, font_family, keymap, shift, altgr, Terminal::control);
}
diff --git a/repos/gems/src/server/terminal/target.mk b/repos/gems/src/server/terminal/target.mk
index 86d2c79bed..dba8b32b51 100644
--- a/repos/gems/src/server/terminal/target.mk
+++ b/repos/gems/src/server/terminal/target.mk
@@ -1,4 +1,4 @@
TARGET = terminal
SRC_CC = main.cc
-LIBS = base config
+LIBS = base timeout
SRC_BIN = $(notdir $(wildcard $(PRG_DIR)/*.tff))